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
37 * The thread manipulation functions (create, exit, join, etc.) have
38 * more freedom -- they can do as they please.
44 #include "glib-init.h"
46 #include "gthreadprivate.h"
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
);
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
85 * - avoid a hard dependency on the symbols used to manipulate these
86 * structures by doing a dynamic lookup of those symbols at
89 * - if the symbols are not available, emulate them using other
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).
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
,
115 void (__stdcall
* WakeAllConditionVariable
) (gpointer cond
);
116 void (__stdcall
* WakeConditionVariable
) (gpointer cond
);
119 static GThreadImplVtable g_thread_impl_vtable
;
123 g_mutex_init (GMutex
*mutex
)
125 g_thread_impl_vtable
.InitializeSRWLock (mutex
);
129 g_mutex_clear (GMutex
*mutex
)
131 if (g_thread_impl_vtable
.DeleteSRWLock
!= NULL
)
132 g_thread_impl_vtable
.DeleteSRWLock (mutex
);
136 g_mutex_lock (GMutex
*mutex
)
138 g_thread_impl_vtable
.AcquireSRWLockExclusive (mutex
);
142 g_mutex_trylock (GMutex
*mutex
)
144 return g_thread_impl_vtable
.TryAcquireSRWLockExclusive (mutex
);
148 g_mutex_unlock (GMutex
*mutex
)
150 g_thread_impl_vtable
.ReleaseSRWLockExclusive (mutex
);
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
);
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
);
190 g_rec_mutex_init (GRecMutex
*mutex
)
192 mutex
->p
= g_rec_mutex_impl_new ();
196 g_rec_mutex_clear (GRecMutex
*mutex
)
198 g_rec_mutex_impl_free (mutex
->p
);
202 g_rec_mutex_lock (GRecMutex
*mutex
)
204 EnterCriticalSection (g_rec_mutex_get_impl (mutex
));
208 g_rec_mutex_unlock (GRecMutex
*mutex
)
210 LeaveCriticalSection (mutex
->p
);
214 g_rec_mutex_trylock (GRecMutex
*mutex
)
216 return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex
));
222 g_rw_lock_init (GRWLock
*lock
)
224 g_thread_impl_vtable
.InitializeSRWLock (lock
);
228 g_rw_lock_clear (GRWLock
*lock
)
230 if (g_thread_impl_vtable
.DeleteSRWLock
!= NULL
)
231 g_thread_impl_vtable
.DeleteSRWLock (lock
);
235 g_rw_lock_writer_lock (GRWLock
*lock
)
237 g_thread_impl_vtable
.AcquireSRWLockExclusive (lock
);
241 g_rw_lock_writer_trylock (GRWLock
*lock
)
243 return g_thread_impl_vtable
.TryAcquireSRWLockExclusive (lock
);
247 g_rw_lock_writer_unlock (GRWLock
*lock
)
249 g_thread_impl_vtable
.ReleaseSRWLockExclusive (lock
);
253 g_rw_lock_reader_lock (GRWLock
*lock
)
255 g_thread_impl_vtable
.AcquireSRWLockShared (lock
);
259 g_rw_lock_reader_trylock (GRWLock
*lock
)
261 return g_thread_impl_vtable
.TryAcquireSRWLockShared (lock
);
265 g_rw_lock_reader_unlock (GRWLock
*lock
)
267 g_thread_impl_vtable
.ReleaseSRWLockShared (lock
);
272 g_cond_init (GCond
*cond
)
274 g_thread_impl_vtable
.InitializeConditionVariable (cond
);
278 g_cond_clear (GCond
*cond
)
280 if (g_thread_impl_vtable
.DeleteConditionVariable
)
281 g_thread_impl_vtable
.DeleteConditionVariable (cond
);
285 g_cond_signal (GCond
*cond
)
287 g_thread_impl_vtable
.WakeConditionVariable (cond
);
291 g_cond_broadcast (GCond
*cond
)
293 g_thread_impl_vtable
.WakeAllConditionVariable (cond
);
297 g_cond_wait (GCond
*cond
,
298 GMutex
*entered_mutex
)
300 g_thread_impl_vtable
.SleepConditionVariableSRW (cond
, entered_mutex
, INFINITE
, 0);
304 g_cond_wait_until (GCond
*cond
,
305 GMutex
*entered_mutex
,
310 span
= end_time
- g_get_monotonic_time ();
312 if G_UNLIKELY (span
< 0)
315 if G_UNLIKELY (span
> G_GINT64_CONSTANT (1000) * G_MAXINT32
)
318 return g_thread_impl_vtable
.SleepConditionVariableSRW (cond
, entered_mutex
, span
/ 1000, 0);
323 typedef struct _GPrivateDestructor GPrivateDestructor
;
325 struct _GPrivateDestructor
328 GDestroyNotify notify
;
329 GPrivateDestructor
*next
;
332 static GPrivateDestructor
* volatile g_private_destructors
;
333 static CRITICAL_SECTION g_private_lock
;
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
;
346 GPrivateDestructor
*destructor
;
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
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
);
384 g_private_get (GPrivate
*key
)
386 return TlsGetValue (g_private_get_impl (key
));
390 g_private_set (GPrivate
*key
,
393 TlsSetValue (g_private_get_impl (key
), value
);
397 g_private_replace (GPrivate
*key
,
400 DWORD impl
= g_private_get_impl (key
);
403 old
= TlsGetValue (impl
);
404 if (old
&& key
->notify
)
406 TlsSetValue (impl
, value
);
411 #define win32_check_for_error(what) G_STMT_START{ \
413 g_error ("file %s: line %d (%s): error %s during %s", \
414 __FILE__, __LINE__, G_STRFUNC, \
415 g_win32_error_message (GetLastError ()), #what); \
418 #define G_MUTEX_SIZE (sizeof (gpointer))
420 typedef BOOL (__stdcall
*GTryEnterCriticalSectionFunc
) (CRITICAL_SECTION
*);
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
);
440 g_system_thread_exit (void)
445 static guint __stdcall
446 g_thread_win32_proxy (gpointer data
)
448 GThreadWin32
*self
= data
;
452 g_system_thread_exit ();
454 g_assert_not_reached ();
460 g_system_thread_new (GThreadFunc func
,
464 GThreadWin32
*thread
;
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
);
478 g_slice_free (GThreadWin32
, thread
);
482 return (GRealThread
*) thread
;
486 g_thread_yield (void)
492 g_system_thread_wait (GRealThread
*thread
)
494 GThreadWin32
*wt
= (GThreadWin32
*) thread
;
496 win32_check_for_error (WAIT_FAILED
!= WaitForSingleObject (wt
->handle
, INFINITE
));
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
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
));
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
);
542 static void __stdcall
543 g_thread_xp_CallThisOnThreadExit (void)
545 GThreadXpWaiter
*waiter
;
547 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
551 TlsSetValue (g_thread_xp_waiter_tls
, NULL
);
552 CloseHandle (waiter
->event
);
557 /* {{{2 SRWLock emulation */
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 */
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
;
583 if (lock
->ever_shared
)
584 DeleteCriticalSection (&lock
->atomicity
);
586 DeleteCriticalSection (&lock
->writer_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.
603 if G_UNLIKELY (result
== NULL
)
605 EnterCriticalSection (&g_thread_xp_lock
);
611 result
= malloc (sizeof (GThreadSRWLock
));
614 g_thread_abort (errno
, "malloc");
616 InitializeCriticalSection (&result
->writer_lock
);
617 result
->writer_locked
= FALSE
;
618 result
->ever_shared
= FALSE
;
622 LeaveCriticalSection (&g_thread_xp_lock
);
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
);
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
))
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
);
674 lock
->writer_locked
= TRUE
;
676 if (lock
->ever_shared
)
680 EnterCriticalSection (&lock
->atomicity
);
681 available
= lock
->num_readers
== 0;
682 LeaveCriticalSection (&lock
->atomicity
);
686 LeaveCriticalSection (&lock
->writer_lock
);
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.
705 LeaveCriticalSection (&lock
->writer_lock
);
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
);
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
))
748 /* See g_thread_xp_AcquireSRWLockExclusive */
749 if G_UNLIKELY (lock
->writer_locked
)
751 LeaveCriticalSection (&lock
->writer_lock
);
755 g_thread_xp_srwlock_become_reader (lock
);
757 LeaveCriticalSection (&lock
->writer_lock
);
762 static void __stdcall
763 g_thread_xp_ReleaseSRWLockShared (gpointer mutex
)
765 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
767 EnterCriticalSection (&lock
->atomicity
);
771 if (lock
->num_readers
== 0 && lock
->queued_writer
)
772 SetEvent (lock
->queued_writer
->event
);
774 LeaveCriticalSection (&lock
->atomicity
);
777 /* {{{2 CONDITION_VARIABLE emulation */
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
;
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.
811 if G_UNLIKELY (result
== NULL
)
813 result
= malloc (sizeof (GThreadXpCONDITION_VARIABLE
));
816 g_thread_abort (errno
, "malloc");
818 result
->first
= NULL
;
819 result
->last_ptr
= &result
->first
;
821 if (InterlockedCompareExchangePointer (cond
, result
, NULL
) != NULL
)
831 static BOOL __stdcall
832 g_thread_xp_SleepConditionVariableSRW (gpointer cond
,
837 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
838 GThreadXpWaiter
*waiter
= g_thread_xp_waiter_get ();
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
)
862 waiter
->next
->my_owner
= waiter
->my_owner
;
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
);
885 waiter
->my_owner
= NULL
;
886 cv
->first
= waiter
->next
;
887 if (cv
->first
!= NULL
)
888 cv
->first
->my_owner
= &cv
->first
;
890 cv
->last_ptr
= &cv
->first
;
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
);
909 cv
->last_ptr
= &cv
->first
;
911 while (waiter
!= NULL
)
913 volatile GThreadXpWaiter
*next
;
916 SetEvent (waiter
->event
);
917 waiter
->my_owner
= NULL
;
921 LeaveCriticalSection (&g_thread_xp_lock
);
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
;
954 g_thread_lookup_native_funcs (void)
956 GThreadImplVtable native_vtable
= { 0, };
959 kernel32
= GetModuleHandle ("KERNEL32.DLL");
961 if (kernel32
== NULL
)
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
);
979 g_thread_impl_vtable
= native_vtable
;
985 g_thread_win32_init (void)
987 if (!g_thread_lookup_native_funcs ())
990 InitializeCriticalSection (&g_private_lock
);
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
)
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: */