diff options
Diffstat (limited to 'libodb/odb/details/win32')
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 |