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.
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_timedwait (GCond
*cond
,
305 GMutex
*entered_mutex
,
312 GetSystemTimeAsFileTime (&ft
);
313 memmove (&now
, &ft
, sizeof (FILETIME
));
315 now
-= G_GINT64_CONSTANT (116444736000000000);
318 span
= abs_time
- now
;
320 if G_UNLIKELY (span
< 0)
323 if G_UNLIKELY (span
> G_GINT64_CONSTANT (1000) * G_MAXINT32
)
326 return g_thread_impl_vtable
.SleepConditionVariableSRW (cond
, entered_mutex
, span
/ 1000, 0);
330 g_cond_timed_wait (GCond
*cond
,
331 GMutex
*entered_mutex
,
338 micros
= abs_time
->tv_sec
;
340 micros
+= abs_time
->tv_usec
;
342 return g_cond_timedwait (cond
, entered_mutex
, micros
);
346 g_cond_wait (cond
, entered_mutex
);
353 typedef struct _GPrivateDestructor GPrivateDestructor
;
355 struct _GPrivateDestructor
358 GDestroyNotify notify
;
359 GPrivateDestructor
*next
;
362 static GPrivateDestructor
* volatile g_private_destructors
;
363 static CRITICAL_SECTION g_private_lock
;
366 g_private_get_impl (GPrivate
*key
)
368 DWORD impl
= (DWORD
) key
->p
;
370 if G_UNLIKELY (impl
== 0)
372 EnterCriticalSection (&g_private_lock
);
373 impl
= (DWORD
) key
->p
;
376 GPrivateDestructor
*destructor
;
380 if (impl
== TLS_OUT_OF_INDEXES
)
381 g_thread_abort (0, "TlsAlloc");
383 if (key
->notify
!= NULL
)
385 destructor
= malloc (sizeof (GPrivateDestructor
));
386 if G_UNLIKELY (destructor
== NULL
)
387 g_thread_abort (errno
, "malloc");
388 destructor
->index
= impl
;
389 destructor
->notify
= key
->notify
;
390 destructor
->next
= g_private_destructors
;
392 /* We need to do an atomic store due to the unlocked
393 * access to the destructor list from the thread exit
396 * It can double as a sanity check...
398 if (InterlockedCompareExchangePointer (&g_private_destructors
, destructor
,
399 destructor
->next
) != destructor
->next
)
400 g_thread_abort (0, "g_private_get_impl(1)");
403 /* Ditto, due to the unlocked access on the fast path */
404 if (InterlockedCompareExchangePointer (&key
->p
, impl
, NULL
) != NULL
)
405 g_thread_abort (0, "g_private_get_impl(2)");
407 LeaveCriticalSection (&g_private_lock
);
414 g_private_get (GPrivate
*key
)
416 return TlsGetValue (g_private_get_impl (key
));
420 g_private_set (GPrivate
*key
,
423 TlsSetValue (g_private_get_impl (key
), value
);
427 g_private_replace (GPrivate
*key
,
430 DWORD impl
= g_private_get_impl (key
);
433 old
= TlsGetValue (impl
);
434 if (old
&& key
->notify
)
436 TlsSetValue (impl
, value
);
442 #include "gthreadprivate.h"
444 #define win32_check_for_error(what) G_STMT_START{ \
446 g_error ("file %s: line %d (%s): error %s during %s", \
447 __FILE__, __LINE__, G_STRFUNC, \
448 g_win32_error_message (GetLastError ()), #what); \
451 #define G_MUTEX_SIZE (sizeof (gpointer))
453 static DWORD g_thread_self_tls
;
455 typedef BOOL (__stdcall
*GTryEnterCriticalSectionFunc
) (CRITICAL_SECTION
*);
457 typedef struct _GThreadData GThreadData
;
467 g_system_thread_new (void)
469 return g_slice_new0 (GRealThread
);
473 g_system_thread_free (GRealThread
*thread
)
475 g_slice_free (GRealThread
, thread
);
479 g_system_thread_exit (void)
484 static guint __stdcall
485 g_thread_proxy (gpointer data
)
487 GThreadData
*self
= (GThreadData
*) data
;
489 win32_check_for_error (TlsSetValue (g_thread_self_tls
, self
));
491 self
->func (self
->data
);
493 g_system_thread_exit ();
495 g_assert_not_reached ();
501 g_system_thread_create (GThreadFunc func
,
511 g_return_if_fail (func
);
513 retval
= g_new(GThreadData
, 1);
517 retval
->joinable
= joinable
;
519 retval
->thread
= (HANDLE
) _beginthreadex (NULL
, stack_size
, g_thread_proxy
,
522 if (retval
->thread
== NULL
)
524 gchar
*win_error
= g_win32_error_message (GetLastError ());
525 g_set_error (error
, G_THREAD_ERROR
, G_THREAD_ERROR_AGAIN
,
526 "Error creating thread: %s", win_error
);
532 *(GThreadData
**)thread
= retval
;
536 g_thread_yield (void)
542 g_system_thread_wait (GRealThread
*thread
)
544 GThreadData
*target
= *(GThreadData
**)&(thread
->system_thread
);
546 g_return_if_fail (target
->joinable
);
548 win32_check_for_error (WAIT_FAILED
!=
549 WaitForSingleObject (target
->thread
, INFINITE
));
551 win32_check_for_error (CloseHandle (target
->thread
));
556 g_system_thread_set_name (const gchar
*name
)
558 /* FIXME: implement */
561 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
563 static CRITICAL_SECTION g_thread_xp_lock
;
564 static DWORD g_thread_xp_waiter_tls
;
566 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
567 typedef struct _GThreadXpWaiter GThreadXpWaiter
;
568 struct _GThreadXpWaiter
571 volatile GThreadXpWaiter
*next
;
574 static GThreadXpWaiter
*
575 g_thread_xp_waiter_get (void)
577 GThreadXpWaiter
*waiter
;
579 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
581 if G_UNLIKELY (waiter
== NULL
)
583 waiter
= malloc (sizeof (GThreadXpWaiter
));
585 g_thread_abort (GetLastError (), "malloc");
586 waiter
->event
= CreateEvent (0, FALSE
, FALSE
, NULL
);
587 if (waiter
->event
== NULL
)
588 g_thread_abort (GetLastError (), "CreateEvent");
590 TlsSetValue (g_thread_xp_waiter_tls
, waiter
);
596 static void __stdcall
597 g_thread_xp_CallThisOnThreadExit (void)
599 GThreadXpWaiter
*waiter
;
601 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
605 TlsSetValue (g_thread_xp_waiter_tls
, NULL
);
606 CloseHandle (waiter
->event
);
611 /* {{{2 SRWLock emulation */
614 CRITICAL_SECTION writer_lock
;
615 gboolean ever_shared
; /* protected by writer_lock */
616 gboolean writer_locked
; /* protected by writer_lock */
618 /* below is only ever touched if ever_shared becomes true */
619 CRITICAL_SECTION atomicity
;
620 GThreadXpWaiter
*queued_writer
; /* protected by atomicity lock */
621 gint num_readers
; /* protected by atomicity lock */
624 static void __stdcall
625 g_thread_xp_InitializeSRWLock (gpointer mutex
)
627 *(GThreadSRWLock
* volatile *) mutex
= NULL
;
630 static void __stdcall
631 g_thread_xp_DeleteSRWLock (gpointer mutex
)
633 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
637 if (lock
->ever_shared
)
638 DeleteCriticalSection (&lock
->atomicity
);
640 DeleteCriticalSection (&lock
->writer_lock
);
645 static GThreadSRWLock
* __stdcall
646 g_thread_xp_get_srwlock (GThreadSRWLock
* volatile *lock
)
648 GThreadSRWLock
*result
;
650 /* It looks like we're missing some barriers here, but this code only
651 * ever runs on Windows XP, which in turn only ever runs on hardware
652 * with a relatively rigid memory model. The 'volatile' will take
653 * care of the compiler.
657 if G_UNLIKELY (result
== NULL
)
659 EnterCriticalSection (&g_thread_xp_lock
);
661 result
= malloc (sizeof (GThreadSRWLock
));
664 g_thread_abort (errno
, "malloc");
666 InitializeCriticalSection (&result
->writer_lock
);
667 result
->writer_locked
= FALSE
;
668 result
->ever_shared
= FALSE
;
671 LeaveCriticalSection (&g_thread_xp_lock
);
677 static void __stdcall
678 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex
)
680 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
682 EnterCriticalSection (&lock
->writer_lock
);
684 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
685 * Detect the deadlock that would occur on later Windows version.
687 g_assert (!lock
->writer_locked
);
688 lock
->writer_locked
= TRUE
;
690 if (lock
->ever_shared
)
692 GThreadXpWaiter
*waiter
= NULL
;
694 EnterCriticalSection (&lock
->atomicity
);
695 if (lock
->num_readers
> 0)
696 lock
->queued_writer
= waiter
= g_thread_xp_waiter_get ();
697 LeaveCriticalSection (&lock
->atomicity
);
700 WaitForSingleObject (waiter
->event
, INFINITE
);
702 lock
->queued_writer
= NULL
;
706 static BOOLEAN __stdcall
707 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex
)
709 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
711 if (!TryEnterCriticalSection (&lock
->writer_lock
))
714 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
715 * Ensure that this properly returns FALSE (as SRWLock would).
717 if G_UNLIKELY (lock
->writer_locked
)
719 LeaveCriticalSection (&lock
->writer_lock
);
723 lock
->writer_locked
= TRUE
;
725 if (lock
->ever_shared
)
729 EnterCriticalSection (&lock
->atomicity
);
730 available
= lock
->num_readers
== 0;
731 LeaveCriticalSection (&lock
->atomicity
);
735 LeaveCriticalSection (&lock
->writer_lock
);
743 static void __stdcall
744 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex
)
746 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
748 lock
->writer_locked
= FALSE
;
750 /* We need this until we fix some weird parts of GLib that try to
751 * unlock freshly-allocated mutexes.
754 LeaveCriticalSection (&lock
->writer_lock
);
758 g_thread_xp_srwlock_become_reader (GThreadSRWLock
*lock
)
760 if G_UNLIKELY (!lock
->ever_shared
)
762 InitializeCriticalSection (&lock
->atomicity
);
763 lock
->queued_writer
= NULL
;
764 lock
->num_readers
= 0;
766 lock
->ever_shared
= TRUE
;
769 EnterCriticalSection (&lock
->atomicity
);
771 LeaveCriticalSection (&lock
->atomicity
);
774 static void __stdcall
775 g_thread_xp_AcquireSRWLockShared (gpointer mutex
)
777 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
779 EnterCriticalSection (&lock
->writer_lock
);
781 /* See g_thread_xp_AcquireSRWLockExclusive */
782 g_assert (!lock
->writer_locked
);
784 g_thread_xp_srwlock_become_reader (lock
);
786 LeaveCriticalSection (&lock
->writer_lock
);
789 static BOOLEAN __stdcall
790 g_thread_xp_TryAcquireSRWLockShared (gpointer mutex
)
792 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
794 if (!TryEnterCriticalSection (&lock
->writer_lock
))
797 /* See g_thread_xp_AcquireSRWLockExclusive */
798 if G_UNLIKELY (lock
->writer_locked
)
800 LeaveCriticalSection (&lock
->writer_lock
);
804 g_thread_xp_srwlock_become_reader (lock
);
806 LeaveCriticalSection (&lock
->writer_lock
);
811 static void __stdcall
812 g_thread_xp_ReleaseSRWLockShared (gpointer mutex
)
814 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
816 EnterCriticalSection (&lock
->atomicity
);
820 if (lock
->num_readers
== 0 && lock
->queued_writer
)
821 SetEvent (lock
->queued_writer
->event
);
823 LeaveCriticalSection (&lock
->atomicity
);
826 /* {{{2 CONDITION_VARIABLE emulation */
829 volatile GThreadXpWaiter
*first
;
830 volatile GThreadXpWaiter
**last_ptr
;
831 } GThreadXpCONDITION_VARIABLE
;
833 static void __stdcall
834 g_thread_xp_InitializeConditionVariable (gpointer cond
)
836 *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
= NULL
;
839 static void __stdcall
840 g_thread_xp_DeleteConditionVariable (gpointer cond
)
842 GThreadXpCONDITION_VARIABLE
*cv
= *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
;
848 static GThreadXpCONDITION_VARIABLE
* __stdcall
849 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE
* volatile *cond
)
851 GThreadXpCONDITION_VARIABLE
*result
;
853 /* It looks like we're missing some barriers here, but this code only
854 * ever runs on Windows XP, which in turn only ever runs on hardware
855 * with a relatively rigid memory model. The 'volatile' will take
856 * care of the compiler.
860 if G_UNLIKELY (result
== NULL
)
862 result
= malloc (sizeof (GThreadXpCONDITION_VARIABLE
));
865 g_thread_abort (errno
, "malloc");
867 result
->first
= NULL
;
868 result
->last_ptr
= &result
->first
;
870 if (InterlockedCompareExchangePointer (cond
, result
, NULL
) != NULL
)
880 static BOOL __stdcall
881 g_thread_xp_SleepConditionVariableSRW (gpointer cond
,
886 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
887 GThreadXpWaiter
*waiter
= g_thread_xp_waiter_get ();
892 EnterCriticalSection (&g_thread_xp_lock
);
893 *cv
->last_ptr
= waiter
;
894 cv
->last_ptr
= &waiter
->next
;
895 LeaveCriticalSection (&g_thread_xp_lock
);
897 g_mutex_unlock (mutex
);
898 status
= WaitForSingleObject (waiter
->event
, timeout
);
900 if (status
!= WAIT_TIMEOUT
&& status
!= WAIT_OBJECT_0
)
901 g_thread_abort (GetLastError (), "WaitForSingleObject");
903 g_mutex_lock (mutex
);
905 return status
== WAIT_OBJECT_0
;
908 static void __stdcall
909 g_thread_xp_WakeConditionVariable (gpointer cond
)
911 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
912 volatile GThreadXpWaiter
*waiter
;
914 EnterCriticalSection (&g_thread_xp_lock
);
918 cv
->first
= waiter
->next
;
919 if (cv
->first
== NULL
)
920 cv
->last_ptr
= &cv
->first
;
922 LeaveCriticalSection (&g_thread_xp_lock
);
925 SetEvent (waiter
->event
);
928 static void __stdcall
929 g_thread_xp_WakeAllConditionVariable (gpointer cond
)
931 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
932 volatile GThreadXpWaiter
*waiter
;
934 EnterCriticalSection (&g_thread_xp_lock
);
937 cv
->last_ptr
= &cv
->first
;
938 LeaveCriticalSection (&g_thread_xp_lock
);
940 while (waiter
!= NULL
)
942 volatile GThreadXpWaiter
*next
;
945 SetEvent (waiter
->event
);
952 g_thread_xp_init (void)
954 static const GThreadImplVtable g_thread_xp_impl_vtable
= {
955 g_thread_xp_CallThisOnThreadExit
,
956 g_thread_xp_InitializeSRWLock
,
957 g_thread_xp_DeleteSRWLock
,
958 g_thread_xp_AcquireSRWLockExclusive
,
959 g_thread_xp_TryAcquireSRWLockExclusive
,
960 g_thread_xp_ReleaseSRWLockExclusive
,
961 g_thread_xp_AcquireSRWLockShared
,
962 g_thread_xp_TryAcquireSRWLockShared
,
963 g_thread_xp_ReleaseSRWLockShared
,
964 g_thread_xp_InitializeConditionVariable
,
965 g_thread_xp_DeleteConditionVariable
,
966 g_thread_xp_SleepConditionVariableSRW
,
967 g_thread_xp_WakeAllConditionVariable
,
968 g_thread_xp_WakeConditionVariable
971 InitializeCriticalSection (&g_thread_xp_lock
);
972 g_thread_xp_waiter_tls
= TlsAlloc ();
974 g_thread_impl_vtable
= g_thread_xp_impl_vtable
;
980 g_thread_lookup_native_funcs (void)
982 GThreadImplVtable native_vtable
= { 0, };
985 kernel32
= GetModuleHandle ("KERNEL32.DLL");
987 if (kernel32
== NULL
)
990 #define GET_FUNC(name) if ((native_vtable.name = (void *) GetProcAddress (kernel32, #name)) == NULL) return FALSE
991 GET_FUNC(InitializeSRWLock
);
992 GET_FUNC(AcquireSRWLockExclusive
);
993 GET_FUNC(TryAcquireSRWLockExclusive
);
994 GET_FUNC(ReleaseSRWLockExclusive
);
995 GET_FUNC(AcquireSRWLockShared
);
996 GET_FUNC(TryAcquireSRWLockShared
);
997 GET_FUNC(ReleaseSRWLockShared
);
999 GET_FUNC(InitializeConditionVariable
);
1000 GET_FUNC(SleepConditionVariableSRW
);
1001 GET_FUNC(WakeAllConditionVariable
);
1002 GET_FUNC(WakeConditionVariable
);
1005 g_thread_impl_vtable
= native_vtable
;
1010 G_GNUC_INTERNAL
void
1011 g_thread_win32_init (void)
1013 if (g_thread_lookup_native_funcs ())
1014 fprintf (stderr
, "(debug) GThread using native mode\n");
1017 fprintf (stderr
, "(debug) GThread using Windows XP mode\n");
1018 g_thread_xp_init ();
1021 win32_check_for_error (TLS_OUT_OF_INDEXES
!= (g_thread_self_tls
= TlsAlloc ()));
1022 InitializeCriticalSection (&g_private_lock
);
1025 G_GNUC_INTERNAL
void
1026 g_thread_win32_thread_detach (void)
1028 GThreadData
*self
= TlsGetValue (g_thread_self_tls
);
1029 gboolean dtors_called
;
1033 GPrivateDestructor
*dtor
;
1035 /* We go by the POSIX book on this one.
1037 * If we call a destructor then there is a chance that some new
1038 * TLS variables got set by code called in that destructor.
1040 * Loop until nothing is left.
1042 dtors_called
= FALSE
;
1044 for (dtor
= g_private_destructors
; dtor
; dtor
= dtor
->next
)
1048 value
= TlsGetValue (dtor
->index
);
1049 if (value
!= NULL
&& dtor
->notify
!= NULL
)
1051 /* POSIX says to clear this before the call */
1052 TlsSetValue (dtor
->index
, NULL
);
1053 dtor
->notify (value
);
1054 dtors_called
= TRUE
;
1058 while (dtors_called
);
1062 if (!self
->joinable
)
1064 win32_check_for_error (CloseHandle (self
->thread
));
1067 win32_check_for_error (TlsSetValue (g_thread_self_tls
, NULL
));
1070 if (g_thread_impl_vtable
.CallThisOnThreadExit
)
1071 g_thread_impl_vtable
.CallThisOnThreadExit ();
1074 /* vim:set foldmethod=marker: */