X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=glib%2Fgthread-win32.c;h=275ecc63c552abbf9d8f135e9343651e2a7ba460;hb=2a53b4d0e2c98a14aedf31e38f0ad1fb2e8fe26f;hp=7f8fb4fc937d3cef3583708dab6f19925633ef84;hpb=3422dcfd28c2e33b5dffbcc0f59cfa507b89a468;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index 7f8fb4f..275ecc6 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -16,9 +16,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* @@ -42,8 +40,11 @@ #include "config.h" +#include "glib.h" +#include "glib-init.h" #include "gthread.h" #include "gthreadprivate.h" +#include "gslice.h" #include @@ -70,13 +71,8 @@ g_thread_abort (gint status, * that only get the kernel involved in cases of contention (similar * to how futex()-based mutexes work on Linux). The biggest advantage * of these new types is that they can be statically initialised to - * zero. This allows us to use them directly and still support: - * - * GMutex mutex = G_MUTEX_INIT; - * - * and - * - * GCond cond = G_COND_INIT; + * zero. That means that they are completely ABI compatible with our + * GMutex and GCond APIs. * * Unfortunately, Windows XP lacks these facilities and GLib still * needs to support Windows XP. Our approach here is as follows: @@ -106,6 +102,9 @@ typedef struct void (__stdcall * AcquireSRWLockExclusive) (gpointer lock); BOOLEAN (__stdcall * TryAcquireSRWLockExclusive) (gpointer lock); void (__stdcall * ReleaseSRWLockExclusive) (gpointer lock); + void (__stdcall * AcquireSRWLockShared) (gpointer lock); + BOOLEAN (__stdcall * TryAcquireSRWLockShared) (gpointer lock); + void (__stdcall * ReleaseSRWLockShared) (gpointer lock); void (__stdcall * InitializeConditionVariable) (gpointer cond); void (__stdcall * DeleteConditionVariable) (gpointer cond); /* fake */ @@ -151,6 +150,123 @@ g_mutex_unlock (GMutex *mutex) g_thread_impl_vtable.ReleaseSRWLockExclusive (mutex); } +/* {{{1 GRecMutex */ + +static CRITICAL_SECTION * +g_rec_mutex_impl_new (void) +{ + CRITICAL_SECTION *cs; + + cs = g_slice_new (CRITICAL_SECTION); + InitializeCriticalSection (cs); + + return cs; +} + +static void +g_rec_mutex_impl_free (CRITICAL_SECTION *cs) +{ + DeleteCriticalSection (cs); + g_slice_free (CRITICAL_SECTION, cs); +} + +static CRITICAL_SECTION * +g_rec_mutex_get_impl (GRecMutex *mutex) +{ + CRITICAL_SECTION *impl = mutex->p; + + if G_UNLIKELY (mutex->p == NULL) + { + impl = g_rec_mutex_impl_new (); + if (InterlockedCompareExchangePointer (&mutex->p, impl, NULL) != NULL) + g_rec_mutex_impl_free (impl); + impl = mutex->p; + } + + return impl; +} + +void +g_rec_mutex_init (GRecMutex *mutex) +{ + mutex->p = g_rec_mutex_impl_new (); +} + +void +g_rec_mutex_clear (GRecMutex *mutex) +{ + g_rec_mutex_impl_free (mutex->p); +} + +void +g_rec_mutex_lock (GRecMutex *mutex) +{ + EnterCriticalSection (g_rec_mutex_get_impl (mutex)); +} + +void +g_rec_mutex_unlock (GRecMutex *mutex) +{ + LeaveCriticalSection (mutex->p); +} + +gboolean +g_rec_mutex_trylock (GRecMutex *mutex) +{ + return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex)); +} + +/* {{{1 GRWLock */ + +void +g_rw_lock_init (GRWLock *lock) +{ + g_thread_impl_vtable.InitializeSRWLock (lock); +} + +void +g_rw_lock_clear (GRWLock *lock) +{ + if (g_thread_impl_vtable.DeleteSRWLock != NULL) + g_thread_impl_vtable.DeleteSRWLock (lock); +} + +void +g_rw_lock_writer_lock (GRWLock *lock) +{ + g_thread_impl_vtable.AcquireSRWLockExclusive (lock); +} + +gboolean +g_rw_lock_writer_trylock (GRWLock *lock) +{ + return g_thread_impl_vtable.TryAcquireSRWLockExclusive (lock); +} + +void +g_rw_lock_writer_unlock (GRWLock *lock) +{ + g_thread_impl_vtable.ReleaseSRWLockExclusive (lock); +} + +void +g_rw_lock_reader_lock (GRWLock *lock) +{ + g_thread_impl_vtable.AcquireSRWLockShared (lock); +} + +gboolean +g_rw_lock_reader_trylock (GRWLock *lock) +{ + return g_thread_impl_vtable.TryAcquireSRWLockShared (lock); +} + +void +g_rw_lock_reader_unlock (GRWLock *lock) +{ + g_thread_impl_vtable.ReleaseSRWLockShared (lock); +} + /* {{{1 GCond */ void g_cond_init (GCond *cond) @@ -185,21 +301,13 @@ g_cond_wait (GCond *cond, } gboolean -g_cond_timedwait (GCond *cond, - GMutex *entered_mutex, - gint64 abs_time) +g_cond_wait_until (GCond *cond, + GMutex *entered_mutex, + gint64 end_time) { gint64 span; - FILETIME ft; - gint64 now; - - GetSystemTimeAsFileTime (&ft); - memmove (&now, &ft, sizeof (FILETIME)); - now -= G_GINT64_CONSTANT (116444736000000000); - now /= 10; - - span = abs_time - now; + span = end_time - g_get_monotonic_time (); if G_UNLIKELY (span < 0) span = 0; @@ -210,28 +318,6 @@ g_cond_timedwait (GCond *cond, return g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, span / 1000, 0); } -gboolean -g_cond_timed_wait (GCond *cond, - GMutex *entered_mutex, - GTimeVal *abs_time) -{ - if (abs_time) - { - gint64 micros; - - micros = abs_time->tv_sec; - micros *= 1000000; - micros += abs_time->tv_usec; - - return g_cond_timedwait (cond, entered_mutex, micros); - } - else - { - g_cond_wait (cond, entered_mutex); - return TRUE; - } -} - /* {{{1 GPrivate */ typedef struct _GPrivateDestructor GPrivateDestructor; @@ -244,55 +330,84 @@ struct _GPrivateDestructor }; static GPrivateDestructor * volatile g_private_destructors; +static CRITICAL_SECTION g_private_lock; -void -g_private_init (GPrivate *key, - GDestroyNotify notify) +static DWORD +g_private_get_impl (GPrivate *key) { - GPrivateDestructor *destructor; + DWORD impl = (DWORD) key->p; - key->index = TlsAlloc (); + if G_UNLIKELY (impl == 0) + { + EnterCriticalSection (&g_private_lock); + impl = (DWORD) key->p; + if (impl == 0) + { + GPrivateDestructor *destructor; - destructor = malloc (sizeof (GPrivateDestructor)); - if G_UNLIKELY (destructor == NULL) - g_thread_abort (errno, "malloc"); - destructor->index = key->index; - destructor->notify = notify; + impl = TlsAlloc (); - do - destructor->next = g_private_destructors; - while (InterlockedCompareExchangePointer (&g_private_destructors, destructor->next, destructor) != destructor->next); + if (impl == TLS_OUT_OF_INDEXES) + g_thread_abort (0, "TlsAlloc"); - key->ready = TRUE; + if (key->notify != NULL) + { + destructor = malloc (sizeof (GPrivateDestructor)); + if G_UNLIKELY (destructor == NULL) + g_thread_abort (errno, "malloc"); + destructor->index = impl; + destructor->notify = key->notify; + destructor->next = g_private_destructors; + + /* We need to do an atomic store due to the unlocked + * access to the destructor list from the thread exit + * function. + * + * It can double as a sanity check... + */ + if (InterlockedCompareExchangePointer (&g_private_destructors, destructor, + destructor->next) != destructor->next) + g_thread_abort (0, "g_private_get_impl(1)"); + } + + /* Ditto, due to the unlocked access on the fast path */ + if (InterlockedCompareExchangePointer (&key->p, impl, NULL) != NULL) + g_thread_abort (0, "g_private_get_impl(2)"); + } + LeaveCriticalSection (&g_private_lock); + } + + return impl; } gpointer g_private_get (GPrivate *key) { - if (!key->ready) - return key->single_value; - - return TlsGetValue (key->index); + return TlsGetValue (g_private_get_impl (key)); } void g_private_set (GPrivate *key, gpointer value) { - if (!key->ready) - { - key->single_value = value; - return; - } + TlsSetValue (g_private_get_impl (key), value); +} - TlsSetValue (key->index, value); +void +g_private_replace (GPrivate *key, + gpointer value) +{ + DWORD impl = g_private_get_impl (key); + gpointer old; + + old = TlsGetValue (impl); + if (old && key->notify) + key->notify (old); + TlsSetValue (impl, value); } /* {{{1 GThread */ -#include "glib.h" -#include "gthreadprivate.h" - #define win32_check_for_error(what) G_STMT_START{ \ if (!(what)) \ g_error ("file %s: line %d (%s): error %s during %s", \ @@ -302,102 +417,37 @@ g_private_set (GPrivate *key, #define G_MUTEX_SIZE (sizeof (gpointer)) -static DWORD g_thread_self_tls; -static DWORD g_private_tls; - typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *); -typedef struct _GThreadData GThreadData; -struct _GThreadData +typedef struct { - GThreadFunc func; - gpointer data; - HANDLE thread; - gboolean joinable; -}; + GRealThread thread; + + GThreadFunc proxy; + HANDLE handle; +} GThreadWin32; void -g_system_thread_self (gpointer thread) +g_system_thread_free (GRealThread *thread) { - GThreadData *self = TlsGetValue (g_thread_self_tls); + GThreadWin32 *wt = (GThreadWin32 *) thread; - if (!self) - { - /* This should only happen for the main thread! */ - HANDLE handle = GetCurrentThread (); - HANDLE process = GetCurrentProcess (); - self = g_new (GThreadData, 1); - win32_check_for_error (DuplicateHandle (process, handle, process, - &self->thread, 0, FALSE, - DUPLICATE_SAME_ACCESS)); - win32_check_for_error (TlsSetValue (g_thread_self_tls, self)); - self->func = NULL; - self->data = NULL; - self->joinable = FALSE; - } - - *(GThreadData **)thread = self; + win32_check_for_error (CloseHandle (wt->handle)); + g_slice_free (GThreadWin32, wt); } void g_system_thread_exit (void) { - GThreadData *self = TlsGetValue (g_thread_self_tls); - gboolean dtors_called; - - do - { - GPrivateDestructor *dtor; - - /* We go by the POSIX book on this one. - * - * If we call a destructor then there is a chance that some new - * TLS variables got set by code called in that destructor. - * - * Loop until nothing is left. - */ - dtors_called = FALSE; - - for (dtor = g_private_destructors; dtor; dtor = dtor->next) - { - gpointer value; - - value = TlsGetValue (dtor->index); - if (value != NULL && dtor->notify != NULL) - { - /* POSIX says to clear this before the call */ - TlsSetValue (dtor->index, NULL); - dtor->notify (value); - dtors_called = TRUE; - } - } - } - while (dtors_called); - - if (self) - { - if (!self->joinable) - { - win32_check_for_error (CloseHandle (self->thread)); - g_free (self); - } - win32_check_for_error (TlsSetValue (g_thread_self_tls, NULL)); - } - - if (g_thread_impl_vtable.CallThisOnThreadExit) - g_thread_impl_vtable.CallThisOnThreadExit (); - _endthreadex (0); } static guint __stdcall -g_thread_proxy (gpointer data) +g_thread_win32_proxy (gpointer data) { - GThreadData *self = (GThreadData*) data; + GThreadWin32 *self = data; - win32_check_for_error (TlsSetValue (g_thread_self_tls, self)); - - self->func (self->data); + self->proxy (self); g_system_thread_exit (); @@ -406,41 +456,30 @@ g_thread_proxy (gpointer data) return 0; } -void -g_system_thread_create (GThreadFunc func, - gpointer data, - gulong stack_size, - gboolean joinable, - gboolean bound, - GThreadPriority priority, - gpointer thread, - GError **error) +GRealThread * +g_system_thread_new (GThreadFunc func, + gulong stack_size, + GError **error) { + GThreadWin32 *thread; guint ignore; - GThreadData *retval; - - g_return_if_fail (func); - retval = g_new(GThreadData, 1); - retval->func = func; - retval->data = data; + thread = g_slice_new0 (GThreadWin32); + thread->proxy = func; - retval->joinable = joinable; + thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread, 0, &ignore); - retval->thread = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_proxy, - retval, 0, &ignore); - - if (retval->thread == NULL) + if (thread->handle == NULL) { gchar *win_error = g_win32_error_message (GetLastError ()); g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, "Error creating thread: %s", win_error); - g_free (retval); g_free (win_error); - return; + g_slice_free (GThreadWin32, thread); + return NULL; } - *(GThreadData **)thread = retval; + return (GRealThread *) thread; } void @@ -450,24 +489,17 @@ g_thread_yield (void) } void -g_system_thread_join (gpointer thread) +g_system_thread_wait (GRealThread *thread) { - GThreadData *target = *(GThreadData **)thread; - - g_return_if_fail (target->joinable); + GThreadWin32 *wt = (GThreadWin32 *) thread; - win32_check_for_error (WAIT_FAILED != - WaitForSingleObject (target->thread, INFINITE)); - - win32_check_for_error (CloseHandle (target->thread)); - g_free (target); + win32_check_for_error (WAIT_FAILED != WaitForSingleObject (wt->handle, INFINITE)); } -gboolean -g_system_thread_equal (gpointer thread1, - gpointer thread2) +void +g_system_thread_set_name (const gchar *name) { - return ((GSystemThread*)thread1)->dummy_pointer == ((GSystemThread*)thread2)->dummy_pointer; + /* FIXME: implement */ } /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */ @@ -479,8 +511,9 @@ static DWORD g_thread_xp_waiter_tls; typedef struct _GThreadXpWaiter GThreadXpWaiter; struct _GThreadXpWaiter { - HANDLE event; - volatile GThreadXpWaiter *next; + HANDLE event; + volatile GThreadXpWaiter *next; + volatile GThreadXpWaiter **my_owner; }; static GThreadXpWaiter * @@ -498,6 +531,7 @@ g_thread_xp_waiter_get (void) waiter->event = CreateEvent (0, FALSE, FALSE, NULL); if (waiter->event == NULL) g_thread_abort (GetLastError (), "CreateEvent"); + waiter->my_owner = NULL; TlsSetValue (g_thread_xp_waiter_tls, waiter); } @@ -523,7 +557,14 @@ g_thread_xp_CallThisOnThreadExit (void) /* {{{2 SRWLock emulation */ typedef struct { - CRITICAL_SECTION critical_section; + CRITICAL_SECTION writer_lock; + gboolean ever_shared; /* protected by writer_lock */ + gboolean writer_locked; /* protected by writer_lock */ + + /* below is only ever touched if ever_shared becomes true */ + CRITICAL_SECTION atomicity; + GThreadXpWaiter *queued_writer; /* protected by atomicity lock */ + gint num_readers; /* protected by atomicity lock */ } GThreadSRWLock; static void __stdcall @@ -539,7 +580,10 @@ g_thread_xp_DeleteSRWLock (gpointer mutex) if (lock) { - DeleteCriticalSection (&lock->critical_section); + if (lock->ever_shared) + DeleteCriticalSection (&lock->atomicity); + + DeleteCriticalSection (&lock->writer_lock); free (lock); } } @@ -560,13 +604,20 @@ g_thread_xp_get_srwlock (GThreadSRWLock * volatile *lock) { EnterCriticalSection (&g_thread_xp_lock); - result = malloc (sizeof (GThreadSRWLock)); - + /* Check again */ + result = *lock; if (result == NULL) - g_thread_abort (errno, "malloc"); + { + result = malloc (sizeof (GThreadSRWLock)); - InitializeCriticalSection (&result->critical_section); - *lock = result; + if (result == NULL) + g_thread_abort (errno, "malloc"); + + InitializeCriticalSection (&result->writer_lock); + result->writer_locked = FALSE; + result->ever_shared = FALSE; + *lock = result; + } LeaveCriticalSection (&g_thread_xp_lock); } @@ -579,7 +630,28 @@ g_thread_xp_AcquireSRWLockExclusive (gpointer mutex) { GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex); - EnterCriticalSection (&lock->critical_section); + EnterCriticalSection (&lock->writer_lock); + + /* CRITICAL_SECTION is reentrant, but SRWLock is not. + * Detect the deadlock that would occur on later Windows version. + */ + g_assert (!lock->writer_locked); + lock->writer_locked = TRUE; + + if (lock->ever_shared) + { + GThreadXpWaiter *waiter = NULL; + + EnterCriticalSection (&lock->atomicity); + if (lock->num_readers > 0) + lock->queued_writer = waiter = g_thread_xp_waiter_get (); + LeaveCriticalSection (&lock->atomicity); + + if (waiter != NULL) + WaitForSingleObject (waiter->event, INFINITE); + + lock->queued_writer = NULL; + } } static BOOLEAN __stdcall @@ -587,7 +659,36 @@ g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex) { GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex); - return TryEnterCriticalSection (&lock->critical_section); + if (!TryEnterCriticalSection (&lock->writer_lock)) + return FALSE; + + /* CRITICAL_SECTION is reentrant, but SRWLock is not. + * Ensure that this properly returns FALSE (as SRWLock would). + */ + if G_UNLIKELY (lock->writer_locked) + { + LeaveCriticalSection (&lock->writer_lock); + return FALSE; + } + + lock->writer_locked = TRUE; + + if (lock->ever_shared) + { + gboolean available; + + EnterCriticalSection (&lock->atomicity); + available = lock->num_readers == 0; + LeaveCriticalSection (&lock->atomicity); + + if (!available) + { + LeaveCriticalSection (&lock->writer_lock); + return FALSE; + } + } + + return TRUE; } static void __stdcall @@ -595,11 +696,82 @@ g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex) { GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex; + lock->writer_locked = FALSE; + /* We need this until we fix some weird parts of GLib that try to * unlock freshly-allocated mutexes. */ if (lock != NULL) - LeaveCriticalSection (&lock->critical_section); + LeaveCriticalSection (&lock->writer_lock); +} + +static void +g_thread_xp_srwlock_become_reader (GThreadSRWLock *lock) +{ + if G_UNLIKELY (!lock->ever_shared) + { + InitializeCriticalSection (&lock->atomicity); + lock->queued_writer = NULL; + lock->num_readers = 0; + + lock->ever_shared = TRUE; + } + + EnterCriticalSection (&lock->atomicity); + lock->num_readers++; + LeaveCriticalSection (&lock->atomicity); +} + +static void __stdcall +g_thread_xp_AcquireSRWLockShared (gpointer mutex) +{ + GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex); + + EnterCriticalSection (&lock->writer_lock); + + /* See g_thread_xp_AcquireSRWLockExclusive */ + g_assert (!lock->writer_locked); + + g_thread_xp_srwlock_become_reader (lock); + + LeaveCriticalSection (&lock->writer_lock); +} + +static BOOLEAN __stdcall +g_thread_xp_TryAcquireSRWLockShared (gpointer mutex) +{ + GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex); + + if (!TryEnterCriticalSection (&lock->writer_lock)) + return FALSE; + + /* See g_thread_xp_AcquireSRWLockExclusive */ + if G_UNLIKELY (lock->writer_locked) + { + LeaveCriticalSection (&lock->writer_lock); + return FALSE; + } + + g_thread_xp_srwlock_become_reader (lock); + + LeaveCriticalSection (&lock->writer_lock); + + return TRUE; +} + +static void __stdcall +g_thread_xp_ReleaseSRWLockShared (gpointer mutex) +{ + GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex); + + EnterCriticalSection (&lock->atomicity); + + lock->num_readers--; + + if (lock->num_readers == 0 && lock->queued_writer) + SetEvent (lock->queued_writer->event); + + LeaveCriticalSection (&lock->atomicity); } /* {{{2 CONDITION_VARIABLE emulation */ @@ -669,6 +841,7 @@ g_thread_xp_SleepConditionVariableSRW (gpointer cond, waiter->next = NULL; EnterCriticalSection (&g_thread_xp_lock); + waiter->my_owner = cv->last_ptr; *cv->last_ptr = waiter; cv->last_ptr = &waiter->next; LeaveCriticalSection (&g_thread_xp_lock); @@ -678,9 +851,23 @@ g_thread_xp_SleepConditionVariableSRW (gpointer cond, if (status != WAIT_TIMEOUT && status != WAIT_OBJECT_0) g_thread_abort (GetLastError (), "WaitForSingleObject"); - g_mutex_lock (mutex); + if (status == WAIT_TIMEOUT) + { + EnterCriticalSection (&g_thread_xp_lock); + if (waiter->my_owner) + { + if (waiter->next) + waiter->next->my_owner = waiter->my_owner; + else + cv->last_ptr = waiter->my_owner; + *waiter->my_owner = waiter->next; + waiter->my_owner = NULL; + } + LeaveCriticalSection (&g_thread_xp_lock); + } + return status == WAIT_OBJECT_0; } @@ -691,17 +878,22 @@ g_thread_xp_WakeConditionVariable (gpointer cond) volatile GThreadXpWaiter *waiter; EnterCriticalSection (&g_thread_xp_lock); + waiter = cv->first; if (waiter != NULL) { + waiter->my_owner = NULL; cv->first = waiter->next; - if (cv->first == NULL) + if (cv->first != NULL) + cv->first->my_owner = &cv->first; + else cv->last_ptr = &cv->first; } - LeaveCriticalSection (&g_thread_xp_lock); if (waiter != NULL) SetEvent (waiter->event); + + LeaveCriticalSection (&g_thread_xp_lock); } static void __stdcall @@ -711,10 +903,10 @@ g_thread_xp_WakeAllConditionVariable (gpointer cond) volatile GThreadXpWaiter *waiter; EnterCriticalSection (&g_thread_xp_lock); + waiter = cv->first; cv->first = NULL; cv->last_ptr = &cv->first; - LeaveCriticalSection (&g_thread_xp_lock); while (waiter != NULL) { @@ -722,8 +914,11 @@ g_thread_xp_WakeAllConditionVariable (gpointer cond) next = waiter->next; SetEvent (waiter->event); + waiter->my_owner = NULL; waiter = next; } + + LeaveCriticalSection (&g_thread_xp_lock); } /* {{{2 XP Setup */ @@ -737,6 +932,9 @@ g_thread_xp_init (void) g_thread_xp_AcquireSRWLockExclusive, g_thread_xp_TryAcquireSRWLockExclusive, g_thread_xp_ReleaseSRWLockExclusive, + g_thread_xp_AcquireSRWLockShared, + g_thread_xp_TryAcquireSRWLockShared, + g_thread_xp_ReleaseSRWLockShared, g_thread_xp_InitializeConditionVariable, g_thread_xp_DeleteConditionVariable, g_thread_xp_SleepConditionVariableSRW, @@ -752,48 +950,6 @@ g_thread_xp_init (void) /* {{{1 Epilogue */ -GThreadFunctions g_thread_functions_for_glib_use = -{ - g_mutex_new, /* mutex */ - g_mutex_lock, - g_mutex_trylock, - g_mutex_unlock, - g_mutex_free, - g_cond_new, /* condition */ - g_cond_signal, - g_cond_broadcast, - g_cond_wait, - g_cond_timed_wait, - g_cond_free, - g_private_new, /* private thread data */ - g_private_get, - g_private_set, - NULL, /* thread */ - g_thread_yield, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -void -_g_thread_impl_init (void) -{ - static gboolean beenhere = FALSE; - - if (beenhere) - return; - - beenhere = TRUE; - - printf ("thread init\n"); - win32_check_for_error (TLS_OUT_OF_INDEXES != - (g_thread_self_tls = TlsAlloc ())); - win32_check_for_error (TLS_OUT_OF_INDEXES != - (g_private_tls = TlsAlloc ())); -} - static gboolean g_thread_lookup_native_funcs (void) { @@ -810,6 +966,9 @@ g_thread_lookup_native_funcs (void) GET_FUNC(AcquireSRWLockExclusive); GET_FUNC(TryAcquireSRWLockExclusive); GET_FUNC(ReleaseSRWLockExclusive); + GET_FUNC(AcquireSRWLockShared); + GET_FUNC(TryAcquireSRWLockShared); + GET_FUNC(ReleaseSRWLockShared); GET_FUNC(InitializeConditionVariable); GET_FUNC(SleepConditionVariableSRW); @@ -822,17 +981,51 @@ g_thread_lookup_native_funcs (void) return TRUE; } -G_GNUC_INTERNAL void -g_thread_DllMain (void) +void +g_thread_win32_init (void) { - if (g_thread_lookup_native_funcs ()) - fprintf (stderr, "(debug) GThread using native mode\n"); - else + if (!g_thread_lookup_native_funcs ()) + g_thread_xp_init (); + + InitializeCriticalSection (&g_private_lock); +} + +void +g_thread_win32_thread_detach (void) +{ + gboolean dtors_called; + + do { - fprintf (stderr, "(debug) GThread using Windows XP mode\n"); - g_thread_xp_init (); + GPrivateDestructor *dtor; + + /* We go by the POSIX book on this one. + * + * If we call a destructor then there is a chance that some new + * TLS variables got set by code called in that destructor. + * + * Loop until nothing is left. + */ + dtors_called = FALSE; + + for (dtor = g_private_destructors; dtor; dtor = dtor->next) + { + gpointer value; + + value = TlsGetValue (dtor->index); + if (value != NULL && dtor->notify != NULL) + { + /* POSIX says to clear this before the call */ + TlsSetValue (dtor->index, NULL); + dtor->notify (value); + dtors_called = TRUE; + } + } } + while (dtors_called); + + if (g_thread_impl_vtable.CallThisOnThreadExit) + g_thread_impl_vtable.CallThisOnThreadExit (); } /* vim:set foldmethod=marker: */ -