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, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GLib Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GLib at ftp://ftp.gtk.org/pub/gtk/.
31 /* The GMutex and GCond implementations in this file are some of the
32 * lowest-level code in GLib. All other parts of GLib (messages,
33 * memory, slices, etc) assume that they can freely use these facilities
34 * without risking recursion.
36 * As such, these functions are NOT permitted to call any other part of
39 * The thread manipulation functions (create, exit, join, etc.) have
40 * more freedom -- they can do as they please.
47 #include "gthreadprivate.h"
57 g_thread_abort (gint status
,
58 const gchar
*function
)
60 fprintf (stderr
, "GLib (gthread-win32.c): Unexpected error from C library during '%s': %s. Aborting.\n",
61 strerror (status
), function
);
65 /* Starting with Vista and Windows 2008, we have access to the
66 * CONDITION_VARIABLE and SRWLock primatives on Windows, which are
67 * pretty reasonable approximations of the primatives specified in
68 * POSIX 2001 (pthread_cond_t and pthread_mutex_t respectively).
70 * Both of these types are structs containing a single pointer. That
71 * pointer is used as an atomic bitfield to support user-space mutexes
72 * that only get the kernel involved in cases of contention (similar
73 * to how futex()-based mutexes work on Linux). The biggest advantage
74 * of these new types is that they can be statically initialised to
75 * zero. That means that they are completely ABI compatible with our
76 * GMutex and GCond APIs.
78 * Unfortunately, Windows XP lacks these facilities and GLib still
79 * needs to support Windows XP. Our approach here is as follows:
81 * - avoid depending on structure declarations at compile-time by
82 * declaring our own GMutex and GCond strutures to be
83 * ABI-compatible with SRWLock and CONDITION_VARIABLE and using
86 * - avoid a hard dependency on the symbols used to manipulate these
87 * structures by doing a dynamic lookup of those symbols at
90 * - if the symbols are not available, emulate them using other
93 * Using this approach also allows us to easily build a GLib that lacks
94 * support for Windows XP or to remove this code entirely when XP is no
95 * longer supported (end of line is currently April 8, 2014).
99 void (__stdcall
* CallThisOnThreadExit
) (void); /* fake */
101 void (__stdcall
* InitializeSRWLock
) (gpointer lock
);
102 void (__stdcall
* DeleteSRWLock
) (gpointer lock
); /* fake */
103 void (__stdcall
* AcquireSRWLockExclusive
) (gpointer lock
);
104 BOOLEAN (__stdcall
* TryAcquireSRWLockExclusive
) (gpointer lock
);
105 void (__stdcall
* ReleaseSRWLockExclusive
) (gpointer lock
);
106 void (__stdcall
* AcquireSRWLockShared
) (gpointer lock
);
107 BOOLEAN (__stdcall
* TryAcquireSRWLockShared
) (gpointer lock
);
108 void (__stdcall
* ReleaseSRWLockShared
) (gpointer lock
);
110 void (__stdcall
* InitializeConditionVariable
) (gpointer cond
);
111 void (__stdcall
* DeleteConditionVariable
) (gpointer cond
); /* fake */
112 BOOL (__stdcall
* SleepConditionVariableSRW
) (gpointer cond
,
116 void (__stdcall
* WakeAllConditionVariable
) (gpointer cond
);
117 void (__stdcall
* WakeConditionVariable
) (gpointer cond
);
120 static GThreadImplVtable g_thread_impl_vtable
;
124 g_mutex_init (GMutex
*mutex
)
126 g_thread_impl_vtable
.InitializeSRWLock (mutex
);
130 g_mutex_clear (GMutex
*mutex
)
132 if (g_thread_impl_vtable
.DeleteSRWLock
!= NULL
)
133 g_thread_impl_vtable
.DeleteSRWLock (mutex
);
137 g_mutex_lock (GMutex
*mutex
)
139 g_thread_impl_vtable
.AcquireSRWLockExclusive (mutex
);
143 g_mutex_trylock (GMutex
*mutex
)
145 return g_thread_impl_vtable
.TryAcquireSRWLockExclusive (mutex
);
149 g_mutex_unlock (GMutex
*mutex
)
151 g_thread_impl_vtable
.ReleaseSRWLockExclusive (mutex
);
156 static CRITICAL_SECTION
*
157 g_rec_mutex_impl_new (void)
159 CRITICAL_SECTION
*cs
;
161 cs
= g_slice_new (CRITICAL_SECTION
);
162 InitializeCriticalSection (cs
);
168 g_rec_mutex_impl_free (CRITICAL_SECTION
*cs
)
170 DeleteCriticalSection (cs
);
171 g_slice_free (CRITICAL_SECTION
, cs
);
174 static CRITICAL_SECTION
*
175 g_rec_mutex_get_impl (GRecMutex
*mutex
)
177 CRITICAL_SECTION
*impl
= mutex
->p
;
179 if G_UNLIKELY (mutex
->p
== NULL
)
181 impl
= g_rec_mutex_impl_new ();
182 if (InterlockedCompareExchangePointer (&mutex
->p
, impl
, NULL
) != NULL
)
183 g_rec_mutex_impl_free (impl
);
191 g_rec_mutex_init (GRecMutex
*mutex
)
193 mutex
->p
= g_rec_mutex_impl_new ();
197 g_rec_mutex_clear (GRecMutex
*mutex
)
199 g_rec_mutex_impl_free (mutex
->p
);
203 g_rec_mutex_lock (GRecMutex
*mutex
)
205 EnterCriticalSection (g_rec_mutex_get_impl (mutex
));
209 g_rec_mutex_unlock (GRecMutex
*mutex
)
211 LeaveCriticalSection (mutex
->p
);
215 g_rec_mutex_trylock (GRecMutex
*mutex
)
217 return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex
));
223 g_rw_lock_init (GRWLock
*lock
)
225 g_thread_impl_vtable
.InitializeSRWLock (lock
);
229 g_rw_lock_clear (GRWLock
*lock
)
231 if (g_thread_impl_vtable
.DeleteSRWLock
!= NULL
)
232 g_thread_impl_vtable
.DeleteSRWLock (lock
);
236 g_rw_lock_writer_lock (GRWLock
*lock
)
238 g_thread_impl_vtable
.AcquireSRWLockExclusive (lock
);
242 g_rw_lock_writer_trylock (GRWLock
*lock
)
244 return g_thread_impl_vtable
.TryAcquireSRWLockExclusive (lock
);
248 g_rw_lock_writer_unlock (GRWLock
*lock
)
250 g_thread_impl_vtable
.ReleaseSRWLockExclusive (lock
);
254 g_rw_lock_reader_lock (GRWLock
*lock
)
256 g_thread_impl_vtable
.AcquireSRWLockShared (lock
);
260 g_rw_lock_reader_trylock (GRWLock
*lock
)
262 return g_thread_impl_vtable
.TryAcquireSRWLockShared (lock
);
266 g_rw_lock_reader_unlock (GRWLock
*lock
)
268 g_thread_impl_vtable
.ReleaseSRWLockShared (lock
);
273 g_cond_init (GCond
*cond
)
275 g_thread_impl_vtable
.InitializeConditionVariable (cond
);
279 g_cond_clear (GCond
*cond
)
281 if (g_thread_impl_vtable
.DeleteConditionVariable
)
282 g_thread_impl_vtable
.DeleteConditionVariable (cond
);
286 g_cond_signal (GCond
*cond
)
288 g_thread_impl_vtable
.WakeConditionVariable (cond
);
292 g_cond_broadcast (GCond
*cond
)
294 g_thread_impl_vtable
.WakeAllConditionVariable (cond
);
298 g_cond_wait (GCond
*cond
,
299 GMutex
*entered_mutex
)
301 g_thread_impl_vtable
.SleepConditionVariableSRW (cond
, entered_mutex
, INFINITE
, 0);
305 g_cond_wait_until (GCond
*cond
,
306 GMutex
*entered_mutex
,
311 span
= end_time
- g_get_monotonic_time ();
313 if G_UNLIKELY (span
< 0)
316 if G_UNLIKELY (span
> G_GINT64_CONSTANT (1000) * G_MAXINT32
)
319 return g_thread_impl_vtable
.SleepConditionVariableSRW (cond
, entered_mutex
, span
/ 1000, 0);
324 typedef struct _GPrivateDestructor GPrivateDestructor
;
326 struct _GPrivateDestructor
329 GDestroyNotify notify
;
330 GPrivateDestructor
*next
;
333 static GPrivateDestructor
* volatile g_private_destructors
;
334 static CRITICAL_SECTION g_private_lock
;
337 g_private_get_impl (GPrivate
*key
)
339 DWORD impl
= (DWORD
) key
->p
;
341 if G_UNLIKELY (impl
== 0)
343 EnterCriticalSection (&g_private_lock
);
344 impl
= (DWORD
) key
->p
;
347 GPrivateDestructor
*destructor
;
351 if (impl
== TLS_OUT_OF_INDEXES
)
352 g_thread_abort (0, "TlsAlloc");
354 if (key
->notify
!= NULL
)
356 destructor
= malloc (sizeof (GPrivateDestructor
));
357 if G_UNLIKELY (destructor
== NULL
)
358 g_thread_abort (errno
, "malloc");
359 destructor
->index
= impl
;
360 destructor
->notify
= key
->notify
;
361 destructor
->next
= g_private_destructors
;
363 /* We need to do an atomic store due to the unlocked
364 * access to the destructor list from the thread exit
367 * It can double as a sanity check...
369 if (InterlockedCompareExchangePointer (&g_private_destructors
, destructor
,
370 destructor
->next
) != destructor
->next
)
371 g_thread_abort (0, "g_private_get_impl(1)");
374 /* Ditto, due to the unlocked access on the fast path */
375 if (InterlockedCompareExchangePointer (&key
->p
, impl
, NULL
) != NULL
)
376 g_thread_abort (0, "g_private_get_impl(2)");
378 LeaveCriticalSection (&g_private_lock
);
385 g_private_get (GPrivate
*key
)
387 return TlsGetValue (g_private_get_impl (key
));
391 g_private_set (GPrivate
*key
,
394 TlsSetValue (g_private_get_impl (key
), value
);
398 g_private_replace (GPrivate
*key
,
401 DWORD impl
= g_private_get_impl (key
);
404 old
= TlsGetValue (impl
);
405 if (old
&& key
->notify
)
407 TlsSetValue (impl
, value
);
412 #define win32_check_for_error(what) G_STMT_START{ \
414 g_error ("file %s: line %d (%s): error %s during %s", \
415 __FILE__, __LINE__, G_STRFUNC, \
416 g_win32_error_message (GetLastError ()), #what); \
419 #define G_MUTEX_SIZE (sizeof (gpointer))
421 typedef BOOL (__stdcall
*GTryEnterCriticalSectionFunc
) (CRITICAL_SECTION
*);
432 g_system_thread_free (GRealThread
*thread
)
434 GThreadWin32
*wt
= (GThreadWin32
*) thread
;
436 win32_check_for_error (CloseHandle (wt
->handle
));
437 g_slice_free (GThreadWin32
, wt
);
441 g_system_thread_exit (void)
446 static guint __stdcall
447 g_thread_win32_proxy (gpointer data
)
449 GThreadWin32
*self
= data
;
453 g_system_thread_exit ();
455 g_assert_not_reached ();
461 g_system_thread_new (GThreadFunc func
,
465 GThreadWin32
*thread
;
468 thread
= g_slice_new0 (GThreadWin32
);
469 thread
->proxy
= func
;
471 thread
->handle
= (HANDLE
) _beginthreadex (NULL
, stack_size
, g_thread_win32_proxy
, thread
, 0, &ignore
);
473 if (thread
->handle
== NULL
)
475 gchar
*win_error
= g_win32_error_message (GetLastError ());
476 g_set_error (error
, G_THREAD_ERROR
, G_THREAD_ERROR_AGAIN
,
477 "Error creating thread: %s", win_error
);
479 g_slice_free (GThreadWin32
, thread
);
483 return (GRealThread
*) thread
;
487 g_thread_yield (void)
493 g_system_thread_wait (GRealThread
*thread
)
495 GThreadWin32
*wt
= (GThreadWin32
*) thread
;
497 win32_check_for_error (WAIT_FAILED
!= WaitForSingleObject (wt
->handle
, INFINITE
));
501 g_system_thread_set_name (const gchar
*name
)
503 /* FIXME: implement */
506 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
508 static CRITICAL_SECTION g_thread_xp_lock
;
509 static DWORD g_thread_xp_waiter_tls
;
511 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
512 typedef struct _GThreadXpWaiter GThreadXpWaiter
;
513 struct _GThreadXpWaiter
516 volatile GThreadXpWaiter
*next
;
517 volatile GThreadXpWaiter
**my_owner
;
520 static GThreadXpWaiter
*
521 g_thread_xp_waiter_get (void)
523 GThreadXpWaiter
*waiter
;
525 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
527 if G_UNLIKELY (waiter
== NULL
)
529 waiter
= malloc (sizeof (GThreadXpWaiter
));
531 g_thread_abort (GetLastError (), "malloc");
532 waiter
->event
= CreateEvent (0, FALSE
, FALSE
, NULL
);
533 if (waiter
->event
== NULL
)
534 g_thread_abort (GetLastError (), "CreateEvent");
535 waiter
->my_owner
= NULL
;
537 TlsSetValue (g_thread_xp_waiter_tls
, waiter
);
543 static void __stdcall
544 g_thread_xp_CallThisOnThreadExit (void)
546 GThreadXpWaiter
*waiter
;
548 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
552 TlsSetValue (g_thread_xp_waiter_tls
, NULL
);
553 CloseHandle (waiter
->event
);
558 /* {{{2 SRWLock emulation */
561 CRITICAL_SECTION writer_lock
;
562 gboolean ever_shared
; /* protected by writer_lock */
563 gboolean writer_locked
; /* protected by writer_lock */
565 /* below is only ever touched if ever_shared becomes true */
566 CRITICAL_SECTION atomicity
;
567 GThreadXpWaiter
*queued_writer
; /* protected by atomicity lock */
568 gint num_readers
; /* protected by atomicity lock */
571 static void __stdcall
572 g_thread_xp_InitializeSRWLock (gpointer mutex
)
574 *(GThreadSRWLock
* volatile *) mutex
= NULL
;
577 static void __stdcall
578 g_thread_xp_DeleteSRWLock (gpointer mutex
)
580 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
584 if (lock
->ever_shared
)
585 DeleteCriticalSection (&lock
->atomicity
);
587 DeleteCriticalSection (&lock
->writer_lock
);
592 static GThreadSRWLock
* __stdcall
593 g_thread_xp_get_srwlock (GThreadSRWLock
* volatile *lock
)
595 GThreadSRWLock
*result
;
597 /* It looks like we're missing some barriers here, but this code only
598 * ever runs on Windows XP, which in turn only ever runs on hardware
599 * with a relatively rigid memory model. The 'volatile' will take
600 * care of the compiler.
604 if G_UNLIKELY (result
== NULL
)
606 EnterCriticalSection (&g_thread_xp_lock
);
612 result
= malloc (sizeof (GThreadSRWLock
));
615 g_thread_abort (errno
, "malloc");
617 InitializeCriticalSection (&result
->writer_lock
);
618 result
->writer_locked
= FALSE
;
619 result
->ever_shared
= FALSE
;
623 LeaveCriticalSection (&g_thread_xp_lock
);
629 static void __stdcall
630 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex
)
632 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
634 EnterCriticalSection (&lock
->writer_lock
);
636 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
637 * Detect the deadlock that would occur on later Windows version.
639 g_assert (!lock
->writer_locked
);
640 lock
->writer_locked
= TRUE
;
642 if (lock
->ever_shared
)
644 GThreadXpWaiter
*waiter
= NULL
;
646 EnterCriticalSection (&lock
->atomicity
);
647 if (lock
->num_readers
> 0)
648 lock
->queued_writer
= waiter
= g_thread_xp_waiter_get ();
649 LeaveCriticalSection (&lock
->atomicity
);
652 WaitForSingleObject (waiter
->event
, INFINITE
);
654 lock
->queued_writer
= NULL
;
658 static BOOLEAN __stdcall
659 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex
)
661 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
663 if (!TryEnterCriticalSection (&lock
->writer_lock
))
666 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
667 * Ensure that this properly returns FALSE (as SRWLock would).
669 if G_UNLIKELY (lock
->writer_locked
)
671 LeaveCriticalSection (&lock
->writer_lock
);
675 lock
->writer_locked
= TRUE
;
677 if (lock
->ever_shared
)
681 EnterCriticalSection (&lock
->atomicity
);
682 available
= lock
->num_readers
== 0;
683 LeaveCriticalSection (&lock
->atomicity
);
687 LeaveCriticalSection (&lock
->writer_lock
);
695 static void __stdcall
696 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex
)
698 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
700 lock
->writer_locked
= FALSE
;
702 /* We need this until we fix some weird parts of GLib that try to
703 * unlock freshly-allocated mutexes.
706 LeaveCriticalSection (&lock
->writer_lock
);
710 g_thread_xp_srwlock_become_reader (GThreadSRWLock
*lock
)
712 if G_UNLIKELY (!lock
->ever_shared
)
714 InitializeCriticalSection (&lock
->atomicity
);
715 lock
->queued_writer
= NULL
;
716 lock
->num_readers
= 0;
718 lock
->ever_shared
= TRUE
;
721 EnterCriticalSection (&lock
->atomicity
);
723 LeaveCriticalSection (&lock
->atomicity
);
726 static void __stdcall
727 g_thread_xp_AcquireSRWLockShared (gpointer mutex
)
729 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
731 EnterCriticalSection (&lock
->writer_lock
);
733 /* See g_thread_xp_AcquireSRWLockExclusive */
734 g_assert (!lock
->writer_locked
);
736 g_thread_xp_srwlock_become_reader (lock
);
738 LeaveCriticalSection (&lock
->writer_lock
);
741 static BOOLEAN __stdcall
742 g_thread_xp_TryAcquireSRWLockShared (gpointer mutex
)
744 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
746 if (!TryEnterCriticalSection (&lock
->writer_lock
))
749 /* See g_thread_xp_AcquireSRWLockExclusive */
750 if G_UNLIKELY (lock
->writer_locked
)
752 LeaveCriticalSection (&lock
->writer_lock
);
756 g_thread_xp_srwlock_become_reader (lock
);
758 LeaveCriticalSection (&lock
->writer_lock
);
763 static void __stdcall
764 g_thread_xp_ReleaseSRWLockShared (gpointer mutex
)
766 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
768 EnterCriticalSection (&lock
->atomicity
);
772 if (lock
->num_readers
== 0 && lock
->queued_writer
)
773 SetEvent (lock
->queued_writer
->event
);
775 LeaveCriticalSection (&lock
->atomicity
);
778 /* {{{2 CONDITION_VARIABLE emulation */
781 volatile GThreadXpWaiter
*first
;
782 volatile GThreadXpWaiter
**last_ptr
;
783 } GThreadXpCONDITION_VARIABLE
;
785 static void __stdcall
786 g_thread_xp_InitializeConditionVariable (gpointer cond
)
788 *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
= NULL
;
791 static void __stdcall
792 g_thread_xp_DeleteConditionVariable (gpointer cond
)
794 GThreadXpCONDITION_VARIABLE
*cv
= *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
;
800 static GThreadXpCONDITION_VARIABLE
* __stdcall
801 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE
* volatile *cond
)
803 GThreadXpCONDITION_VARIABLE
*result
;
805 /* It looks like we're missing some barriers here, but this code only
806 * ever runs on Windows XP, which in turn only ever runs on hardware
807 * with a relatively rigid memory model. The 'volatile' will take
808 * care of the compiler.
812 if G_UNLIKELY (result
== NULL
)
814 result
= malloc (sizeof (GThreadXpCONDITION_VARIABLE
));
817 g_thread_abort (errno
, "malloc");
819 result
->first
= NULL
;
820 result
->last_ptr
= &result
->first
;
822 if (InterlockedCompareExchangePointer (cond
, result
, NULL
) != NULL
)
832 static BOOL __stdcall
833 g_thread_xp_SleepConditionVariableSRW (gpointer cond
,
838 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
839 GThreadXpWaiter
*waiter
= g_thread_xp_waiter_get ();
844 EnterCriticalSection (&g_thread_xp_lock
);
845 waiter
->my_owner
= cv
->last_ptr
;
846 *cv
->last_ptr
= waiter
;
847 cv
->last_ptr
= &waiter
->next
;
848 LeaveCriticalSection (&g_thread_xp_lock
);
850 g_mutex_unlock (mutex
);
851 status
= WaitForSingleObject (waiter
->event
, timeout
);
853 if (status
!= WAIT_TIMEOUT
&& status
!= WAIT_OBJECT_0
)
854 g_thread_abort (GetLastError (), "WaitForSingleObject");
855 g_mutex_lock (mutex
);
857 if (status
== WAIT_TIMEOUT
)
859 EnterCriticalSection (&g_thread_xp_lock
);
860 if (waiter
->my_owner
)
863 waiter
->next
->my_owner
= waiter
->my_owner
;
865 cv
->last_ptr
= waiter
->my_owner
;
866 *waiter
->my_owner
= waiter
->next
;
867 waiter
->my_owner
= NULL
;
869 LeaveCriticalSection (&g_thread_xp_lock
);
872 return status
== WAIT_OBJECT_0
;
875 static void __stdcall
876 g_thread_xp_WakeConditionVariable (gpointer cond
)
878 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
879 volatile GThreadXpWaiter
*waiter
;
881 EnterCriticalSection (&g_thread_xp_lock
);
886 waiter
->my_owner
= NULL
;
887 cv
->first
= waiter
->next
;
888 if (cv
->first
!= NULL
)
889 cv
->first
->my_owner
= &cv
->first
;
891 cv
->last_ptr
= &cv
->first
;
895 SetEvent (waiter
->event
);
897 LeaveCriticalSection (&g_thread_xp_lock
);
900 static void __stdcall
901 g_thread_xp_WakeAllConditionVariable (gpointer cond
)
903 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
904 volatile GThreadXpWaiter
*waiter
;
906 EnterCriticalSection (&g_thread_xp_lock
);
910 cv
->last_ptr
= &cv
->first
;
912 while (waiter
!= NULL
)
914 volatile GThreadXpWaiter
*next
;
917 SetEvent (waiter
->event
);
918 waiter
->my_owner
= NULL
;
922 LeaveCriticalSection (&g_thread_xp_lock
);
927 g_thread_xp_init (void)
929 static const GThreadImplVtable g_thread_xp_impl_vtable
= {
930 g_thread_xp_CallThisOnThreadExit
,
931 g_thread_xp_InitializeSRWLock
,
932 g_thread_xp_DeleteSRWLock
,
933 g_thread_xp_AcquireSRWLockExclusive
,
934 g_thread_xp_TryAcquireSRWLockExclusive
,
935 g_thread_xp_ReleaseSRWLockExclusive
,
936 g_thread_xp_AcquireSRWLockShared
,
937 g_thread_xp_TryAcquireSRWLockShared
,
938 g_thread_xp_ReleaseSRWLockShared
,
939 g_thread_xp_InitializeConditionVariable
,
940 g_thread_xp_DeleteConditionVariable
,
941 g_thread_xp_SleepConditionVariableSRW
,
942 g_thread_xp_WakeAllConditionVariable
,
943 g_thread_xp_WakeConditionVariable
946 InitializeCriticalSection (&g_thread_xp_lock
);
947 g_thread_xp_waiter_tls
= TlsAlloc ();
949 g_thread_impl_vtable
= g_thread_xp_impl_vtable
;
955 g_thread_lookup_native_funcs (void)
957 GThreadImplVtable native_vtable
= { 0, };
960 kernel32
= GetModuleHandle ("KERNEL32.DLL");
962 if (kernel32
== NULL
)
965 #define GET_FUNC(name) if ((native_vtable.name = (void *) GetProcAddress (kernel32, #name)) == NULL) return FALSE
966 GET_FUNC(InitializeSRWLock
);
967 GET_FUNC(AcquireSRWLockExclusive
);
968 GET_FUNC(TryAcquireSRWLockExclusive
);
969 GET_FUNC(ReleaseSRWLockExclusive
);
970 GET_FUNC(AcquireSRWLockShared
);
971 GET_FUNC(TryAcquireSRWLockShared
);
972 GET_FUNC(ReleaseSRWLockShared
);
974 GET_FUNC(InitializeConditionVariable
);
975 GET_FUNC(SleepConditionVariableSRW
);
976 GET_FUNC(WakeAllConditionVariable
);
977 GET_FUNC(WakeConditionVariable
);
980 g_thread_impl_vtable
= native_vtable
;
986 g_thread_win32_init (void)
988 if (!g_thread_lookup_native_funcs ())
991 InitializeCriticalSection (&g_private_lock
);
995 g_thread_win32_thread_detach (void)
997 gboolean dtors_called
;
1001 GPrivateDestructor
*dtor
;
1003 /* We go by the POSIX book on this one.
1005 * If we call a destructor then there is a chance that some new
1006 * TLS variables got set by code called in that destructor.
1008 * Loop until nothing is left.
1010 dtors_called
= FALSE
;
1012 for (dtor
= g_private_destructors
; dtor
; dtor
= dtor
->next
)
1016 value
= TlsGetValue (dtor
->index
);
1017 if (value
!= NULL
&& dtor
->notify
!= NULL
)
1019 /* POSIX says to clear this before the call */
1020 TlsSetValue (dtor
->index
, NULL
);
1021 dtor
->notify (value
);
1022 dtors_called
= TRUE
;
1026 while (dtors_called
);
1028 if (g_thread_impl_vtable
.CallThisOnThreadExit
)
1029 g_thread_impl_vtable
.CallThisOnThreadExit ();
1032 /* vim:set foldmethod=marker: */