summaryrefslogtreecommitdiff
path: root/libodb/odb/details/win32
diff options
context:
space:
mode:
Diffstat (limited to 'libodb/odb/details/win32')
-rw-r--r--libodb/odb/details/win32/condition.cxx54
-rw-r--r--libodb/odb/details/win32/condition.hxx52
-rw-r--r--libodb/odb/details/win32/condition.ixx30
-rw-r--r--libodb/odb/details/win32/dll.cxx51
-rw-r--r--libodb/odb/details/win32/exceptions.cxx22
-rw-r--r--libodb/odb/details/win32/exceptions.hxx40
-rw-r--r--libodb/odb/details/win32/init.cxx41
-rw-r--r--libodb/odb/details/win32/init.hxx36
-rw-r--r--libodb/odb/details/win32/lock.hxx49
-rw-r--r--libodb/odb/details/win32/mutex.hxx43
-rw-r--r--libodb/odb/details/win32/mutex.ixx32
-rw-r--r--libodb/odb/details/win32/once-init.hxx23
-rw-r--r--libodb/odb/details/win32/once.cxx26
-rw-r--r--libodb/odb/details/win32/once.hxx50
-rw-r--r--libodb/odb/details/win32/once.ixx42
-rw-r--r--libodb/odb/details/win32/thread.cxx88
-rw-r--r--libodb/odb/details/win32/thread.hxx59
-rw-r--r--libodb/odb/details/win32/tls-init.hxx26
-rw-r--r--libodb/odb/details/win32/tls.cxx245
-rw-r--r--libodb/odb/details/win32/tls.hxx120
-rw-r--r--libodb/odb/details/win32/tls.ixx20
-rw-r--r--libodb/odb/details/win32/tls.txx94
-rw-r--r--libodb/odb/details/win32/windows.hxx33
23 files changed, 1276 insertions, 0 deletions
diff --git a/libodb/odb/details/win32/condition.cxx b/libodb/odb/details/win32/condition.cxx
new file mode 100644
index 0000000..3a4b605
--- /dev/null
+++ b/libodb/odb/details/win32/condition.cxx
@@ -0,0 +1,54 @@
+// file : odb/details/win32/condition.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/win32/condition.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ void condition::
+ signal ()
+ {
+ mutex_.lock ();
+
+ if (waiters_ > signals_)
+ {
+ if (signals_++ == 0)
+ {
+ if (SetEvent (event_) == 0)
+ throw win32_exception ();
+ }
+ }
+
+ mutex_.unlock ();
+ }
+
+ void condition::
+ wait (lock&)
+ {
+ // When we enter this functions the mutex is locked. When we
+ // return from this function the mutex must be locked.
+ //
+ waiters_++;
+ mutex_.unlock ();
+
+ if (WaitForSingleObject (event_, INFINITE) != 0)
+ throw win32_exception ();
+
+ mutex_.lock ();
+ waiters_--;
+ signals_--;
+
+ if (signals_ > 0)
+ {
+ // Wake up the next thread.
+ //
+ if (SetEvent (event_) == 0)
+ throw win32_exception ();
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/condition.hxx b/libodb/odb/details/win32/condition.hxx
new file mode 100644
index 0000000..69972a0
--- /dev/null
+++ b/libodb/odb/details/win32/condition.hxx
@@ -0,0 +1,52 @@
+// file : odb/details/win32/condition.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_CONDITION_HXX
+#define ODB_DETAILS_WIN32_CONDITION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/details/export.hxx>
+#include <odb/details/win32/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class lock;
+
+ class LIBODB_EXPORT condition
+ {
+ public:
+ ~condition ();
+ condition (mutex&);
+
+ void
+ signal ();
+
+ void
+ wait (lock&);
+
+ private:
+ condition (const condition&);
+ condition& operator= (const condition&);
+
+ private:
+ mutex& mutex_;
+ HANDLE event_;
+
+ std::size_t waiters_;
+ std::size_t signals_;
+ };
+ }
+}
+
+#include <odb/details/win32/condition.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_CONDITION_HXX
diff --git a/libodb/odb/details/win32/condition.ixx b/libodb/odb/details/win32/condition.ixx
new file mode 100644
index 0000000..37a2bac
--- /dev/null
+++ b/libodb/odb/details/win32/condition.ixx
@@ -0,0 +1,30 @@
+// file : odb/details/win32/condition.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline condition::
+ ~condition ()
+ {
+ CloseHandle (event_);
+ }
+
+ inline condition::
+ condition (mutex& mutex)
+ : mutex_ (mutex), waiters_ (0), signals_ (0)
+ {
+ // Auto-reset event. Releases one waiting thread and automatically
+ // resets the event state. If no threads are waiting the event
+ // remains signalled.
+ //
+ event_ = CreateEvent (0, false, false, 0);
+
+ if (event_ == 0)
+ throw win32_exception ();
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/dll.cxx b/libodb/odb/details/win32/dll.cxx
new file mode 100644
index 0000000..49b660c
--- /dev/null
+++ b/libodb/odb/details/win32/dll.cxx
@@ -0,0 +1,51 @@
+// file : odb/details/win32/dll.cxx
+// 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(_MSC_VER) && defined(LIBODB_DYNAMIC_LIB)) || \
+ (!defined(_MSC_VER) && defined(DLL_EXPORT))
+
+#include <odb/details/win32/windows.hxx>
+#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/libodb/odb/details/win32/exceptions.cxx b/libodb/odb/details/win32/exceptions.cxx
new file mode 100644
index 0000000..3cf11c2
--- /dev/null
+++ b/libodb/odb/details/win32/exceptions.cxx
@@ -0,0 +1,22 @@
+// file : odb/details/win32/exceptions.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ const char* win32_exception::
+ what () const ODB_NOTHROW_NOEXCEPT
+ {
+ return "Win32 API error";
+ }
+
+ win32_exception* win32_exception::
+ clone () const
+ {
+ return new win32_exception (*this);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/exceptions.hxx b/libodb/odb/details/win32/exceptions.hxx
new file mode 100644
index 0000000..b61a447
--- /dev/null
+++ b/libodb/odb/details/win32/exceptions.hxx
@@ -0,0 +1,40 @@
+// file : odb/details/win32/exceptions.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_EXCEPTIONS_HXX
+#define ODB_DETAILS_WIN32_EXCEPTIONS_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/config.hxx> // ODB_NOTHROW_NOEXCEPT
+#include <odb/details/export.hxx>
+#include <odb/details/exception.hxx>
+#include <odb/details/win32/windows.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ struct LIBODB_EXPORT win32_exception: details::exception
+ {
+ win32_exception () : code_ (GetLastError ()) {}
+ win32_exception (DWORD code) : code_ (code) {}
+
+ DWORD
+ code () const {return code_;}
+
+ virtual const char*
+ what () const ODB_NOTHROW_NOEXCEPT;
+
+ virtual win32_exception*
+ clone () const;
+
+ private:
+ DWORD code_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_EXCEPTIONS_HXX
diff --git a/libodb/odb/details/win32/init.cxx b/libodb/odb/details/win32/init.cxx
new file mode 100644
index 0000000..f6e0f9a
--- /dev/null
+++ b/libodb/odb/details/win32/init.cxx
@@ -0,0 +1,41 @@
+// file : odb/details/win32/init.cxx
+// 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/libodb/odb/details/win32/init.hxx b/libodb/odb/details/win32/init.hxx
new file mode 100644
index 0000000..1c15ffd
--- /dev/null
+++ b/libodb/odb/details/win32/init.hxx
@@ -0,0 +1,36 @@
+// file : odb/details/win32/init.hxx
+// 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/libodb/odb/details/win32/lock.hxx b/libodb/odb/details/win32/lock.hxx
new file mode 100644
index 0000000..2e81ac6
--- /dev/null
+++ b/libodb/odb/details/win32/lock.hxx
@@ -0,0 +1,49 @@
+// file : odb/details/win32/lock.hxx
+// 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 <odb/details/win32/windows.hxx>
+
+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/libodb/odb/details/win32/mutex.hxx b/libodb/odb/details/win32/mutex.hxx
new file mode 100644
index 0000000..b2cd997
--- /dev/null
+++ b/libodb/odb/details/win32/mutex.hxx
@@ -0,0 +1,43 @@
+// file : odb/details/win32/mutex.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_MUTEX_HXX
+#define ODB_DETAILS_WIN32_MUTEX_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/export.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT mutex
+ {
+ public:
+ ~mutex ();
+ mutex ();
+
+ void
+ lock ();
+
+ void
+ unlock ();
+
+ private:
+ mutex (const mutex&);
+ mutex& operator= (const mutex&);
+
+ private:
+ friend class condition;
+ CRITICAL_SECTION cs_;
+ };
+ }
+}
+
+#include <odb/details/win32/mutex.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_MUTEX_HXX
diff --git a/libodb/odb/details/win32/mutex.ixx b/libodb/odb/details/win32/mutex.ixx
new file mode 100644
index 0000000..bb06415
--- /dev/null
+++ b/libodb/odb/details/win32/mutex.ixx
@@ -0,0 +1,32 @@
+// file : odb/details/win32/mutex.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace details
+ {
+ inline mutex::
+ ~mutex ()
+ {
+ DeleteCriticalSection (&cs_);
+ }
+
+ inline mutex::
+ mutex ()
+ {
+ InitializeCriticalSection (&cs_);
+ }
+
+ inline void mutex::
+ lock ()
+ {
+ EnterCriticalSection (&cs_);
+ }
+
+ inline void mutex::
+ unlock ()
+ {
+ LeaveCriticalSection (&cs_);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/once-init.hxx b/libodb/odb/details/win32/once-init.hxx
new file mode 100644
index 0000000..a465c90
--- /dev/null
+++ b/libodb/odb/details/win32/once-init.hxx
@@ -0,0 +1,23 @@
+// file : odb/details/win32/once-init.hxx
+// 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/libodb/odb/details/win32/once.cxx b/libodb/odb/details/win32/once.cxx
new file mode 100644
index 0000000..7b98d80
--- /dev/null
+++ b/libodb/odb/details/win32/once.cxx
@@ -0,0 +1,26 @@
+// file : odb/details/win32/once.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/win32/once.hxx>
+#include <odb/details/win32/once-init.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ CRITICAL_SECTION win32_once_cs_;
+
+ void
+ once_process_start ()
+ {
+ InitializeCriticalSection (&win32_once_cs_);
+ }
+
+ void
+ once_process_end (bool)
+ {
+ DeleteCriticalSection (&win32_once_cs_);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/once.hxx b/libodb/odb/details/win32/once.hxx
new file mode 100644
index 0000000..45748b8
--- /dev/null
+++ b/libodb/odb/details/win32/once.hxx
@@ -0,0 +1,50 @@
+// file : odb/details/win32/once.hxx
+// 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 <odb/details/win32/windows.hxx>
+#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:
+ bool called_;
+ };
+
+ // Low-level, POSIX-like API that can be used safely during static
+ // initialization (that is, win32_once() can be called during static
+ // initialization) provided once_process_start() has been called.
+ //
+ typedef unsigned int win32_once_t;
+ const win32_once_t WIN32_ONCE_INIT = 0;
+
+ LIBODB_EXPORT void
+ win32_once (win32_once_t&, void (*func) ());
+
+ extern LIBODB_EXPORT CRITICAL_SECTION win32_once_cs_;
+ }
+}
+
+#include <odb/details/win32/once.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_ONCE_HXX
diff --git a/libodb/odb/details/win32/once.ixx b/libodb/odb/details/win32/once.ixx
new file mode 100644
index 0000000..1638706
--- /dev/null
+++ b/libodb/odb/details/win32/once.ixx
@@ -0,0 +1,42 @@
+// file : odb/details/win32/once.ixx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/lock.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ inline void
+ win32_once (win32_once_t& o, void (*func) ())
+ {
+ win32_lock l (win32_once_cs_);
+
+ if (o == 0)
+ {
+ o = 1;
+ l.unlock ();
+ func ();
+ }
+ }
+
+ inline once::
+ once ()
+ : called_ (false)
+ {
+ }
+
+ inline void once::
+ call (void (*func) ())
+ {
+ win32_lock l (win32_once_cs_);
+
+ if (!called_)
+ {
+ called_ = true;
+ l.unlock ();
+ func ();
+ }
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/thread.cxx b/libodb/odb/details/win32/thread.cxx
new file mode 100644
index 0000000..46720d4
--- /dev/null
+++ b/libodb/odb/details/win32/thread.cxx
@@ -0,0 +1,88 @@
+// file : odb/details/win32/thread.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#include <process.h> // _beginthreadex, _endthreadex
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/win32/thread.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+unsigned int __stdcall
+odb_thread_thunk (void* arg)
+{
+ odb::details::thread::thread_thunk (arg);
+ _endthreadex (0);
+ return 0;
+}
+
+namespace odb
+{
+ namespace details
+ {
+ void thread::
+ thread_thunk (void* arg)
+ {
+ data* d (static_cast<data*> (arg));
+ d->ret = d->func (d->arg);
+ d->mutex.lock ();
+ unsigned char count = --d->count;
+ d->mutex.unlock ();
+
+ if (count == 0)
+ delete d;
+ }
+
+ thread::
+ ~thread ()
+ {
+ if (handle_ != 0)
+ {
+ CloseHandle (handle_);
+
+ // Win32 mutex implementation does not throw.
+ //
+ data_->mutex.lock ();
+ unsigned char count = --data_->count;
+ data_->mutex.unlock ();
+
+ if (count == 0)
+ delete data_;
+ }
+ }
+
+ thread::
+ thread (void* (*func) (void*), void* arg)
+ {
+ unique_ptr<data> d (new data);
+ d->func = func;
+ d->arg = arg;
+ d->count = 2; // One for the thread and one for us.
+
+ handle_ = (HANDLE)_beginthreadex (
+ 0, 0, &odb_thread_thunk, d.get (), 0, 0);
+
+ if (handle_ == 0)
+ throw win32_exception ();
+
+ data_ = d.release ();
+ }
+
+ void* thread::
+ join ()
+ {
+ void* r;
+
+ if (WaitForSingleObject (handle_, INFINITE) != 0)
+ throw win32_exception ();
+
+ r = data_->ret;
+
+ CloseHandle (handle_);
+ delete data_;
+ handle_ = 0;
+ data_ = 0;
+ return r;
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/thread.hxx b/libodb/odb/details/win32/thread.hxx
new file mode 100644
index 0000000..a4e1a15
--- /dev/null
+++ b/libodb/odb/details/win32/thread.hxx
@@ -0,0 +1,59 @@
+// file : odb/details/win32/thread.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_THREAD_HXX
+#define ODB_DETAILS_WIN32_THREAD_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/win32/windows.hxx>
+#include <odb/details/export.hxx>
+#include <odb/details/win32/mutex.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ class LIBODB_EXPORT thread
+ {
+ public:
+ ~thread ();
+ thread (void* (*thread_func) (void*), void* arg = 0);
+
+ void*
+ join ();
+
+ private:
+ thread (const thread&);
+ thread& operator= (const thread&);
+
+ private:
+ typedef void* (*thread_func) (void*);
+
+ struct data
+ {
+ thread_func func;
+ void* arg;
+ void* ret;
+
+ // Thread-safe reference counter.
+ //
+ details::mutex mutex;
+ unsigned char count;
+ };
+
+
+ public:
+ static void
+ thread_thunk (void*);
+
+ private:
+ HANDLE handle_;
+ data* data_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_THREAD_HXX
diff --git a/libodb/odb/details/win32/tls-init.hxx b/libodb/odb/details/win32/tls-init.hxx
new file mode 100644
index 0000000..0a44a10
--- /dev/null
+++ b/libodb/odb/details/win32/tls-init.hxx
@@ -0,0 +1,26 @@
+// file : odb/details/win32/tls-init.hxx
+// 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/libodb/odb/details/win32/tls.cxx b/libodb/odb/details/win32/tls.cxx
new file mode 100644
index 0000000..2edc364
--- /dev/null
+++ b/libodb/odb/details/win32/tls.cxx
@@ -0,0 +1,245 @@
+// file : odb/details/win32/tls.cxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/win32/windows.hxx>
+#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>
+
+#ifdef _MSC_VER
+# pragma warning (disable:4200) // zero-sized array in struct
+#endif
+
+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_);
+
+ process_data* pd (
+ static_cast<process_data*> (
+ operator new (
+ sizeof (process_data) + sizeof (dtor_func) * init_capacity)));
+
+ pd->size = 0;
+ pd->capacity = init_capacity;
+ memset (pd->dtors, 0, sizeof (dtor_func) * init_capacity);
+
+ proc_data_ = pd;
+ }
+
+ void
+ tls_process_end (bool)
+ {
+ 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;
+
+ // Try to do "atomic" switch-over so that proc_data_ always points
+ // to memory that can be freed even if this thread is killed in the
+ // middle.
+ //
+ 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 (pd->dtors + n, 0, sizeof (dtor_func) * (c - n));
+
+ pd->size = n;
+ pd->capacity = c;
+
+ process_data* old (proc_data_);
+ proc_data_ = pd;
+ operator delete (old);
+ }
+
+ 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/libodb/odb/details/win32/tls.hxx b/libodb/odb/details/win32/tls.hxx
new file mode 100644
index 0000000..2a75cc8
--- /dev/null
+++ b/libodb/odb/details/win32/tls.hxx
@@ -0,0 +1,120 @@
+// file : odb/details/win32/tls.hxx
+// 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;
+
+ void
+ free ();
+
+ private:
+ tls (const tls&);
+ tls& operator= (const tls&);
+
+ private:
+ static void
+ key_init ();
+
+ static void
+ destructor (void*);
+
+ private:
+ static win32_once_t 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 win32_once_t once_;
+ static std::size_t key_;
+ };
+
+ template <typename T>
+ inline T&
+ tls_get (const tls<T>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T>
+ inline void
+ tls_free (tls<T>& t)
+ {
+ t.free ();
+ }
+
+ template <typename T>
+ inline T*
+ tls_get (const tls<T*>& t)
+ {
+ return t.get ();
+ }
+
+ template <typename T, typename T1>
+ inline void
+ tls_set (tls<T*>& t, T1* p1)
+ {
+ T* p (p1);
+ 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/libodb/odb/details/win32/tls.ixx b/libodb/odb/details/win32/tls.ixx
new file mode 100644
index 0000000..fbcc3dd
--- /dev/null
+++ b/libodb/odb/details/win32/tls.ixx
@@ -0,0 +1,20 @@
+// file : odb/details/win32/tls.ixx
+// 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/libodb/odb/details/win32/tls.txx b/libodb/odb/details/win32/tls.txx
new file mode 100644
index 0000000..96bed4c
--- /dev/null
+++ b/libodb/odb/details/win32/tls.txx
@@ -0,0 +1,94 @@
+// file : odb/details/win32/tls.txx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <odb/details/unique-ptr.hxx>
+#include <odb/details/win32/exceptions.hxx>
+
+namespace odb
+{
+ namespace details
+ {
+ // tls<T>
+ //
+ template <typename T>
+ win32_once_t tls<T>::once_= WIN32_ONCE_INIT;
+
+ template <typename T>
+ size_t tls<T>::key_;
+
+ template <typename T>
+ T& tls<T>::
+ get () const
+ {
+ win32_once (once_, key_init);
+
+ if (void* v = _get (key_))
+ return *static_cast<T*> (v);
+
+ unique_ptr<T> p (new T);
+ _set (key_, p.get ());
+
+ T& r (*p);
+ p.release ();
+ return r;
+ }
+
+ template <typename T>
+ void tls<T>::
+ free ()
+ {
+ win32_once (once_, key_init);
+
+ if (void* v = _get (key_))
+ {
+ _set (key_, 0);
+ delete static_cast<T*> (v);
+ }
+ }
+
+ 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>
+ win32_once_t tls<T*>::once_ = WIN32_ONCE_INIT;
+
+ template <typename T>
+ size_t tls<T*>::key_;
+
+ template <typename T>
+ T* tls<T*>::
+ get () const
+ {
+ win32_once (once_, key_init);
+ return static_cast<T*> (_get (key_));
+ }
+
+ template <typename T>
+ void tls<T*>::
+ set (T* p)
+ {
+ win32_once (once_, key_init);
+ _set (key_, p);
+ }
+
+ template <typename T>
+ void tls<T*>::
+ key_init ()
+ {
+ key_ = _allocate (0);
+ }
+ }
+}
diff --git a/libodb/odb/details/win32/windows.hxx b/libodb/odb/details/win32/windows.hxx
new file mode 100644
index 0000000..9ff4cb4
--- /dev/null
+++ b/libodb/odb/details/win32/windows.hxx
@@ -0,0 +1,33 @@
+// file : odb/details/win32/windows.hxx
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_DETAILS_WIN32_WINDOWS_HXX
+#define ODB_DETAILS_WIN32_WINDOWS_HXX
+
+#include <odb/pre.hxx>
+
+// Try to include <windows.h> so that it doesn't mess other things up.
+//
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# ifndef NOMINMAX // No min and max macros.
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+# undef WIN32_LEAN_AND_MEAN
+#else
+# ifndef NOMINMAX
+# define NOMINMAX
+# include <windows.h>
+# undef NOMINMAX
+# else
+# include <windows.h>
+# endif
+#endif
+
+#include <odb/post.hxx>
+
+#endif // ODB_DETAILS_WIN32_WINDOWS_HXX