aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-09-03 16:20:38 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-09-03 16:20:38 +0200
commit0e2ae18a97fd507bac872031888d34c3a7d8b17b (patch)
tree3f9a551486969d2bc05f272e2da372c1a55d34cf
parent137b1eb3e41578d9d4a066ef75c6abfa597c46cd (diff)
Implement Win32 TLS support
-rw-r--r--configure.ac4
-rw-r--r--m4/static-lib.m419
-rw-r--r--odb/Makefile.am6
-rw-r--r--odb/details/config-vc.h4
-rw-r--r--odb/details/config.h.in2
-rw-r--r--odb/details/export.hxx18
-rw-r--r--odb/details/lock.hxx17
-rw-r--r--odb/details/posix/tls.hxx3
-rw-r--r--odb/details/shared-ptr/base.hxx4
-rw-r--r--odb/details/tls.hxx28
-rw-r--r--odb/details/win32/dll.cxx52
-rw-r--r--odb/details/win32/init.cxx43
-rw-r--r--odb/details/win32/init.hxx38
-rw-r--r--odb/details/win32/lock.hxx51
-rw-r--r--odb/details/win32/once-init.hxx25
-rw-r--r--odb/details/win32/once.cxx29
-rw-r--r--odb/details/win32/once.hxx49
-rw-r--r--odb/details/win32/once.ixx30
-rw-r--r--odb/details/win32/tls-init.hxx28
-rw-r--r--odb/details/win32/tls.cxx236
-rw-r--r--odb/details/win32/tls.hxx111
-rw-r--r--odb/details/win32/tls.ixx22
-rw-r--r--odb/details/win32/tls.txx87
-rw-r--r--odb/libodb-vc10.vcxproj1
-rw-r--r--odb/libodb-vc9.vcproj1
-rw-r--r--odb/makefile13
26 files changed, 872 insertions, 49 deletions
diff --git a/configure.ac b/configure.ac
index 041c63e..fe1d59d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,10 @@ AS_IF([test x$threads = xnone], AC_DEFINE([ODB_THREADS_NONE], [1], [Have no thre
AS_IF([test x$threads = xwin32], AC_DEFINE([ODB_THREADS_WIN32], [1], [Have Win32 threads.]))
AS_IF([test x$threads = xposix], AC_DEFINE([ODB_THREADS_POSIX], [1], [Have POSIX threads.]))
+# Define LIBODB_STATIC_LIB if we are build static library on certain platforms.
+#
+STATIC_LIB([LIBODB_STATIC_LIB], [Static library interface.])
+
# Allow the user to specify the pkgconfig directory.
#
PKGCONFIG
diff --git a/m4/static-lib.m4 b/m4/static-lib.m4
new file mode 100644
index 0000000..1c0af42
--- /dev/null
+++ b/m4/static-lib.m4
@@ -0,0 +1,19 @@
+dnl file : m4/static-lib.m4
+dnl author : Boris Kolpackov <boris@codesynthesis.com>
+dnl copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+dnl license : GNU GPL v2; see accompanying LICENSE file
+dnl
+dnl STATIC_LIB(MACRO, DESCRIPTION)
+dnl
+dnl Define MACRO if we are on MinGW and are only building static library.
+dnl
+AC_DEFUN([STATIC_LIB],
+[
+if test x$enable_shared = xno; then
+ case $host_os in
+ mingw*)
+ AC_DEFINE([$1], [1], [$2])
+ ;;
+ esac
+fi
+])dnl
diff --git a/odb/Makefile.am b/odb/Makefile.am
index cfb0af8..afdf450 100644
--- a/odb/Makefile.am
+++ b/odb/Makefile.am
@@ -18,9 +18,9 @@ nobase_odbinclude_HEADERS += __path__(posix_headers)
endif
if ODB_THREADS_WIN32
-libodb_la_SOURCES += __path__(win32_sources)
+libodb_la_SOURCES += __path__(win32_sources) __path__(win32_dll_sources)
nobase_odbinclude_HEADERS += __path__(win32_headers)
endif
-AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
-libodb_la_LDFLAGS = -release __value__(interface_version)
+libodb_la_CPPFLAGS= -I$(top_builddir) -I$(top_srcdir) -DLIBODB_DYNAMIC_LIB
+libodb_la_LDFLAGS = -release __value__(interface_version) -no-undefined
diff --git a/odb/details/config-vc.h b/odb/details/config-vc.h
index f90ac4d..52b7430 100644
--- a/odb/details/config-vc.h
+++ b/odb/details/config-vc.h
@@ -10,8 +10,6 @@
#define ODB_DETAILS_CONFIG_VC_H
#define ODB_THREADS_WIN32
-#define ODB_THREADS_TLS_DECLSPEC_POINTER
-#define ODB_THREADS_TLS_DECLSPEC_OBJECT
-
+#define ODB_THREADS_TLS_DECLSPEC
#endif /* ODB_DETAILS_CONFIG_VC_H */
diff --git a/odb/details/config.h.in b/odb/details/config.h.in
index aa2417d..a55352a 100644
--- a/odb/details/config.h.in
+++ b/odb/details/config.h.in
@@ -13,4 +13,6 @@
#undef ODB_THREADS_POSIX
#undef ODB_THREADS_WIN32
+#undef LIBODB_STATIC_LIB
+
#endif /* ODB_DETAILS_CONFIG_H */
diff --git a/odb/details/export.hxx b/odb/details/export.hxx
index ef43c6c..19bd313 100644
--- a/odb/details/export.hxx
+++ b/odb/details/export.hxx
@@ -14,10 +14,22 @@
# define LIBODB_EXPORT
#else
# ifdef _WIN32
-# ifdef LIBODB_DYNAMIC_LIB
-# define LIBODB_EXPORT __declspec(dllexport)
+# ifdef _MSC_VER
+# ifdef LIBODB_DYNAMIC_LIB
+# define LIBODB_EXPORT __declspec(dllexport)
+# else
+# define LIBODB_EXPORT __declspec(dllimport)
+# endif
# else
-# define LIBODB_EXPORT __declspec(dllimport)
+# ifdef LIBODB_DYNAMIC_LIB
+# ifdef DLL_EXPORT
+# define LIBODB_EXPORT __declspec(dllexport)
+# else
+# define LIBODB_EXPORT
+# endif
+# else
+# define LIBODB_EXPORT __declspec(dllimport)
+# endif
# endif
# else
# define LIBODB_EXPORT
diff --git a/odb/details/lock.hxx b/odb/details/lock.hxx
index 7902d77..b479f28 100644
--- a/odb/details/lock.hxx
+++ b/odb/details/lock.hxx
@@ -18,30 +18,29 @@ namespace odb
struct LIBODB_EXPORT lock
{
lock (mutex& m)
- : mutex_ (m), locked_ (true)
+ : mutex_ (&m)
{
- mutex_.lock ();
+ mutex_->lock ();
}
~lock ()
{
- if (locked_)
- mutex_.unlock ();
+ if (mutex_ != 0)
+ mutex_->unlock ();
}
void
unlock ()
{
- if (locked_)
+ if (mutex_ != 0)
{
- mutex_.unlock ();
- locked_ = true;
+ mutex_->unlock ();
+ mutex_ = 0;
}
}
private:
- mutex& mutex_;
- bool locked_;
+ mutex* mutex_;
};
}
}
diff --git a/odb/details/posix/tls.hxx b/odb/details/posix/tls.hxx
index 92b0f4b..d23a09a 100644
--- a/odb/details/posix/tls.hxx
+++ b/odb/details/posix/tls.hxx
@@ -15,9 +15,6 @@ namespace odb
namespace details
{
template <typename T>
- class tls;
-
- template <typename T>
class tls
{
public:
diff --git a/odb/details/shared-ptr/base.hxx b/odb/details/shared-ptr/base.hxx
index 309f7d2..c8beb07 100644
--- a/odb/details/shared-ptr/base.hxx
+++ b/odb/details/shared-ptr/base.hxx
@@ -31,8 +31,8 @@ namespace odb
char id_;
};
- extern share shared;
- extern share exclusive;
+ extern LIBODB_EXPORT share shared;
+ extern LIBODB_EXPORT share exclusive;
}
}
diff --git a/odb/details/tls.hxx b/odb/details/tls.hxx
index 7ce5c19..d2627be 100644
--- a/odb/details/tls.hxx
+++ b/odb/details/tls.hxx
@@ -50,7 +50,9 @@ namespace odb
#elif defined(ODB_THREADS_WIN32)
-# ifdef ODB_THREADS_TLS_DECLSPEC_POINTER
+# include <odb/details/win32/tls.hxx>
+
+# ifdef ODB_THREADS_TLS_DECLSPEC
# define ODB_TLS_POINTER(type) __declspec(thread) type*
namespace odb
@@ -74,29 +76,9 @@ namespace odb
}
# else
-# error unsupported TLS pointer model
-# endif
-
-# ifdef ODB_THREADS_TLS_DECLSPEC_OBJECT
-# define ODB_TLS_OBJECT(type) __declspec(thread) type
-
-namespace odb
-{
- namespace details
- {
- template <typename T>
- inline T&
- tls_get (T& x)
- {
- return x;
- }
- }
-}
-
-# else
-# error unsupported TLS object model
+# define ODB_TLS_POINTER(type) tls<type*>
# endif
-
+# define ODB_TLS_OBJECT(type) tls<type>
#else
# error unknown threading model
#endif
diff --git a/odb/details/win32/dll.cxx b/odb/details/win32/dll.cxx
new file mode 100644
index 0000000..843be8d
--- /dev/null
+++ b/odb/details/win32/dll.cxx
@@ -0,0 +1,52 @@
+// file : odb/details/win32/dll.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// If we are building a static library from VC++ (LIBODB_STATIC_LIB) or
+// a static library from automake (!DLL_EXPORT), then omit DllMain.
+//
+#if defined(LIBODB_STATIC_LIB) || !defined (_MSC_VER) && !defined(DLL_EXPORT)
+
+#include <windows.h>
+
+#include <odb/details/win32/init.hxx>
+
+using namespace odb::details;
+
+extern "C" BOOL WINAPI
+DllMain (HINSTANCE, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ process_start ();
+ thread_start ();
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ thread_start ();
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ thread_end ();
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ thread_end ();
+ process_end (reserved == NULL);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+#endif
diff --git a/odb/details/win32/init.cxx b/odb/details/win32/init.cxx
new file mode 100644
index 0000000..c07b9d8
--- /dev/null
+++ b/odb/details/win32/init.cxx
@@ -0,0 +1,43 @@
+// file : odb/details/win32/init.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/init.hxx>
+#include <odb/details/win32/once-init.hxx>
+#include <odb/details/win32/tls-init.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ process_start ()
+ {
+ // The order is important.
+ //
+ once_process_start ();
+ tls_process_start ();
+ }
+
+ void
+ process_end (bool safe)
+ {
+ // The order is important.
+ //
+ tls_process_end (safe);
+ once_process_end (safe);
+ }
+
+ void
+ thread_start ()
+ {
+ }
+
+ void
+ thread_end ()
+ {
+ tls_thread_end ();
+ }
+ }
+}
diff --git a/odb/details/win32/init.hxx b/odb/details/win32/init.hxx
new file mode 100644
index 0000000..4a49129
--- /dev/null
+++ b/odb/details/win32/init.hxx
@@ -0,0 +1,38 @@
+// file : odb/details/win32/init.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_INIT_HXX
+#define ODB_DETAILS_WIN32_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ process_start ();
+
+ // The safe parameter indicates whether it is safe to free heap objects.
+ // If the process is terminated by a call to ExitProcess(), some threads
+ // might have been killed leaving things in inconsistent state.
+ //
+ void
+ process_end (bool safe = true);
+
+ void
+ thread_start ();
+
+ // This function may be called even for thread for which thread_start()
+ // hasn't been called.
+ //
+ void
+ thread_end ();
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_INIT_HXX
diff --git a/odb/details/win32/lock.hxx b/odb/details/win32/lock.hxx
new file mode 100644
index 0000000..50611e0
--- /dev/null
+++ b/odb/details/win32/lock.hxx
@@ -0,0 +1,51 @@
+// file : odb/details/win32/lock.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_LOCK_HXX
+#define ODB_DETAILS_WIN32_LOCK_HXX
+
+#include <odb/pre.hxx>
+
+#include <windows.h>
+
+namespace odb
+{
+ namespace details
+ {
+ // Critical section lock. Not exported; for internal use only.
+ //
+ struct win32_lock
+ {
+ win32_lock (CRITICAL_SECTION& cs)
+ : cs_ (&cs)
+ {
+ EnterCriticalSection (cs_);
+ }
+
+ ~win32_lock ()
+ {
+ if (cs_ != 0)
+ LeaveCriticalSection (cs_);
+ }
+
+ void
+ unlock ()
+ {
+ if (cs_ != 0)
+ {
+ LeaveCriticalSection (cs_);
+ cs_ = 0;
+ }
+ }
+
+ private:
+ CRITICAL_SECTION* cs_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_LOCK_HXX
diff --git a/odb/details/win32/once-init.hxx b/odb/details/win32/once-init.hxx
new file mode 100644
index 0000000..2826a8b
--- /dev/null
+++ b/odb/details/win32/once-init.hxx
@@ -0,0 +1,25 @@
+// file : odb/details/win32/once-init.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_ONCE_INIT_HXX
+#define ODB_DETAILS_WIN32_ONCE_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ once_process_start ();
+
+ void
+ once_process_end (bool safe);
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_ONCE_INIT_HXX
diff --git a/odb/details/win32/once.cxx b/odb/details/win32/once.cxx
new file mode 100644
index 0000000..9201ea6
--- /dev/null
+++ b/odb/details/win32/once.cxx
@@ -0,0 +1,29 @@
+// file : odb/details/win32/once.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <windows.h>
+
+#include <odb/details/win32/once.hxx>
+#include <odb/details/win32/once-init.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ CRITICAL_SECTION once::cs_;
+
+ void
+ once_process_start ()
+ {
+ InitializeCriticalSection (&once::cs_);
+ }
+
+ void
+ once_process_end (bool)
+ {
+ DeleteCriticalSection (&once::cs_);
+ }
+ }
+}
diff --git a/odb/details/win32/once.hxx b/odb/details/win32/once.hxx
new file mode 100644
index 0000000..258d5e0
--- /dev/null
+++ b/odb/details/win32/once.hxx
@@ -0,0 +1,49 @@
+// file : odb/details/win32/once.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_ONCE_HXX
+#define ODB_DETAILS_WIN32_ONCE_HXX
+
+#include <odb/pre.hxx>
+
+#include <windows.h>
+
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT once
+ {
+ public:
+ once ();
+
+ void
+ call (void (*func) ());
+
+ private:
+ once (const once&);
+ once& operator= (const once&);
+
+ private:
+ friend void
+ once_process_start ();
+
+ friend void
+ once_process_end (bool);
+
+ private:
+ bool called_;
+ static CRITICAL_SECTION cs_;
+ };
+ }
+}
+
+#include <odb/details/win32/once.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_ONCE_HXX
diff --git a/odb/details/win32/once.ixx b/odb/details/win32/once.ixx
new file mode 100644
index 0000000..9f1706d
--- /dev/null
+++ b/odb/details/win32/once.ixx
@@ -0,0 +1,30 @@
+// file : odb/details/win32/once.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/lock.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline once::
+ once ()
+ : called_ (false)
+ {
+ }
+
+ inline void once::
+ call (void (*func) ())
+ {
+ win32_lock l (cs_);
+
+ if (!called_)
+ {
+ func ();
+ called_ = true;
+ }
+ }
+ }
+}
diff --git a/odb/details/win32/tls-init.hxx b/odb/details/win32/tls-init.hxx
new file mode 100644
index 0000000..80e00f9
--- /dev/null
+++ b/odb/details/win32/tls-init.hxx
@@ -0,0 +1,28 @@
+// file : odb/details/win32/tls-init.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_TLS_INIT_HXX
+#define ODB_DETAILS_WIN32_TLS_INIT_HXX
+
+#include <odb/pre.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void
+ tls_process_start ();
+
+ void
+ tls_process_end (bool safe);
+
+ void
+ tls_thread_end ();
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_TLS_INIT_HXX
diff --git a/odb/details/win32/tls.cxx b/odb/details/win32/tls.cxx
new file mode 100644
index 0000000..48c2f00
--- /dev/null
+++ b/odb/details/win32/tls.cxx
@@ -0,0 +1,236 @@
+// file : odb/details/win32/tls.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <windows.h>
+#include <winerror.h> // ERROR_INVALID_INDEX
+
+#include <new>
+#include <cstddef> // std::size_t
+
+#include <odb/details/win32/lock.hxx>
+#include <odb/details/win32/tls.hxx>
+#include <odb/details/win32/tls-init.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ namespace details
+ {
+ typedef void (*dtor_func) (void*);
+
+ struct entry
+ {
+ void* value;
+ dtor_func dtor;
+ };
+
+ struct thread_data
+ {
+ size_t size;
+ size_t capacity;
+ entry entries[0];
+ };
+
+ struct process_data
+ {
+ size_t size;
+ size_t capacity;
+ dtor_func dtors[0];
+ };
+
+ static DWORD index_ = TLS_OUT_OF_INDEXES;
+ static CRITICAL_SECTION cs_;
+ static process_data* proc_data_;
+
+ const size_t init_capacity = 4;
+
+ void
+ tls_process_start ()
+ {
+ index_ = TlsAlloc ();
+
+ if (index_ == TLS_OUT_OF_INDEXES)
+ throw win32_exception ();
+
+ InitializeCriticalSection (&cs_);
+
+ proc_data_ = static_cast<process_data*> (
+ operator new (
+ sizeof (process_data) + sizeof (dtor_func) * init_capacity));
+
+ proc_data_->size = 0;
+ proc_data_->capacity = init_capacity;
+ memset (proc_data_->dtors, 0, sizeof (dtor_func) * init_capacity);
+ }
+
+ void
+ tls_process_end (bool safe)
+ {
+ if (safe)
+ operator delete (proc_data_);
+
+ DeleteCriticalSection (&cs_);
+
+ if (index_ != TLS_OUT_OF_INDEXES)
+ {
+ if (!TlsFree (index_))
+ throw win32_exception ();
+ }
+ }
+
+ void
+ tls_thread_end ()
+ {
+ if (thread_data* d = static_cast<thread_data*> (TlsGetValue (index_)))
+ {
+ // Call destructors. Implement the pthread semantics in that the
+ // destructors are called until all the values become 0.
+ //
+ for (bool pass (true); pass;)
+ {
+ pass = false;
+
+ for (size_t i (0); i < d->size; ++i)
+ {
+ if (d->entries[i].dtor != 0 && d->entries[i].value != 0)
+ {
+ pass = true;
+ void* tmp (d->entries[i].value);
+ d->entries[i].value = 0;
+ d->entries[i].dtor (tmp);
+ }
+ }
+ }
+
+ operator delete (d);
+ }
+ }
+
+ //
+ // tls_common
+ //
+
+ std::size_t tls_common::
+ _allocate (dtor_func dtor)
+ {
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+ size_t c (proc_data_->capacity);
+
+ if (n == c)
+ {
+ c *= 2;
+
+ process_data* pd (
+ static_cast<process_data*> (
+ operator new (sizeof (process_data) + sizeof (dtor_func) * c)));
+
+ memcpy (pd->dtors, proc_data_->dtors, n * sizeof (dtor_func));
+ memset (proc_data_->dtors + n, 0, sizeof (dtor_func) * (c - n));
+
+ pd->size = n;
+ pd->capacity = c;
+ operator delete (proc_data_);
+ proc_data_ = pd;
+ }
+
+ proc_data_->dtors[n] = dtor;
+ return proc_data_->size++;
+ }
+
+ void* tls_common::
+ _get (std::size_t key)
+ {
+ if (thread_data* d = static_cast<thread_data*> (TlsGetValue (index_)))
+ {
+ if (key < d->size)
+ return d->entries[key].value;
+ }
+
+ // Check if this key is valid.
+ //
+ win32_lock l (cs_);
+
+ if (key < proc_data_->size)
+ return 0;
+
+ throw win32_exception (ERROR_INVALID_INDEX);
+ }
+
+ void tls_common::
+ _set (std::size_t key, void* value)
+ {
+ thread_data* d (static_cast<thread_data*> (TlsGetValue (index_)));
+
+ if (d != 0 && key < d->capacity)
+ {
+ if (key >= d->size)
+ {
+ // Check if this key is valid. If so then we need to copy
+ // dtors for new slots.
+ //
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+
+ if (key >= n)
+ throw win32_exception (ERROR_INVALID_INDEX);
+
+ for (size_t i (d->size); i < n; ++i)
+ d->entries[i].dtor = proc_data_->dtors[i];
+
+ d->size = n;
+ }
+
+ d->entries[key].value = value;
+ }
+ else
+ {
+ // Check if this key is valid. If so then we need to (re)-allocate
+ // our storage.
+ //
+ win32_lock l (cs_);
+
+ size_t n (proc_data_->size);
+
+ if (key >= n)
+ throw win32_exception (ERROR_INVALID_INDEX);
+
+ size_t c (proc_data_->capacity);
+
+ thread_data* nd (
+ static_cast<thread_data*> (
+ operator new (sizeof (thread_data) + sizeof (entry) * c)));
+
+ size_t on (d == 0 ? 0 : d->size);
+
+ // Copy over the data.
+ //
+ if (on != 0)
+ memcpy (nd->entries, d->entries, sizeof (entry) * on);
+
+ // Zero out the rest.
+ //
+ memset (nd->entries + on, 0, sizeof (entry) * (c - on));
+
+ // Assign destructors to new slots [on, n).
+ //
+ for (size_t i (on); i < n; ++i)
+ nd->entries[i].dtor = proc_data_->dtors[i];
+
+ nd->size = n;
+ nd->capacity = c;
+
+ operator delete (d);
+ TlsSetValue (index_, nd);
+
+ nd->entries[key].value = value;
+ }
+ }
+ }
+}
diff --git a/odb/details/win32/tls.hxx b/odb/details/win32/tls.hxx
new file mode 100644
index 0000000..b1dce0f
--- /dev/null
+++ b/odb/details/win32/tls.hxx
@@ -0,0 +1,111 @@
+// file : odb/details/win32/tls.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_TLS_HXX
+#define ODB_DETAILS_WIN32_TLS_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/export.hxx>
+#include <odb/details/win32/once.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT tls_common
+ {
+ public:
+ static std::size_t
+ _allocate (void (*dtor) (void*));
+
+ static void*
+ _get (std::size_t key);
+
+ static void
+ _set (std::size_t key, void* value);
+ };
+
+ template <typename T>
+ class tls: protected tls_common
+ {
+ public:
+ tls ();
+
+ T&
+ get () const;
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ static void
+ destructor (void*);
+
+ private:
+ static once once_;
+ static std::size_t key_;
+ };
+
+ template <typename T>
+ class tls<T*>: protected tls_common
+ {
+ public:
+ tls ();
+
+ T*
+ get () const;
+
+ void
+ set (T* p);
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ private:
+ static once once_;
+ static std::size_t key_;
+ };
+
+ template <typename T>
+ inline T&
+ tls_get (const tls<T>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (const tls<T*>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T>
+ inline void
+ tls_set (tls<T*>& t, T* p)
+ {
+ t.set (p);
+ }
+ }
+}
+
+#include <odb/details/win32/tls.ixx>
+#include <odb/details/win32/tls.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_TLS_HXX
diff --git a/odb/details/win32/tls.ixx b/odb/details/win32/tls.ixx
new file mode 100644
index 0000000..7b0f341
--- /dev/null
+++ b/odb/details/win32/tls.ixx
@@ -0,0 +1,22 @@
+// file : odb/details/win32/tls.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ template <typename T>
+ inline tls<T>::
+ tls ()
+ {
+ }
+
+ template <typename T>
+ inline tls<T*>::
+ tls ()
+ {
+ }
+ }
+}
diff --git a/odb/details/win32/tls.txx b/odb/details/win32/tls.txx
new file mode 100644
index 0000000..f20b6a9
--- /dev/null
+++ b/odb/details/win32/tls.txx
@@ -0,0 +1,87 @@
+// file : odb/details/win32/tls.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <memory> // std::auto_ptr
+
+#include <odb/details/win32/exceptions.hxx>
+
+using namespace std;
+
+namespace odb
+{
+ namespace details
+ {
+ // tls<T>
+ //
+ template <typename T>
+ once tls<T>::once_;
+
+ template <typename T>
+ size_t tls<T>::key_;
+
+ template <typename T>
+ T& tls<T>::
+ get () const
+ {
+ once_.call (key_init);
+ void* v (_get (key_));
+
+ if (v != 0)
+ return *static_cast<T*> (v);
+
+ auto_ptr<T> p (new T);
+ _set (key_, p.get ());
+
+ T& r (*p);
+ p.release ();
+ return r;
+ }
+
+ template <typename T>
+ void tls<T>::
+ key_init ()
+ {
+ key_ = _allocate (destructor);
+ }
+
+ template <typename T>
+ void tls<T>::
+ destructor (void* v)
+ {
+ delete static_cast<T*> (v);
+ }
+
+ // tls<T*>
+ //
+ template <typename T>
+ once tls<T*>::once_;
+
+ template <typename T>
+ size_t tls<T*>::key_;
+
+ template <typename T>
+ T* tls<T*>::
+ get () const
+ {
+ once_.call (key_init);
+ return static_cast<T*> (_get (key_));
+ }
+
+ template <typename T>
+ void tls<T*>::
+ set (T* p)
+ {
+ once_.call (key_init);
+ _set (key_, p);
+ }
+
+ template <typename T>
+ void tls<T*>::
+ key_init ()
+ {
+ key_ = _allocate (0);
+ }
+ }
+}
diff --git a/odb/libodb-vc10.vcxproj b/odb/libodb-vc10.vcxproj
index 81f1a2a..18e5415 100644
--- a/odb/libodb-vc10.vcxproj
+++ b/odb/libodb-vc10.vcxproj
@@ -165,6 +165,7 @@ __header_entry__(details\config-vc.h)
<ItemGroup>
__source_entries__(sources)
__source_entries__(win32_sources)
+__source_entries__(win32_dll_sources)
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
diff --git a/odb/libodb-vc9.vcproj b/odb/libodb-vc9.vcproj
index 3877c89..d8a98b3 100644
--- a/odb/libodb-vc9.vcproj
+++ b/odb/libodb-vc9.vcproj
@@ -342,6 +342,7 @@
>
__source_entries__(sources)
__source_entries__(win32_sources)
+__source_entries__(win32_dll_sources)
</Filter>
<Filter
Name="Header Files"
diff --git a/odb/makefile b/odb/makefile
index e058463..0fb038d 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -26,9 +26,14 @@ details/posix/thread.cxx
# Win32-based implementation details.
#
win32_cxx := \
-details/win32/exceptions.cxx \
+details/win32/init.cxx \
+details/win32/once.cxx \
+details/win32/tls.cxx \
details/win32/condition.cxx \
-details/win32/thread.cxx
+details/win32/thread.cxx \
+details/win32/exceptions.cxx
+
+win32_dll_cxx := details/win32/dll.cxx
cxx_tun := $(cxx) $(posix_cxx)
cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
@@ -61,6 +66,7 @@ $(out_base)/: $(odb.l)
$(dist): export sources := $(cxx)
$(dist): export posix_sources := $(posix_cxx)
$(dist): export win32_sources := $(win32_cxx)
+$(dist): export win32_dll_sources := $(win32_dll_cxx)
$(dist): export headers = $(subst $(src_base)/,,$(shell find $(src_base) \
-path $(src_base)/details/posix -a -prune -a -false -o \
@@ -79,7 +85,8 @@ $(dist): export interface_version = $(shell sed -e \
$(dist):
$(call dist-data,$(sources) $(posix_sources) $(win32_sources) \
-$(headers) $(posix_headers) $(win32_headers) $(data_dist) details/config.h.in)
+$(win32_dll_sources) $(headers) $(posix_headers) $(win32_headers) \
+$(data_dist) details/config.h.in)
$(call meta-vc9proj,$(src_base)/libodb-vc9.vcproj)
$(call meta-vc10proj,$(src_base)/libodb-vc10.vcxproj)
$(call meta-automake)