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
));
499 #define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
502 static void *SetThreadName_VEH_handle
= NULL
;
504 static LONG __stdcall
505 SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo
)
507 if (ExceptionInfo
->ExceptionRecord
!= NULL
&&
508 ExceptionInfo
->ExceptionRecord
->ExceptionCode
== EXCEPTION_SET_THREAD_NAME
)
509 return EXCEPTION_CONTINUE_EXECUTION
;
511 return EXCEPTION_CONTINUE_SEARCH
;
515 typedef struct _THREADNAME_INFO
517 DWORD dwType
; /* must be 0x1000 */
518 LPCSTR szName
; /* pointer to name (in user addr space) */
519 DWORD dwThreadID
; /* thread ID (-1=caller thread) */
520 DWORD dwFlags
; /* reserved for future use, must be zero */
524 SetThreadName (DWORD dwThreadID
,
527 THREADNAME_INFO info
;
530 info
.dwType
= 0x1000;
531 info
.szName
= szThreadName
;
532 info
.dwThreadID
= dwThreadID
;
535 infosize
= sizeof (info
) / sizeof (DWORD
);
540 RaiseException (EXCEPTION_SET_THREAD_NAME
, 0, infosize
, (DWORD
*) &info
);
542 __except (EXCEPTION_EXECUTE_HANDLER
)
546 /* Without a debugger we *must* have an exception handler,
547 * otherwise raising an exception will crash the process.
549 if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle
== NULL
))
552 RaiseException (EXCEPTION_SET_THREAD_NAME
, 0, infosize
, (DWORD
*) &info
);
557 g_system_thread_set_name (const gchar
*name
)
559 SetThreadName ((DWORD
) -1, name
);
562 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
564 static CRITICAL_SECTION g_thread_xp_lock
;
565 static DWORD g_thread_xp_waiter_tls
;
567 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
568 typedef struct _GThreadXpWaiter GThreadXpWaiter
;
569 struct _GThreadXpWaiter
572 volatile GThreadXpWaiter
*next
;
573 volatile GThreadXpWaiter
**my_owner
;
576 static GThreadXpWaiter
*
577 g_thread_xp_waiter_get (void)
579 GThreadXpWaiter
*waiter
;
581 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
583 if G_UNLIKELY (waiter
== NULL
)
585 waiter
= malloc (sizeof (GThreadXpWaiter
));
587 g_thread_abort (GetLastError (), "malloc");
588 waiter
->event
= CreateEvent (0, FALSE
, FALSE
, NULL
);
589 if (waiter
->event
== NULL
)
590 g_thread_abort (GetLastError (), "CreateEvent");
591 waiter
->my_owner
= NULL
;
593 TlsSetValue (g_thread_xp_waiter_tls
, waiter
);
599 static void __stdcall
600 g_thread_xp_CallThisOnThreadExit (void)
602 GThreadXpWaiter
*waiter
;
604 waiter
= TlsGetValue (g_thread_xp_waiter_tls
);
608 TlsSetValue (g_thread_xp_waiter_tls
, NULL
);
609 CloseHandle (waiter
->event
);
614 /* {{{2 SRWLock emulation */
617 CRITICAL_SECTION writer_lock
;
618 gboolean ever_shared
; /* protected by writer_lock */
619 gboolean writer_locked
; /* protected by writer_lock */
621 /* below is only ever touched if ever_shared becomes true */
622 CRITICAL_SECTION atomicity
;
623 GThreadXpWaiter
*queued_writer
; /* protected by atomicity lock */
624 gint num_readers
; /* protected by atomicity lock */
627 static void __stdcall
628 g_thread_xp_InitializeSRWLock (gpointer mutex
)
630 *(GThreadSRWLock
* volatile *) mutex
= NULL
;
633 static void __stdcall
634 g_thread_xp_DeleteSRWLock (gpointer mutex
)
636 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
640 if (lock
->ever_shared
)
641 DeleteCriticalSection (&lock
->atomicity
);
643 DeleteCriticalSection (&lock
->writer_lock
);
648 static GThreadSRWLock
* __stdcall
649 g_thread_xp_get_srwlock (GThreadSRWLock
* volatile *lock
)
651 GThreadSRWLock
*result
;
653 /* It looks like we're missing some barriers here, but this code only
654 * ever runs on Windows XP, which in turn only ever runs on hardware
655 * with a relatively rigid memory model. The 'volatile' will take
656 * care of the compiler.
660 if G_UNLIKELY (result
== NULL
)
662 EnterCriticalSection (&g_thread_xp_lock
);
668 result
= malloc (sizeof (GThreadSRWLock
));
671 g_thread_abort (errno
, "malloc");
673 InitializeCriticalSection (&result
->writer_lock
);
674 result
->writer_locked
= FALSE
;
675 result
->ever_shared
= FALSE
;
679 LeaveCriticalSection (&g_thread_xp_lock
);
685 static void __stdcall
686 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex
)
688 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
690 EnterCriticalSection (&lock
->writer_lock
);
692 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
693 * Detect the deadlock that would occur on later Windows version.
695 g_assert (!lock
->writer_locked
);
696 lock
->writer_locked
= TRUE
;
698 if (lock
->ever_shared
)
700 GThreadXpWaiter
*waiter
= NULL
;
702 EnterCriticalSection (&lock
->atomicity
);
703 if (lock
->num_readers
> 0)
704 lock
->queued_writer
= waiter
= g_thread_xp_waiter_get ();
705 LeaveCriticalSection (&lock
->atomicity
);
708 WaitForSingleObject (waiter
->event
, INFINITE
);
710 lock
->queued_writer
= NULL
;
714 static BOOLEAN __stdcall
715 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex
)
717 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
719 if (!TryEnterCriticalSection (&lock
->writer_lock
))
722 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
723 * Ensure that this properly returns FALSE (as SRWLock would).
725 if G_UNLIKELY (lock
->writer_locked
)
727 LeaveCriticalSection (&lock
->writer_lock
);
731 lock
->writer_locked
= TRUE
;
733 if (lock
->ever_shared
)
737 EnterCriticalSection (&lock
->atomicity
);
738 available
= lock
->num_readers
== 0;
739 LeaveCriticalSection (&lock
->atomicity
);
743 LeaveCriticalSection (&lock
->writer_lock
);
751 static void __stdcall
752 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex
)
754 GThreadSRWLock
*lock
= *(GThreadSRWLock
* volatile *) mutex
;
756 lock
->writer_locked
= FALSE
;
758 /* We need this until we fix some weird parts of GLib that try to
759 * unlock freshly-allocated mutexes.
762 LeaveCriticalSection (&lock
->writer_lock
);
766 g_thread_xp_srwlock_become_reader (GThreadSRWLock
*lock
)
768 if G_UNLIKELY (!lock
->ever_shared
)
770 InitializeCriticalSection (&lock
->atomicity
);
771 lock
->queued_writer
= NULL
;
772 lock
->num_readers
= 0;
774 lock
->ever_shared
= TRUE
;
777 EnterCriticalSection (&lock
->atomicity
);
779 LeaveCriticalSection (&lock
->atomicity
);
782 static void __stdcall
783 g_thread_xp_AcquireSRWLockShared (gpointer mutex
)
785 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
787 EnterCriticalSection (&lock
->writer_lock
);
789 /* See g_thread_xp_AcquireSRWLockExclusive */
790 g_assert (!lock
->writer_locked
);
792 g_thread_xp_srwlock_become_reader (lock
);
794 LeaveCriticalSection (&lock
->writer_lock
);
797 static BOOLEAN __stdcall
798 g_thread_xp_TryAcquireSRWLockShared (gpointer mutex
)
800 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
802 if (!TryEnterCriticalSection (&lock
->writer_lock
))
805 /* See g_thread_xp_AcquireSRWLockExclusive */
806 if G_UNLIKELY (lock
->writer_locked
)
808 LeaveCriticalSection (&lock
->writer_lock
);
812 g_thread_xp_srwlock_become_reader (lock
);
814 LeaveCriticalSection (&lock
->writer_lock
);
819 static void __stdcall
820 g_thread_xp_ReleaseSRWLockShared (gpointer mutex
)
822 GThreadSRWLock
*lock
= g_thread_xp_get_srwlock (mutex
);
824 EnterCriticalSection (&lock
->atomicity
);
828 if (lock
->num_readers
== 0 && lock
->queued_writer
)
829 SetEvent (lock
->queued_writer
->event
);
831 LeaveCriticalSection (&lock
->atomicity
);
834 /* {{{2 CONDITION_VARIABLE emulation */
837 volatile GThreadXpWaiter
*first
;
838 volatile GThreadXpWaiter
**last_ptr
;
839 } GThreadXpCONDITION_VARIABLE
;
841 static void __stdcall
842 g_thread_xp_InitializeConditionVariable (gpointer cond
)
844 *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
= NULL
;
847 static void __stdcall
848 g_thread_xp_DeleteConditionVariable (gpointer cond
)
850 GThreadXpCONDITION_VARIABLE
*cv
= *(GThreadXpCONDITION_VARIABLE
* volatile *) cond
;
856 static GThreadXpCONDITION_VARIABLE
* __stdcall
857 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE
* volatile *cond
)
859 GThreadXpCONDITION_VARIABLE
*result
;
861 /* It looks like we're missing some barriers here, but this code only
862 * ever runs on Windows XP, which in turn only ever runs on hardware
863 * with a relatively rigid memory model. The 'volatile' will take
864 * care of the compiler.
868 if G_UNLIKELY (result
== NULL
)
870 result
= malloc (sizeof (GThreadXpCONDITION_VARIABLE
));
873 g_thread_abort (errno
, "malloc");
875 result
->first
= NULL
;
876 result
->last_ptr
= &result
->first
;
878 if (InterlockedCompareExchangePointer (cond
, result
, NULL
) != NULL
)
888 static BOOL __stdcall
889 g_thread_xp_SleepConditionVariableSRW (gpointer cond
,
894 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
895 GThreadXpWaiter
*waiter
= g_thread_xp_waiter_get ();
900 EnterCriticalSection (&g_thread_xp_lock
);
901 waiter
->my_owner
= cv
->last_ptr
;
902 *cv
->last_ptr
= waiter
;
903 cv
->last_ptr
= &waiter
->next
;
904 LeaveCriticalSection (&g_thread_xp_lock
);
906 g_mutex_unlock (mutex
);
907 status
= WaitForSingleObject (waiter
->event
, timeout
);
909 if (status
!= WAIT_TIMEOUT
&& status
!= WAIT_OBJECT_0
)
910 g_thread_abort (GetLastError (), "WaitForSingleObject");
911 g_mutex_lock (mutex
);
913 if (status
== WAIT_TIMEOUT
)
915 EnterCriticalSection (&g_thread_xp_lock
);
916 if (waiter
->my_owner
)
919 waiter
->next
->my_owner
= waiter
->my_owner
;
921 cv
->last_ptr
= waiter
->my_owner
;
922 *waiter
->my_owner
= waiter
->next
;
923 waiter
->my_owner
= NULL
;
925 LeaveCriticalSection (&g_thread_xp_lock
);
928 return status
== WAIT_OBJECT_0
;
931 static void __stdcall
932 g_thread_xp_WakeConditionVariable (gpointer cond
)
934 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
935 volatile GThreadXpWaiter
*waiter
;
937 EnterCriticalSection (&g_thread_xp_lock
);
942 waiter
->my_owner
= NULL
;
943 cv
->first
= waiter
->next
;
944 if (cv
->first
!= NULL
)
945 cv
->first
->my_owner
= &cv
->first
;
947 cv
->last_ptr
= &cv
->first
;
951 SetEvent (waiter
->event
);
953 LeaveCriticalSection (&g_thread_xp_lock
);
956 static void __stdcall
957 g_thread_xp_WakeAllConditionVariable (gpointer cond
)
959 GThreadXpCONDITION_VARIABLE
*cv
= g_thread_xp_get_condition_variable (cond
);
960 volatile GThreadXpWaiter
*waiter
;
962 EnterCriticalSection (&g_thread_xp_lock
);
966 cv
->last_ptr
= &cv
->first
;
968 while (waiter
!= NULL
)
970 volatile GThreadXpWaiter
*next
;
973 SetEvent (waiter
->event
);
974 waiter
->my_owner
= NULL
;
978 LeaveCriticalSection (&g_thread_xp_lock
);
983 g_thread_xp_init (void)
985 static const GThreadImplVtable g_thread_xp_impl_vtable
= {
986 g_thread_xp_CallThisOnThreadExit
,
987 g_thread_xp_InitializeSRWLock
,
988 g_thread_xp_DeleteSRWLock
,
989 g_thread_xp_AcquireSRWLockExclusive
,
990 g_thread_xp_TryAcquireSRWLockExclusive
,
991 g_thread_xp_ReleaseSRWLockExclusive
,
992 g_thread_xp_AcquireSRWLockShared
,
993 g_thread_xp_TryAcquireSRWLockShared
,
994 g_thread_xp_ReleaseSRWLockShared
,
995 g_thread_xp_InitializeConditionVariable
,
996 g_thread_xp_DeleteConditionVariable
,
997 g_thread_xp_SleepConditionVariableSRW
,
998 g_thread_xp_WakeAllConditionVariable
,
999 g_thread_xp_WakeConditionVariable
1002 InitializeCriticalSection (&g_thread_xp_lock
);
1003 g_thread_xp_waiter_tls
= TlsAlloc ();
1005 g_thread_impl_vtable
= g_thread_xp_impl_vtable
;
1011 g_thread_lookup_native_funcs (void)
1013 GThreadImplVtable native_vtable
= { 0, };
1016 kernel32
= GetModuleHandle ("KERNEL32.DLL");
1018 if (kernel32
== NULL
)
1021 #define GET_FUNC(name) if ((native_vtable.name = (void *) GetProcAddress (kernel32, #name)) == NULL) return FALSE
1022 GET_FUNC(InitializeSRWLock
);
1023 GET_FUNC(AcquireSRWLockExclusive
);
1024 GET_FUNC(TryAcquireSRWLockExclusive
);
1025 GET_FUNC(ReleaseSRWLockExclusive
);
1026 GET_FUNC(AcquireSRWLockShared
);
1027 GET_FUNC(TryAcquireSRWLockShared
);
1028 GET_FUNC(ReleaseSRWLockShared
);
1030 GET_FUNC(InitializeConditionVariable
);
1031 GET_FUNC(SleepConditionVariableSRW
);
1032 GET_FUNC(WakeAllConditionVariable
);
1033 GET_FUNC(WakeConditionVariable
);
1036 g_thread_impl_vtable
= native_vtable
;
1042 g_thread_win32_init (void)
1044 if (!g_thread_lookup_native_funcs ())
1045 g_thread_xp_init ();
1047 InitializeCriticalSection (&g_private_lock
);
1050 SetThreadName_VEH_handle
= AddVectoredExceptionHandler (1, &SetThreadName_VEH
);
1051 if (SetThreadName_VEH_handle
== NULL
)
1053 /* This is bad, but what can we do? */
1059 g_thread_win32_thread_detach (void)
1061 gboolean dtors_called
;
1065 GPrivateDestructor
*dtor
;
1067 /* We go by the POSIX book on this one.
1069 * If we call a destructor then there is a chance that some new
1070 * TLS variables got set by code called in that destructor.
1072 * Loop until nothing is left.
1074 dtors_called
= FALSE
;
1076 for (dtor
= g_private_destructors
; dtor
; dtor
= dtor
->next
)
1080 value
= TlsGetValue (dtor
->index
);
1081 if (value
!= NULL
&& dtor
->notify
!= NULL
)
1083 /* POSIX says to clear this before the call */
1084 TlsSetValue (dtor
->index
, NULL
);
1085 dtor
->notify (value
);
1086 dtors_called
= TRUE
;
1090 while (dtors_called
);
1092 if (g_thread_impl_vtable
.CallThisOnThreadExit
)
1093 g_thread_impl_vtable
.CallThisOnThreadExit ();
1097 g_thread_win32_process_detach (void)
1100 if (SetThreadName_VEH_handle
!= NULL
)
1102 RemoveVectoredExceptionHandler (SetThreadName_VEH_handle
);
1103 SetThreadName_VEH_handle
= NULL
;
1108 /* vim:set foldmethod=marker: */