nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * gthread.c: solaris thread system implementation
5 * Copyright 1998-2001 Sebastian Wilhelmi; University of Karlsruhe
6 * Copyright 2001 Hans Breuer
7 *
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.
12 *
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.
17 *
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/>.
20 */
21  
22 /*
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/.
27 */
28  
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.
33 *
34 * As such, these functions are NOT permitted to call any other part of
35 * GLib.
36 *
37 * The thread manipulation functions (create, exit, join, etc.) have
38 * more freedom -- they can do as they please.
39 */
40  
41 #include "config.h"
42  
43 #include "glib.h"
44 #include "glib-init.h"
45 #include "gthread.h"
46 #include "gthreadprivate.h"
47 #include "gslice.h"
48  
49 #include <windows.h>
50  
51 #include <process.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54  
55 static void
56 g_thread_abort (gint status,
57 const gchar *function)
58 {
59 fprintf (stderr, "GLib (gthread-win32.c): Unexpected error from C library during '%s': %s. Aborting.\n",
60 strerror (status), function);
61 abort ();
62 }
63  
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).
68 *
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.
76 *
77 * Unfortunately, Windows XP lacks these facilities and GLib still
78 * needs to support Windows XP. Our approach here is as follows:
79 *
80 * - avoid depending on structure declarations at compile-time by
81 * declaring our own GMutex and GCond strutures to be
82 * ABI-compatible with SRWLock and CONDITION_VARIABLE and using
83 * those instead
84 *
85 * - avoid a hard dependency on the symbols used to manipulate these
86 * structures by doing a dynamic lookup of those symbols at
87 * runtime
88 *
89 * - if the symbols are not available, emulate them using other
90 * primatives
91 *
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).
95 */
96 typedef struct
97 {
98 void (__stdcall * CallThisOnThreadExit) (void); /* fake */
99  
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);
108  
109 void (__stdcall * InitializeConditionVariable) (gpointer cond);
110 void (__stdcall * DeleteConditionVariable) (gpointer cond); /* fake */
111 BOOL (__stdcall * SleepConditionVariableSRW) (gpointer cond,
112 gpointer lock,
113 DWORD timeout,
114 ULONG flags);
115 void (__stdcall * WakeAllConditionVariable) (gpointer cond);
116 void (__stdcall * WakeConditionVariable) (gpointer cond);
117 } GThreadImplVtable;
118  
119 static GThreadImplVtable g_thread_impl_vtable;
120  
121 /* {{{1 GMutex */
122 void
123 g_mutex_init (GMutex *mutex)
124 {
125 g_thread_impl_vtable.InitializeSRWLock (mutex);
126 }
127  
128 void
129 g_mutex_clear (GMutex *mutex)
130 {
131 if (g_thread_impl_vtable.DeleteSRWLock != NULL)
132 g_thread_impl_vtable.DeleteSRWLock (mutex);
133 }
134  
135 void
136 g_mutex_lock (GMutex *mutex)
137 {
138 g_thread_impl_vtable.AcquireSRWLockExclusive (mutex);
139 }
140  
141 gboolean
142 g_mutex_trylock (GMutex *mutex)
143 {
144 return g_thread_impl_vtable.TryAcquireSRWLockExclusive (mutex);
145 }
146  
147 void
148 g_mutex_unlock (GMutex *mutex)
149 {
150 g_thread_impl_vtable.ReleaseSRWLockExclusive (mutex);
151 }
152  
153 /* {{{1 GRecMutex */
154  
155 static CRITICAL_SECTION *
156 g_rec_mutex_impl_new (void)
157 {
158 CRITICAL_SECTION *cs;
159  
160 cs = g_slice_new (CRITICAL_SECTION);
161 InitializeCriticalSection (cs);
162  
163 return cs;
164 }
165  
166 static void
167 g_rec_mutex_impl_free (CRITICAL_SECTION *cs)
168 {
169 DeleteCriticalSection (cs);
170 g_slice_free (CRITICAL_SECTION, cs);
171 }
172  
173 static CRITICAL_SECTION *
174 g_rec_mutex_get_impl (GRecMutex *mutex)
175 {
176 CRITICAL_SECTION *impl = mutex->p;
177  
178 if G_UNLIKELY (mutex->p == NULL)
179 {
180 impl = g_rec_mutex_impl_new ();
181 if (InterlockedCompareExchangePointer (&mutex->p, impl, NULL) != NULL)
182 g_rec_mutex_impl_free (impl);
183 impl = mutex->p;
184 }
185  
186 return impl;
187 }
188  
189 void
190 g_rec_mutex_init (GRecMutex *mutex)
191 {
192 mutex->p = g_rec_mutex_impl_new ();
193 }
194  
195 void
196 g_rec_mutex_clear (GRecMutex *mutex)
197 {
198 g_rec_mutex_impl_free (mutex->p);
199 }
200  
201 void
202 g_rec_mutex_lock (GRecMutex *mutex)
203 {
204 EnterCriticalSection (g_rec_mutex_get_impl (mutex));
205 }
206  
207 void
208 g_rec_mutex_unlock (GRecMutex *mutex)
209 {
210 LeaveCriticalSection (mutex->p);
211 }
212  
213 gboolean
214 g_rec_mutex_trylock (GRecMutex *mutex)
215 {
216 return TryEnterCriticalSection (g_rec_mutex_get_impl (mutex));
217 }
218  
219 /* {{{1 GRWLock */
220  
221 void
222 g_rw_lock_init (GRWLock *lock)
223 {
224 g_thread_impl_vtable.InitializeSRWLock (lock);
225 }
226  
227 void
228 g_rw_lock_clear (GRWLock *lock)
229 {
230 if (g_thread_impl_vtable.DeleteSRWLock != NULL)
231 g_thread_impl_vtable.DeleteSRWLock (lock);
232 }
233  
234 void
235 g_rw_lock_writer_lock (GRWLock *lock)
236 {
237 g_thread_impl_vtable.AcquireSRWLockExclusive (lock);
238 }
239  
240 gboolean
241 g_rw_lock_writer_trylock (GRWLock *lock)
242 {
243 return g_thread_impl_vtable.TryAcquireSRWLockExclusive (lock);
244 }
245  
246 void
247 g_rw_lock_writer_unlock (GRWLock *lock)
248 {
249 g_thread_impl_vtable.ReleaseSRWLockExclusive (lock);
250 }
251  
252 void
253 g_rw_lock_reader_lock (GRWLock *lock)
254 {
255 g_thread_impl_vtable.AcquireSRWLockShared (lock);
256 }
257  
258 gboolean
259 g_rw_lock_reader_trylock (GRWLock *lock)
260 {
261 return g_thread_impl_vtable.TryAcquireSRWLockShared (lock);
262 }
263  
264 void
265 g_rw_lock_reader_unlock (GRWLock *lock)
266 {
267 g_thread_impl_vtable.ReleaseSRWLockShared (lock);
268 }
269  
270 /* {{{1 GCond */
271 void
272 g_cond_init (GCond *cond)
273 {
274 g_thread_impl_vtable.InitializeConditionVariable (cond);
275 }
276  
277 void
278 g_cond_clear (GCond *cond)
279 {
280 if (g_thread_impl_vtable.DeleteConditionVariable)
281 g_thread_impl_vtable.DeleteConditionVariable (cond);
282 }
283  
284 void
285 g_cond_signal (GCond *cond)
286 {
287 g_thread_impl_vtable.WakeConditionVariable (cond);
288 }
289  
290 void
291 g_cond_broadcast (GCond *cond)
292 {
293 g_thread_impl_vtable.WakeAllConditionVariable (cond);
294 }
295  
296 void
297 g_cond_wait (GCond *cond,
298 GMutex *entered_mutex)
299 {
300 g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, INFINITE, 0);
301 }
302  
303 gboolean
304 g_cond_wait_until (GCond *cond,
305 GMutex *entered_mutex,
306 gint64 end_time)
307 {
308 gint64 span;
309  
310 span = end_time - g_get_monotonic_time ();
311  
312 if G_UNLIKELY (span < 0)
313 span = 0;
314  
315 if G_UNLIKELY (span > G_GINT64_CONSTANT (1000) * G_MAXINT32)
316 span = INFINITE;
317  
318 return g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, span / 1000, 0);
319 }
320  
321 /* {{{1 GPrivate */
322  
323 typedef struct _GPrivateDestructor GPrivateDestructor;
324  
325 struct _GPrivateDestructor
326 {
327 DWORD index;
328 GDestroyNotify notify;
329 GPrivateDestructor *next;
330 };
331  
332 static GPrivateDestructor * volatile g_private_destructors;
333 static CRITICAL_SECTION g_private_lock;
334  
335 static DWORD
336 g_private_get_impl (GPrivate *key)
337 {
338 DWORD impl = (DWORD) key->p;
339  
340 if G_UNLIKELY (impl == 0)
341 {
342 EnterCriticalSection (&g_private_lock);
343 impl = (DWORD) key->p;
344 if (impl == 0)
345 {
346 GPrivateDestructor *destructor;
347  
348 impl = TlsAlloc ();
349  
350 if (impl == TLS_OUT_OF_INDEXES)
351 g_thread_abort (0, "TlsAlloc");
352  
353 if (key->notify != NULL)
354 {
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;
361  
362 /* We need to do an atomic store due to the unlocked
363 * access to the destructor list from the thread exit
364 * function.
365 *
366 * It can double as a sanity check...
367 */
368 if (InterlockedCompareExchangePointer (&g_private_destructors, destructor,
369 destructor->next) != destructor->next)
370 g_thread_abort (0, "g_private_get_impl(1)");
371 }
372  
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)");
376 }
377 LeaveCriticalSection (&g_private_lock);
378 }
379  
380 return impl;
381 }
382  
383 gpointer
384 g_private_get (GPrivate *key)
385 {
386 return TlsGetValue (g_private_get_impl (key));
387 }
388  
389 void
390 g_private_set (GPrivate *key,
391 gpointer value)
392 {
393 TlsSetValue (g_private_get_impl (key), value);
394 }
395  
396 void
397 g_private_replace (GPrivate *key,
398 gpointer value)
399 {
400 DWORD impl = g_private_get_impl (key);
401 gpointer old;
402  
403 old = TlsGetValue (impl);
404 if (old && key->notify)
405 key->notify (old);
406 TlsSetValue (impl, value);
407 }
408  
409 /* {{{1 GThread */
410  
411 #define win32_check_for_error(what) G_STMT_START{ \
412 if (!(what)) \
413 g_error ("file %s: line %d (%s): error %s during %s", \
414 __FILE__, __LINE__, G_STRFUNC, \
415 g_win32_error_message (GetLastError ()), #what); \
416 }G_STMT_END
417  
418 #define G_MUTEX_SIZE (sizeof (gpointer))
419  
420 typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *);
421  
422 typedef struct
423 {
424 GRealThread thread;
425  
426 GThreadFunc proxy;
427 HANDLE handle;
428 } GThreadWin32;
429  
430 void
431 g_system_thread_free (GRealThread *thread)
432 {
433 GThreadWin32 *wt = (GThreadWin32 *) thread;
434  
435 win32_check_for_error (CloseHandle (wt->handle));
436 g_slice_free (GThreadWin32, wt);
437 }
438  
439 void
440 g_system_thread_exit (void)
441 {
442 _endthreadex (0);
443 }
444  
445 static guint __stdcall
446 g_thread_win32_proxy (gpointer data)
447 {
448 GThreadWin32 *self = data;
449  
450 self->proxy (self);
451  
452 g_system_thread_exit ();
453  
454 g_assert_not_reached ();
455  
456 return 0;
457 }
458  
459 GRealThread *
460 g_system_thread_new (GThreadFunc func,
461 gulong stack_size,
462 GError **error)
463 {
464 GThreadWin32 *thread;
465 guint ignore;
466  
467 thread = g_slice_new0 (GThreadWin32);
468 thread->proxy = func;
469  
470 thread->handle = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_win32_proxy, thread, 0, &ignore);
471  
472 if (thread->handle == NULL)
473 {
474 gchar *win_error = g_win32_error_message (GetLastError ());
475 g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
476 "Error creating thread: %s", win_error);
477 g_free (win_error);
478 g_slice_free (GThreadWin32, thread);
479 return NULL;
480 }
481  
482 return (GRealThread *) thread;
483 }
484  
485 void
486 g_thread_yield (void)
487 {
488 Sleep(0);
489 }
490  
491 void
492 g_system_thread_wait (GRealThread *thread)
493 {
494 GThreadWin32 *wt = (GThreadWin32 *) thread;
495  
496 win32_check_for_error (WAIT_FAILED != WaitForSingleObject (wt->handle, INFINITE));
497 }
498  
499 #define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
500  
501 #ifndef _MSC_VER
502 static void *SetThreadName_VEH_handle = NULL;
503  
504 static LONG __stdcall
505 SetThreadName_VEH (PEXCEPTION_POINTERS ExceptionInfo)
506 {
507 if (ExceptionInfo->ExceptionRecord != NULL &&
508 ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME)
509 return EXCEPTION_CONTINUE_EXECUTION;
510  
511 return EXCEPTION_CONTINUE_SEARCH;
512 }
513 #endif
514  
515 typedef struct _THREADNAME_INFO
516 {
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 */
521 } THREADNAME_INFO;
522  
523 static void
524 SetThreadName (DWORD dwThreadID,
525 LPCSTR szThreadName)
526 {
527 THREADNAME_INFO info;
528 DWORD infosize;
529  
530 info.dwType = 0x1000;
531 info.szName = szThreadName;
532 info.dwThreadID = dwThreadID;
533 info.dwFlags = 0;
534  
535 infosize = sizeof (info) / sizeof (DWORD);
536  
537 #ifdef _MSC_VER
538 __try
539 {
540 RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
541 }
542 __except (EXCEPTION_EXECUTE_HANDLER)
543 {
544 }
545 #else
546 /* Without a debugger we *must* have an exception handler,
547 * otherwise raising an exception will crash the process.
548 */
549 if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL))
550 return;
551  
552 RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *) &info);
553 #endif
554 }
555  
556 void
557 g_system_thread_set_name (const gchar *name)
558 {
559 SetThreadName ((DWORD) -1, name);
560 }
561  
562 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
563  
564 static CRITICAL_SECTION g_thread_xp_lock;
565 static DWORD g_thread_xp_waiter_tls;
566  
567 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
568 typedef struct _GThreadXpWaiter GThreadXpWaiter;
569 struct _GThreadXpWaiter
570 {
571 HANDLE event;
572 volatile GThreadXpWaiter *next;
573 volatile GThreadXpWaiter **my_owner;
574 };
575  
576 static GThreadXpWaiter *
577 g_thread_xp_waiter_get (void)
578 {
579 GThreadXpWaiter *waiter;
580  
581 waiter = TlsGetValue (g_thread_xp_waiter_tls);
582  
583 if G_UNLIKELY (waiter == NULL)
584 {
585 waiter = malloc (sizeof (GThreadXpWaiter));
586 if (waiter == NULL)
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;
592  
593 TlsSetValue (g_thread_xp_waiter_tls, waiter);
594 }
595  
596 return waiter;
597 }
598  
599 static void __stdcall
600 g_thread_xp_CallThisOnThreadExit (void)
601 {
602 GThreadXpWaiter *waiter;
603  
604 waiter = TlsGetValue (g_thread_xp_waiter_tls);
605  
606 if (waiter != NULL)
607 {
608 TlsSetValue (g_thread_xp_waiter_tls, NULL);
609 CloseHandle (waiter->event);
610 free (waiter);
611 }
612 }
613  
614 /* {{{2 SRWLock emulation */
615 typedef struct
616 {
617 CRITICAL_SECTION writer_lock;
618 gboolean ever_shared; /* protected by writer_lock */
619 gboolean writer_locked; /* protected by writer_lock */
620  
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 */
625 } GThreadSRWLock;
626  
627 static void __stdcall
628 g_thread_xp_InitializeSRWLock (gpointer mutex)
629 {
630 *(GThreadSRWLock * volatile *) mutex = NULL;
631 }
632  
633 static void __stdcall
634 g_thread_xp_DeleteSRWLock (gpointer mutex)
635 {
636 GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
637  
638 if (lock)
639 {
640 if (lock->ever_shared)
641 DeleteCriticalSection (&lock->atomicity);
642  
643 DeleteCriticalSection (&lock->writer_lock);
644 free (lock);
645 }
646 }
647  
648 static GThreadSRWLock * __stdcall
649 g_thread_xp_get_srwlock (GThreadSRWLock * volatile *lock)
650 {
651 GThreadSRWLock *result;
652  
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.
657 */
658 result = *lock;
659  
660 if G_UNLIKELY (result == NULL)
661 {
662 EnterCriticalSection (&g_thread_xp_lock);
663  
664 /* Check again */
665 result = *lock;
666 if (result == NULL)
667 {
668 result = malloc (sizeof (GThreadSRWLock));
669  
670 if (result == NULL)
671 g_thread_abort (errno, "malloc");
672  
673 InitializeCriticalSection (&result->writer_lock);
674 result->writer_locked = FALSE;
675 result->ever_shared = FALSE;
676 *lock = result;
677 }
678  
679 LeaveCriticalSection (&g_thread_xp_lock);
680 }
681  
682 return result;
683 }
684  
685 static void __stdcall
686 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex)
687 {
688 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
689  
690 EnterCriticalSection (&lock->writer_lock);
691  
692 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
693 * Detect the deadlock that would occur on later Windows version.
694 */
695 g_assert (!lock->writer_locked);
696 lock->writer_locked = TRUE;
697  
698 if (lock->ever_shared)
699 {
700 GThreadXpWaiter *waiter = NULL;
701  
702 EnterCriticalSection (&lock->atomicity);
703 if (lock->num_readers > 0)
704 lock->queued_writer = waiter = g_thread_xp_waiter_get ();
705 LeaveCriticalSection (&lock->atomicity);
706  
707 if (waiter != NULL)
708 WaitForSingleObject (waiter->event, INFINITE);
709  
710 lock->queued_writer = NULL;
711 }
712 }
713  
714 static BOOLEAN __stdcall
715 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex)
716 {
717 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
718  
719 if (!TryEnterCriticalSection (&lock->writer_lock))
720 return FALSE;
721  
722 /* CRITICAL_SECTION is reentrant, but SRWLock is not.
723 * Ensure that this properly returns FALSE (as SRWLock would).
724 */
725 if G_UNLIKELY (lock->writer_locked)
726 {
727 LeaveCriticalSection (&lock->writer_lock);
728 return FALSE;
729 }
730  
731 lock->writer_locked = TRUE;
732  
733 if (lock->ever_shared)
734 {
735 gboolean available;
736  
737 EnterCriticalSection (&lock->atomicity);
738 available = lock->num_readers == 0;
739 LeaveCriticalSection (&lock->atomicity);
740  
741 if (!available)
742 {
743 LeaveCriticalSection (&lock->writer_lock);
744 return FALSE;
745 }
746 }
747  
748 return TRUE;
749 }
750  
751 static void __stdcall
752 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex)
753 {
754 GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
755  
756 lock->writer_locked = FALSE;
757  
758 /* We need this until we fix some weird parts of GLib that try to
759 * unlock freshly-allocated mutexes.
760 */
761 if (lock != NULL)
762 LeaveCriticalSection (&lock->writer_lock);
763 }
764  
765 static void
766 g_thread_xp_srwlock_become_reader (GThreadSRWLock *lock)
767 {
768 if G_UNLIKELY (!lock->ever_shared)
769 {
770 InitializeCriticalSection (&lock->atomicity);
771 lock->queued_writer = NULL;
772 lock->num_readers = 0;
773  
774 lock->ever_shared = TRUE;
775 }
776  
777 EnterCriticalSection (&lock->atomicity);
778 lock->num_readers++;
779 LeaveCriticalSection (&lock->atomicity);
780 }
781  
782 static void __stdcall
783 g_thread_xp_AcquireSRWLockShared (gpointer mutex)
784 {
785 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
786  
787 EnterCriticalSection (&lock->writer_lock);
788  
789 /* See g_thread_xp_AcquireSRWLockExclusive */
790 g_assert (!lock->writer_locked);
791  
792 g_thread_xp_srwlock_become_reader (lock);
793  
794 LeaveCriticalSection (&lock->writer_lock);
795 }
796  
797 static BOOLEAN __stdcall
798 g_thread_xp_TryAcquireSRWLockShared (gpointer mutex)
799 {
800 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
801  
802 if (!TryEnterCriticalSection (&lock->writer_lock))
803 return FALSE;
804  
805 /* See g_thread_xp_AcquireSRWLockExclusive */
806 if G_UNLIKELY (lock->writer_locked)
807 {
808 LeaveCriticalSection (&lock->writer_lock);
809 return FALSE;
810 }
811  
812 g_thread_xp_srwlock_become_reader (lock);
813  
814 LeaveCriticalSection (&lock->writer_lock);
815  
816 return TRUE;
817 }
818  
819 static void __stdcall
820 g_thread_xp_ReleaseSRWLockShared (gpointer mutex)
821 {
822 GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
823  
824 EnterCriticalSection (&lock->atomicity);
825  
826 lock->num_readers--;
827  
828 if (lock->num_readers == 0 && lock->queued_writer)
829 SetEvent (lock->queued_writer->event);
830  
831 LeaveCriticalSection (&lock->atomicity);
832 }
833  
834 /* {{{2 CONDITION_VARIABLE emulation */
835 typedef struct
836 {
837 volatile GThreadXpWaiter *first;
838 volatile GThreadXpWaiter **last_ptr;
839 } GThreadXpCONDITION_VARIABLE;
840  
841 static void __stdcall
842 g_thread_xp_InitializeConditionVariable (gpointer cond)
843 {
844 *(GThreadXpCONDITION_VARIABLE * volatile *) cond = NULL;
845 }
846  
847 static void __stdcall
848 g_thread_xp_DeleteConditionVariable (gpointer cond)
849 {
850 GThreadXpCONDITION_VARIABLE *cv = *(GThreadXpCONDITION_VARIABLE * volatile *) cond;
851  
852 if (cv)
853 free (cv);
854 }
855  
856 static GThreadXpCONDITION_VARIABLE * __stdcall
857 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE * volatile *cond)
858 {
859 GThreadXpCONDITION_VARIABLE *result;
860  
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.
865 */
866 result = *cond;
867  
868 if G_UNLIKELY (result == NULL)
869 {
870 result = malloc (sizeof (GThreadXpCONDITION_VARIABLE));
871  
872 if (result == NULL)
873 g_thread_abort (errno, "malloc");
874  
875 result->first = NULL;
876 result->last_ptr = &result->first;
877  
878 if (InterlockedCompareExchangePointer (cond, result, NULL) != NULL)
879 {
880 free (result);
881 result = *cond;
882 }
883 }
884  
885 return result;
886 }
887  
888 static BOOL __stdcall
889 g_thread_xp_SleepConditionVariableSRW (gpointer cond,
890 gpointer mutex,
891 DWORD timeout,
892 ULONG flags)
893 {
894 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
895 GThreadXpWaiter *waiter = g_thread_xp_waiter_get ();
896 DWORD status;
897  
898 waiter->next = NULL;
899  
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);
905  
906 g_mutex_unlock (mutex);
907 status = WaitForSingleObject (waiter->event, timeout);
908  
909 if (status != WAIT_TIMEOUT && status != WAIT_OBJECT_0)
910 g_thread_abort (GetLastError (), "WaitForSingleObject");
911 g_mutex_lock (mutex);
912  
913 if (status == WAIT_TIMEOUT)
914 {
915 EnterCriticalSection (&g_thread_xp_lock);
916 if (waiter->my_owner)
917 {
918 if (waiter->next)
919 waiter->next->my_owner = waiter->my_owner;
920 else
921 cv->last_ptr = waiter->my_owner;
922 *waiter->my_owner = waiter->next;
923 waiter->my_owner = NULL;
924 }
925 LeaveCriticalSection (&g_thread_xp_lock);
926 }
927  
928 return status == WAIT_OBJECT_0;
929 }
930  
931 static void __stdcall
932 g_thread_xp_WakeConditionVariable (gpointer cond)
933 {
934 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
935 volatile GThreadXpWaiter *waiter;
936  
937 EnterCriticalSection (&g_thread_xp_lock);
938  
939 waiter = cv->first;
940 if (waiter != NULL)
941 {
942 waiter->my_owner = NULL;
943 cv->first = waiter->next;
944 if (cv->first != NULL)
945 cv->first->my_owner = &cv->first;
946 else
947 cv->last_ptr = &cv->first;
948 }
949  
950 if (waiter != NULL)
951 SetEvent (waiter->event);
952  
953 LeaveCriticalSection (&g_thread_xp_lock);
954 }
955  
956 static void __stdcall
957 g_thread_xp_WakeAllConditionVariable (gpointer cond)
958 {
959 GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
960 volatile GThreadXpWaiter *waiter;
961  
962 EnterCriticalSection (&g_thread_xp_lock);
963  
964 waiter = cv->first;
965 cv->first = NULL;
966 cv->last_ptr = &cv->first;
967  
968 while (waiter != NULL)
969 {
970 volatile GThreadXpWaiter *next;
971  
972 next = waiter->next;
973 SetEvent (waiter->event);
974 waiter->my_owner = NULL;
975 waiter = next;
976 }
977  
978 LeaveCriticalSection (&g_thread_xp_lock);
979 }
980  
981 /* {{{2 XP Setup */
982 static void
983 g_thread_xp_init (void)
984 {
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
1000 };
1001  
1002 InitializeCriticalSection (&g_thread_xp_lock);
1003 g_thread_xp_waiter_tls = TlsAlloc ();
1004  
1005 g_thread_impl_vtable = g_thread_xp_impl_vtable;
1006 }
1007  
1008 /* {{{1 Epilogue */
1009  
1010 static gboolean
1011 g_thread_lookup_native_funcs (void)
1012 {
1013 GThreadImplVtable native_vtable = { 0, };
1014 HMODULE kernel32;
1015  
1016 kernel32 = GetModuleHandle ("KERNEL32.DLL");
1017  
1018 if (kernel32 == NULL)
1019 return FALSE;
1020  
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);
1029  
1030 GET_FUNC(InitializeConditionVariable);
1031 GET_FUNC(SleepConditionVariableSRW);
1032 GET_FUNC(WakeAllConditionVariable);
1033 GET_FUNC(WakeConditionVariable);
1034 #undef GET_FUNC
1035  
1036 g_thread_impl_vtable = native_vtable;
1037  
1038 return TRUE;
1039 }
1040  
1041 void
1042 g_thread_win32_init (void)
1043 {
1044 if (!g_thread_lookup_native_funcs ())
1045 g_thread_xp_init ();
1046  
1047 InitializeCriticalSection (&g_private_lock);
1048  
1049 #ifndef _MSC_VER
1050 SetThreadName_VEH_handle = AddVectoredExceptionHandler (1, &SetThreadName_VEH);
1051 if (SetThreadName_VEH_handle == NULL)
1052 {
1053 /* This is bad, but what can we do? */
1054 }
1055 #endif
1056 }
1057  
1058 void
1059 g_thread_win32_thread_detach (void)
1060 {
1061 gboolean dtors_called;
1062  
1063 do
1064 {
1065 GPrivateDestructor *dtor;
1066  
1067 /* We go by the POSIX book on this one.
1068 *
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.
1071 *
1072 * Loop until nothing is left.
1073 */
1074 dtors_called = FALSE;
1075  
1076 for (dtor = g_private_destructors; dtor; dtor = dtor->next)
1077 {
1078 gpointer value;
1079  
1080 value = TlsGetValue (dtor->index);
1081 if (value != NULL && dtor->notify != NULL)
1082 {
1083 /* POSIX says to clear this before the call */
1084 TlsSetValue (dtor->index, NULL);
1085 dtor->notify (value);
1086 dtors_called = TRUE;
1087 }
1088 }
1089 }
1090 while (dtors_called);
1091  
1092 if (g_thread_impl_vtable.CallThisOnThreadExit)
1093 g_thread_impl_vtable.CallThisOnThreadExit ();
1094 }
1095  
1096 void
1097 g_thread_win32_process_detach (void)
1098 {
1099 #ifndef _MSC_VER
1100 if (SetThreadName_VEH_handle != NULL)
1101 {
1102 RemoveVectoredExceptionHandler (SetThreadName_VEH_handle);
1103 SetThreadName_VEH_handle = NULL;
1104 }
1105 #endif
1106 }
1107  
1108 /* vim:set foldmethod=marker: */