unicode: Simplify width table generation
[glib.git] / glib / gthread-win32.c
blob275ecc63c552abbf9d8f135e9343651e2a7ba460
1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * gthread.c: solaris thread system implementation
5 * Copyright 1998-2001 Sebastian Wilhelmi; University of Karlsruhe
6 * Copyright 2001 Hans Breuer
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
24 * file for a list of people on the GLib Team. See the ChangeLog
25 * files for a list of changes. These files are distributed with
26 * GLib at ftp://ftp.gtk.org/pub/gtk/.
29 /* The GMutex and GCond implementations in this file are some of the
30 * lowest-level code in GLib. All other parts of GLib (messages,
31 * memory, slices, etc) assume that they can freely use these facilities
32 * without risking recursion.
34 * As such, these functions are NOT permitted to call any other part of
35 * GLib.
37 * The thread manipulation functions (create, exit, join, etc.) have
38 * more freedom -- they can do as they please.
41 #include "config.h"
43 #include "glib.h"
44 #include "glib-init.h"
45 #include "gthread.h"
46 #include "gthreadprivate.h"
47 #include "gslice.h"
49 #include <windows.h>
51 #include <process.h>
52 #include <stdlib.h>
53 #include <stdio.h>
55 static void
56 g_thread_abort (gint status,
57 const gchar *function)
59 fprintf (stderr, "GLib (gthread-win32.c): Unexpected error from C library during '%s': %s. Aborting.\n",
60 strerror (status), function);
61 abort ();
64 /* Starting with Vista and Windows 2008, we have access to the
65 * CONDITION_VARIABLE and SRWLock primatives on Windows, which are
66 * pretty reasonable approximations of the primatives specified in
67 * POSIX 2001 (pthread_cond_t and pthread_mutex_t respectively).
69 * Both of these types are structs containing a single pointer. That
70 * pointer is used as an atomic bitfield to support user-space mutexes
71 * that only get the kernel involved in cases of contention (similar
72 * to how futex()-based mutexes work on Linux). The biggest advantage
73 * of these new types is that they can be statically initialised to
74 * zero. That means that they are completely ABI compatible with our
75 * GMutex and GCond APIs.
77 * Unfortunately, Windows XP lacks these facilities and GLib still
78 * needs to support Windows XP. Our approach here is as follows:
80 * - avoid depending on structure declarations at compile-time by
81 * declaring our own GMutex and GCond strutures to be
82 * ABI-compatible with SRWLock and CONDITION_VARIABLE and using
83 * those instead
85 * - avoid a hard dependency on the symbols used to manipulate these
86 * structures by doing a dynamic lookup of those symbols at
87 * runtime
89 * - if the symbols are not available, emulate them using other
90 * primatives
92 * Using this approach also allows us to easily build a GLib that lacks
93 * support for Windows XP or to remove this code entirely when XP is no
94 * longer supported (end of line is currently April 8, 2014).
96 typedef struct
98 void (__stdcall * CallThisOnThreadExit) (void); /* fake */
100 void (__stdcall * InitializeSRWLock) (gpointer lock);
101 void (__stdcall * DeleteSRWLock) (gpointer lock); /* fake */
102 void (__stdcall * AcquireSRWLockExclusive) (gpointer lock);
103 BOOLEAN (__stdcall * TryAcquireSRWLockExclusive) (gpointer lock);
104 void (__stdcall * ReleaseSRWLockExclusive) (gpointer lock);
105 void (__stdcall * AcquireSRWLockShared) (gpointer lock);
106 BOOLEAN (__stdcall * TryAcquireSRWLockShared) (gpointer lock);
107 void (__stdcall * ReleaseSRWLockShared) (gpointer lock);
109 void (__stdcall * InitializeConditionVariable) (gpointer cond);
110 void (__stdcall * DeleteConditionVariable) (gpointer cond); /* fake */
111 BOOL (__stdcall * SleepConditionVariableSRW) (gpointer cond,
112 gpointer lock,
113 DWORD timeout,
114 ULONG flags);
115 void (__stdcall * WakeAllConditionVariable) (gpointer cond);
116 void (__stdcall * WakeConditionVariable) (gpointer cond);
117 } GThreadImplVtable;
119 static GThreadImplVtable g_thread_impl_vtable;
121 /* {{{1 GMutex */
122 void
123 g_mutex_init (GMutex *mutex)
125 g_thread_impl_vtable.InitializeSRWLock (mutex);
128 void
129 g_mutex_clear (GMutex *mutex)
131 if (g_thread_impl_vtable.DeleteSRWLock != NULL)
132 g_thread_impl_vtable.DeleteSRWLock (mutex);
135 void
136 g_mutex_lock (GMutex *mutex)
138 g_thread_impl_vtable.AcquireSRWLockExclusive (mutex);
141 gboolean
142 g_mutex_trylock (GMutex *mutex)
144 return g_thread_impl_vtable.TryAcquireSRWLockExclusive (mutex);
147 void
148 g_mutex_unlock (GMutex *mutex)
150 g_thread_impl_vtable.ReleaseSRWLockExclusive (mutex);
153 /* {{{1 GRecMutex */
155 static CRITICAL_SECTION *
156 g_rec_mutex_impl_new (void)
158 CRITICAL_SECTION *cs;
160 cs = g_slice_new (CRITICAL_SECTION);
161 InitializeCriticalSection (cs);
163 return cs;
166 static void
167 g_rec_mutex_impl_free (CRITICAL_SECTION *cs)
169 DeleteCriticalSection (cs);
170 g_slice_free (CRITICAL_SECTION, cs);
173 static CRITICAL_SECTION *
174 g_rec_mutex_get_impl (GRecMutex *mutex)
176 CRITICAL_SECTION *impl = mutex->p;
178 if G_UNLIKELY (mutex->p == NULL)
180 impl = g_rec_mutex_impl_new ();
181 if (InterlockedCompareExchangePointer (&mutex->p, impl, NULL) != NULL)
182 g_rec_mutex_impl_free (impl);
183 impl = mutex->p;
186 return impl;
189 void
190 g_rec_mutex_init (GRecMutex *mutex)
192 mutex->p = g_rec_mutex_impl_new ();
195 void
196 g_rec_mutex_clear (GRecMutex *mutex)
198 g_rec_mutex_impl_free (mutex->p);
201 void
202 g_rec_mutex_lock (GRecMutex *mutex)
204 EnterCriticalSection (g_rec_mutex_get_impl (mutex));
207 void
208 g_rec_mutex_unlock (GRecMutex *mutex)
210 LeaveCriticalSection (mutex->p);
213 gboolean
214 g_rec_mutex_trylock (GRecMutex *mutex)
216 return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex));
219 /* {{{1 GRWLock */
221 void
222 g_rw_lock_init (GRWLock *lock)
224 g_thread_impl_vtable.InitializeSRWLock (lock);
227 void
228 g_rw_lock_clear (GRWLock *lock)
230 if (g_thread_impl_vtable.DeleteSRWLock != NULL)
231 g_thread_impl_vtable.DeleteSRWLock (lock);
234 void
235 g_rw_lock_writer_lock (GRWLock *lock)
237 g_thread_impl_vtable.AcquireSRWLockExclusive (lock);
240 gboolean
241 g_rw_lock_writer_trylock (GRWLock *lock)
243 return g_thread_impl_vtable.TryAcquireSRWLockExclusive (lock);
246 void
247 g_rw_lock_writer_unlock (GRWLock *lock)
249 g_thread_impl_vtable.ReleaseSRWLockExclusive (lock);
252 void
253 g_rw_lock_reader_lock (GRWLock *lock)
255 g_thread_impl_vtable.AcquireSRWLockShared (lock);
258 gboolean
259 g_rw_lock_reader_trylock (GRWLock *lock)
261 return g_thread_impl_vtable.TryAcquireSRWLockShared (lock);
264 void
265 g_rw_lock_reader_unlock (GRWLock *lock)
267 g_thread_impl_vtable.ReleaseSRWLockShared (lock);
270 /* {{{1 GCond */
271 void
272 g_cond_init (GCond *cond)
274 g_thread_impl_vtable.InitializeConditionVariable (cond);
277 void
278 g_cond_clear (GCond *cond)
280 if (g_thread_impl_vtable.DeleteConditionVariable)
281 g_thread_impl_vtable.DeleteConditionVariable (cond);
284 void
285 g_cond_signal (GCond *cond)
287 g_thread_impl_vtable.WakeConditionVariable (cond);
290 void
291 g_cond_broadcast (GCond *cond)
293 g_thread_impl_vtable.WakeAllConditionVariable (cond);
296 void
297 g_cond_wait (GCond *cond,
298 GMutex *entered_mutex)
300 g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, INFINITE, 0);
303 gboolean
304 g_cond_wait_until (GCond *cond,
305 GMutex *entered_mutex,
306 gint64 end_time)
308 gint64 span;
310 span = end_time - g_get_monotonic_time ();
312 if G_UNLIKELY (span < 0)
313 span = 0;
315 if G_UNLIKELY (span > G_GINT64_CONSTANT (1000) * G_MAXINT32)
316 span = INFINITE;
318 return g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, span / 1000, 0);
321 /* {{{1 GPrivate */
323 typedef struct _GPrivateDestructor GPrivateDestructor;
325 struct _GPrivateDestructor
327 DWORD index;
328 GDestroyNotify notify;
329 GPrivateDestructor *next;
332 static GPrivateDestructor * volatile g_private_destructors;
333 static CRITICAL_SECTION g_private_lock;
335 static DWORD
336 g_private_get_impl (GPrivate *key)
338 DWORD impl = (DWORD) key->p;
340 if G_UNLIKELY (impl == 0)
342 EnterCriticalSection (&g_private_lock);
343 impl = (DWORD) key->p;
344 if (impl == 0)
346 GPrivateDestructor *destructor;
348 impl = TlsAlloc ();
350 if (impl == TLS_OUT_OF_INDEXES)
351 g_thread_abort (0, "TlsAlloc");
353 if (key->notify != NULL)
355 destructor = malloc (sizeof (GPrivateDestructor));
356 if G_UNLIKELY (destructor == NULL)
357 g_thread_abort (errno, "malloc");
358 destructor->index = impl;
359 destructor->notify = key->notify;
360 destructor->next = g_private_destructors;
362 /* We need to do an atomic store due to the unlocked
363 * access to the destructor list from the thread exit
364 * function.
366 * It can double as a sanity check...
368 if (InterlockedCompareExchangePointer (&g_private_destructors, destructor,
369 destructor->next) != destructor->next)
370 g_thread_abort (0, "g_private_get_impl(1)");
373 /* Ditto, due to the unlocked access on the fast path */
374 if (InterlockedCompareExchangePointer (&key->p, impl, NULL) != NULL)
375 g_thread_abort (0, "g_private_get_impl(2)");
377 LeaveCriticalSection (&g_private_lock);
380 return impl;
383 gpointer
384 g_private_get (GPrivate *key)
386 return TlsGetValue (g_private_get_impl (key));
389 void
390 g_private_set (GPrivate *key,
391 gpointer value)
393 TlsSetValue (g_private_get_impl (key), value);
396 void
397 g_private_replace (GPrivate *key,
398 gpointer value)
400 DWORD impl = g_private_get_impl (key);
401 gpointer old;
403 old = TlsGetValue (impl);
404 if (old && key->notify)
405 key->notify (old);
406 TlsSetValue (impl, value);
409 /* {{{1 GThread */
411 #define win32_check_for_error(what) G_STMT_START{ \
412 if (!(what)) \
413 g_error ("file %s: line %d (%s): error %s during %s", \
414 __FILE__, __LINE__, G_STRFUNC, \
415 g_win32_error_message (GetLastError ()), #what); \
416 }G_STMT_END
418 #define G_MUTEX_SIZE (sizeof (gpointer))
420 typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *);
422 typedef struct
424 GRealThread thread;
426 GThreadFunc proxy;
427 HANDLE handle;
428 } GThreadWin32;
430 void
431 g_system_thread_free (GRealThread *thread)
433 GThreadWin32 *wt = (GThreadWin32 *) thread;
435 win32_check_for_error (CloseHandle (wt->handle));
436 g_slice_free (GThreadWin32, wt);
439 void
440 g_system_thread_exit (void)
442 _endthreadex (0);
445 static guint __stdcall
446 g_thread_win32_proxy (gpointer data)
448 GThreadWin32 *self = data;
450 self->proxy (self);
452 g_system_thread_exit ();
454 g_assert_not_reached ();
456 return 0;
459 GRealThread *
460 g_system_thread_new (GThreadFunc func,
461 gulong stack_size,
462 GError **error)
464 GThreadWin32 *thread;
465 guint ignore;
467 thread = g_slice_new0 (GThreadWin32);
468 thread->proxy = func;
470 thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread, 0, &ignore);
472 if (thread->handle == NULL)
474 gchar *win_error = g_win32_error_message (GetLastError ());
475 g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
476 "Error creating thread: %s", win_error);
477 g_free (win_error);
478 g_slice_free (GThreadWin32, thread);
479 return NULL;
482 return (GRealThread *) thread;
485 void
486 g_thread_yield (void)
488 Sleep(0);
491 void
492 g_system_thread_wait (GRealThread *thread)
494 GThreadWin32 *wt = (GThreadWin32 *) thread;
496 win32_check_for_error (WAIT_FAILED != WaitForSingleObject (wt->handle, INFINITE));
499 void
500 g_system_thread_set_name (const gchar *name)
502 /* FIXME: implement */
505 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
507 static CRITICAL_SECTION g_thread_xp_lock;
508 static DWORD g_thread_xp_waiter_tls;
510 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
511 typedef struct _GThreadXpWaiter GThreadXpWaiter;
512 struct _GThreadXpWaiter
514 HANDLE event;
515 volatile GThreadXpWaiter *next;
516 volatile GThreadXpWaiter **my_owner;
519 static GThreadXpWaiter *
520 g_thread_xp_waiter_get (void)
522 GThreadXpWaiter *waiter;
524 waiter = TlsGetValue (g_thread_xp_waiter_tls);
526 if G_UNLIKELY (waiter == NULL)
528 waiter = malloc (sizeof (GThreadXpWaiter));
529 if (waiter == NULL)
530 g_thread_abort (GetLastError (), "malloc");
531 waiter->event = CreateEvent (0, FALSE, FALSE, NULL);
532 if (waiter->event == NULL)
533 g_thread_abort (GetLastError (), "CreateEvent");
534 waiter->my_owner = NULL;
536 TlsSetValue (g_thread_xp_waiter_tls, waiter);
539 return waiter;
542 static void __stdcall
543 g_thread_xp_CallThisOnThreadExit (void)
545 GThreadXpWaiter *waiter;
547 waiter = TlsGetValue (g_thread_xp_waiter_tls);
549 if (waiter != NULL)
551 TlsSetValue (g_thread_xp_waiter_tls, NULL);
552 CloseHandle (waiter->event);
553 free (waiter);
557 /* {{{2 SRWLock emulation */
558 typedef struct
560 CRITICAL_SECTION writer_lock;
561 gboolean ever_shared; /* protected by writer_lock */
562 gboolean writer_locked; /* protected by writer_lock */
564 /* below is only ever touched if ever_shared becomes true */
565 CRITICAL_SECTION atomicity;
566 GThreadXpWaiter *queued_writer; /* protected by atomicity lock */
567 gint num_readers; /* protected by atomicity lock */
568 } GThreadSRWLock;
570 static void __stdcall
571 g_thread_xp_InitializeSRWLock (gpointer mutex)
573 *(GThreadSRWLock * volatile *) mutex = NULL;
576 static void __stdcall
577 g_thread_xp_DeleteSRWLock (gpointer mutex)
579 GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
581 if (lock)
583 if (lock->ever_shared)
584 DeleteCriticalSection (&lock->atomicity);
586 DeleteCriticalSection (&lock->writer_lock);
587 free (lock);
591 static GThreadSRWLock * __stdcall
592 g_thread_xp_get_srwlock (GThreadSRWLock * volatile *lock)
594 GThreadSRWLock *result;
596 /* It looks like we're missing some barriers here, but this code only
597 * ever runs on Windows XP, which in turn only ever runs on hardware
598 * with a relatively rigid memory model. The 'volatile' will take
599 * care of the compiler.
601 result = *lock;
603 if G_UNLIKELY (result == NULL)
605 EnterCriticalSection (&g_thread_xp_lock);
607 /* Check again */
608 result = *lock;
609 if (result == NULL)
611 result = malloc (sizeof (GThreadSRWLock));
613 if (result == NULL)
614 g_thread_abort (errno, "malloc");
616 InitializeCriticalSection (&result->writer_lock);
617 result->writer_locked = FALSE;
618 result->ever_shared = FALSE;
619 *lock = result;
622 LeaveCriticalSection (&g_thread_xp_lock);
625 return result;
628 static void __stdcall
629 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex)
631 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
633 EnterCriticalSection (&lock->writer_lock);
635 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
636 * Detect the deadlock that would occur on later Windows version.
638 g_assert (!lock->writer_locked);
639 lock->writer_locked = TRUE;
641 if (lock->ever_shared)
643 GThreadXpWaiter *waiter = NULL;
645 EnterCriticalSection (&lock->atomicity);
646 if (lock->num_readers > 0)
647 lock->queued_writer = waiter = g_thread_xp_waiter_get ();
648 LeaveCriticalSection (&lock->atomicity);
650 if (waiter != NULL)
651 WaitForSingleObject (waiter->event, INFINITE);
653 lock->queued_writer = NULL;
657 static BOOLEAN __stdcall
658 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex)
660 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
662 if (!TryEnterCriticalSection (&lock->writer_lock))
663 return FALSE;
665 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
666 * Ensure that this properly returns FALSE (as SRWLock would).
668 if G_UNLIKELY (lock->writer_locked)
670 LeaveCriticalSection (&lock->writer_lock);
671 return FALSE;
674 lock->writer_locked = TRUE;
676 if (lock->ever_shared)
678 gboolean available;
680 EnterCriticalSection (&lock->atomicity);
681 available = lock->num_readers == 0;
682 LeaveCriticalSection (&lock->atomicity);
684 if (!available)
686 LeaveCriticalSection (&lock->writer_lock);
687 return FALSE;
691 return TRUE;
694 static void __stdcall
695 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex)
697 GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
699 lock->writer_locked = FALSE;
701 /* We need this until we fix some weird parts of GLib that try to
702 * unlock freshly-allocated mutexes.
704 if (lock != NULL)
705 LeaveCriticalSection (&lock->writer_lock);
708 static void
709 g_thread_xp_srwlock_become_reader (GThreadSRWLock *lock)
711 if G_UNLIKELY (!lock->ever_shared)
713 InitializeCriticalSection (&lock->atomicity);
714 lock->queued_writer = NULL;
715 lock->num_readers = 0;
717 lock->ever_shared = TRUE;
720 EnterCriticalSection (&lock->atomicity);
721 lock->num_readers++;
722 LeaveCriticalSection (&lock->atomicity);
725 static void __stdcall
726 g_thread_xp_AcquireSRWLockShared (gpointer mutex)
728 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
730 EnterCriticalSection (&lock->writer_lock);
732 /* See g_thread_xp_AcquireSRWLockExclusive */
733 g_assert (!lock->writer_locked);
735 g_thread_xp_srwlock_become_reader (lock);
737 LeaveCriticalSection (&lock->writer_lock);
740 static BOOLEAN __stdcall
741 g_thread_xp_TryAcquireSRWLockShared (gpointer mutex)
743 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
745 if (!TryEnterCriticalSection (&lock->writer_lock))
746 return FALSE;
748 /* See g_thread_xp_AcquireSRWLockExclusive */
749 if G_UNLIKELY (lock->writer_locked)
751 LeaveCriticalSection (&lock->writer_lock);
752 return FALSE;
755 g_thread_xp_srwlock_become_reader (lock);
757 LeaveCriticalSection (&lock->writer_lock);
759 return TRUE;
762 static void __stdcall
763 g_thread_xp_ReleaseSRWLockShared (gpointer mutex)
765 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
767 EnterCriticalSection (&lock->atomicity);
769 lock->num_readers--;
771 if (lock->num_readers == 0 && lock->queued_writer)
772 SetEvent (lock->queued_writer->event);
774 LeaveCriticalSection (&lock->atomicity);
777 /* {{{2 CONDITION_VARIABLE emulation */
778 typedef struct
780 volatile GThreadXpWaiter *first;
781 volatile GThreadXpWaiter **last_ptr;
782 } GThreadXpCONDITION_VARIABLE;
784 static void __stdcall
785 g_thread_xp_InitializeConditionVariable (gpointer cond)
787 *(GThreadXpCONDITION_VARIABLE * volatile *) cond = NULL;
790 static void __stdcall
791 g_thread_xp_DeleteConditionVariable (gpointer cond)
793 GThreadXpCONDITION_VARIABLE *cv = *(GThreadXpCONDITION_VARIABLE * volatile *) cond;
795 if (cv)
796 free (cv);
799 static GThreadXpCONDITION_VARIABLE * __stdcall
800 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE * volatile *cond)
802 GThreadXpCONDITION_VARIABLE *result;
804 /* It looks like we're missing some barriers here, but this code only
805 * ever runs on Windows XP, which in turn only ever runs on hardware
806 * with a relatively rigid memory model. The 'volatile' will take
807 * care of the compiler.
809 result = *cond;
811 if G_UNLIKELY (result == NULL)
813 result = malloc (sizeof (GThreadXpCONDITION_VARIABLE));
815 if (result == NULL)
816 g_thread_abort (errno, "malloc");
818 result->first = NULL;
819 result->last_ptr = &result->first;
821 if (InterlockedCompareExchangePointer (cond, result, NULL) != NULL)
823 free (result);
824 result = *cond;
828 return result;
831 static BOOL __stdcall
832 g_thread_xp_SleepConditionVariableSRW (gpointer cond,
833 gpointer mutex,
834 DWORD timeout,
835 ULONG flags)
837 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
838 GThreadXpWaiter *waiter = g_thread_xp_waiter_get ();
839 DWORD status;
841 waiter->next = NULL;
843 EnterCriticalSection (&g_thread_xp_lock);
844 waiter->my_owner = cv->last_ptr;
845 *cv->last_ptr = waiter;
846 cv->last_ptr = &waiter->next;
847 LeaveCriticalSection (&g_thread_xp_lock);
849 g_mutex_unlock (mutex);
850 status = WaitForSingleObject (waiter->event, timeout);
852 if (status != WAIT_TIMEOUT && status != WAIT_OBJECT_0)
853 g_thread_abort (GetLastError (), "WaitForSingleObject");
854 g_mutex_lock (mutex);
856 if (status == WAIT_TIMEOUT)
858 EnterCriticalSection (&g_thread_xp_lock);
859 if (waiter->my_owner)
861 if (waiter->next)
862 waiter->next->my_owner = waiter->my_owner;
863 else
864 cv->last_ptr = waiter->my_owner;
865 *waiter->my_owner = waiter->next;
866 waiter->my_owner = NULL;
868 LeaveCriticalSection (&g_thread_xp_lock);
871 return status == WAIT_OBJECT_0;
874 static void __stdcall
875 g_thread_xp_WakeConditionVariable (gpointer cond)
877 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
878 volatile GThreadXpWaiter *waiter;
880 EnterCriticalSection (&g_thread_xp_lock);
882 waiter = cv->first;
883 if (waiter != NULL)
885 waiter->my_owner = NULL;
886 cv->first = waiter->next;
887 if (cv->first != NULL)
888 cv->first->my_owner = &cv->first;
889 else
890 cv->last_ptr = &cv->first;
893 if (waiter != NULL)
894 SetEvent (waiter->event);
896 LeaveCriticalSection (&g_thread_xp_lock);
899 static void __stdcall
900 g_thread_xp_WakeAllConditionVariable (gpointer cond)
902 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
903 volatile GThreadXpWaiter *waiter;
905 EnterCriticalSection (&g_thread_xp_lock);
907 waiter = cv->first;
908 cv->first = NULL;
909 cv->last_ptr = &cv->first;
911 while (waiter != NULL)
913 volatile GThreadXpWaiter *next;
915 next = waiter->next;
916 SetEvent (waiter->event);
917 waiter->my_owner = NULL;
918 waiter = next;
921 LeaveCriticalSection (&g_thread_xp_lock);
924 /* {{{2 XP Setup */
925 static void
926 g_thread_xp_init (void)
928 static const GThreadImplVtable g_thread_xp_impl_vtable = {
929 g_thread_xp_CallThisOnThreadExit,
930 g_thread_xp_InitializeSRWLock,
931 g_thread_xp_DeleteSRWLock,
932 g_thread_xp_AcquireSRWLockExclusive,
933 g_thread_xp_TryAcquireSRWLockExclusive,
934 g_thread_xp_ReleaseSRWLockExclusive,
935 g_thread_xp_AcquireSRWLockShared,
936 g_thread_xp_TryAcquireSRWLockShared,
937 g_thread_xp_ReleaseSRWLockShared,
938 g_thread_xp_InitializeConditionVariable,
939 g_thread_xp_DeleteConditionVariable,
940 g_thread_xp_SleepConditionVariableSRW,
941 g_thread_xp_WakeAllConditionVariable,
942 g_thread_xp_WakeConditionVariable
945 InitializeCriticalSection (&g_thread_xp_lock);
946 g_thread_xp_waiter_tls = TlsAlloc ();
948 g_thread_impl_vtable = g_thread_xp_impl_vtable;
951 /* {{{1 Epilogue */
953 static gboolean
954 g_thread_lookup_native_funcs (void)
956 GThreadImplVtable native_vtable = { 0, };
957 HMODULE kernel32;
959 kernel32 = GetModuleHandle ("KERNEL32.DLL");
961 if (kernel32 == NULL)
962 return FALSE;
964 #define GET_FUNC(name) if ((native_vtable.name = (void *) GetProcAddress (kernel32, #name)) == NULL) return FALSE
965 GET_FUNC(InitializeSRWLock);
966 GET_FUNC(AcquireSRWLockExclusive);
967 GET_FUNC(TryAcquireSRWLockExclusive);
968 GET_FUNC(ReleaseSRWLockExclusive);
969 GET_FUNC(AcquireSRWLockShared);
970 GET_FUNC(TryAcquireSRWLockShared);
971 GET_FUNC(ReleaseSRWLockShared);
973 GET_FUNC(InitializeConditionVariable);
974 GET_FUNC(SleepConditionVariableSRW);
975 GET_FUNC(WakeAllConditionVariable);
976 GET_FUNC(WakeConditionVariable);
977 #undef GET_FUNC
979 g_thread_impl_vtable = native_vtable;
981 return TRUE;
984 void
985 g_thread_win32_init (void)
987 if (!g_thread_lookup_native_funcs ())
988 g_thread_xp_init ();
990 InitializeCriticalSection (&g_private_lock);
993 void
994 g_thread_win32_thread_detach (void)
996 gboolean dtors_called;
1000 GPrivateDestructor *dtor;
1002 /* We go by the POSIX book on this one.
1004 * If we call a destructor then there is a chance that some new
1005 * TLS variables got set by code called in that destructor.
1007 * Loop until nothing is left.
1009 dtors_called = FALSE;
1011 for (dtor = g_private_destructors; dtor; dtor = dtor->next)
1013 gpointer value;
1015 value = TlsGetValue (dtor->index);
1016 if (value != NULL && dtor->notify != NULL)
1018 /* POSIX says to clear this before the call */
1019 TlsSetValue (dtor->index, NULL);
1020 dtor->notify (value);
1021 dtors_called = TRUE;
1025 while (dtors_called);
1027 if (g_thread_impl_vtable.CallThisOnThreadExit)
1028 g_thread_impl_vtable.CallThisOnThreadExit ();
1031 /* vim:set foldmethod=marker: */