Remove "temporary until GLib is fixed" code
[platform/upstream/glib.git] / glib / gthread-win32.c
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, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /*
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/.
29  */
30
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.
35  *
36  * As such, these functions are NOT permitted to call any other part of
37  * GLib.
38  *
39  * The thread manipulation functions (create, exit, join, etc.) have
40  * more freedom -- they can do as they please.
41  */
42
43 #include "config.h"
44
45 #include "gthread.h"
46
47 #define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
48 #include <windows.h>
49
50 #include <process.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53
54 static void
55 g_thread_abort (gint         status,
56                 const gchar *function)
57 {
58   fprintf (stderr, "GLib (gthread-win32.c): Unexpected error from C library during '%s': %s.  Aborting.\n",
59            strerror (status), function);
60   abort ();
61 }
62
63 /* Starting with Vista and Windows 2008, we have access to the
64  * CONDITION_VARIABLE and SRWLock primatives on Windows, which are
65  * pretty reasonable approximations of the primatives specified in
66  * POSIX 2001 (pthread_cond_t and pthread_mutex_t respectively).
67  *
68  * Both of these types are structs containing a single pointer.  That
69  * pointer is used as an atomic bitfield to support user-space mutexes
70  * that only get the kernel involved in cases of contention (similar
71  * to how futex()-based mutexes work on Linux).  The biggest advantage
72  * of these new types is that they can be statically initialised to
73  * zero.  This allows us to use them directly and still support:
74  *
75  *   GMutex mutex = G_MUTEX_INIT;
76  *
77  * and
78  *
79  *   GCond cond = G_COND_INIT;
80  *
81  * Unfortunately, Windows XP lacks these facilities and GLib still
82  * needs to support Windows XP.  Our approach here is as follows:
83  *
84  *   - avoid depending on structure declarations at compile-time by
85  *     declaring our own GMutex and GCond strutures to be
86  *     ABI-compatible with SRWLock and CONDITION_VARIABLE and using
87  *     those instead
88  *
89  *   - avoid a hard dependency on the symbols used to manipulate these
90  *     structures by doing a dynamic lookup of those symbols at
91  *     runtime
92  *
93  *   - if the symbols are not available, emulate them using other
94  *     primatives
95  *
96  * Using this approach also allows us to easily build a GLib that lacks
97  * support for Windows XP or to remove this code entirely when XP is no
98  * longer supported (end of line is currently April 8, 2014).
99  */
100 typedef struct
101 {
102   void     (* CallThisOnThreadExit)        (void);              /* fake */
103
104   void     (* InitializeSRWLock)           (gpointer lock);
105   void     (* DeleteSRWLock)               (gpointer lock);     /* fake */
106   void     (* AcquireSRWLockExclusive)     (gpointer lock);
107   BOOLEAN  (* TryAcquireSRWLockExclusive)  (gpointer lock);
108   void     (* ReleaseSRWLockExclusive)     (gpointer lock);
109
110   void     (* InitializeConditionVariable) (gpointer cond);
111   void     (* DeleteConditionVariable)     (gpointer cond);     /* fake */
112   BOOL     (* SleepConditionVariableSRW)   (gpointer cond,
113                                             gpointer lock,
114                                             DWORD    timeout,
115                                             ULONG    flags);
116   void     (* WakeAllConditionVariable)    (gpointer cond);
117   void     (* WakeConditionVariable)       (gpointer cond);
118 } GThreadImplVtable;
119
120 static GThreadImplVtable g_thread_impl_vtable;
121
122 /* {{{1 GMutex */
123 void
124 g_mutex_init (GMutex *mutex)
125 {
126   g_thread_impl_vtable.InitializeSRWLock (mutex);
127 }
128
129 void
130 g_mutex_clear (GMutex *mutex)
131 {
132   if (g_thread_impl_vtable.DeleteSRWLock != NULL)
133     g_thread_impl_vtable.DeleteSRWLock (mutex);
134 }
135
136 void
137 g_mutex_lock (GMutex *mutex)
138 {
139   g_thread_impl_vtable.AcquireSRWLockExclusive (mutex);
140 }
141
142 gboolean
143 g_mutex_trylock (GMutex *mutex)
144 {
145   return g_thread_impl_vtable.TryAcquireSRWLockExclusive (mutex);
146 }
147
148 void
149 g_mutex_unlock (GMutex *mutex)
150 {
151   g_thread_impl_vtable.ReleaseSRWLockExclusive (mutex);
152 }
153
154 /* {{{1 GCond */
155 void
156 g_cond_init (GCond *cond)
157 {
158   g_thread_impl_vtable.InitializeConditionVariable (cond);
159 }
160
161 void
162 g_cond_clear (GCond *cond)
163 {
164   if (g_thread_impl_vtable.DeleteConditionVariable)
165     g_thread_impl_vtable.DeleteConditionVariable (cond);
166 }
167
168 void
169 g_cond_signal (GCond *cond)
170 {
171   g_thread_impl_vtable.WakeConditionVariable (cond);
172 }
173
174 void
175 g_cond_broadcast (GCond *cond)
176 {
177   g_thread_impl_vtable.WakeAllConditionVariable (cond);
178 }
179
180 void
181 g_cond_wait (GCond  *cond,
182              GMutex *entered_mutex)
183 {
184   g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, INFINITE, 0);
185 }
186
187 gboolean
188 g_cond_timedwait (GCond  *cond,
189                   GMutex *entered_mutex,
190                   gint64  abs_time)
191 {
192   gint64 span;
193   FILETIME ft;
194   gint64 now;
195
196   GetSystemTimeAsFileTime (&ft);
197   memmove (&now, &ft, sizeof (FILETIME));
198
199   now -= G_GINT64_CONSTANT (116444736000000000);
200   now /= 10;
201
202   span = abs_time - now;
203
204   if G_UNLIKELY (span < 0)
205     span = 0;
206
207   if G_UNLIKELY (span > G_GINT64_CONSTANT (1000) * G_MAXINT32)
208     span = INFINITE;
209
210   return g_thread_impl_vtable.SleepConditionVariableSRW (cond, entered_mutex, span / 1000, 0);
211 }
212
213 gboolean
214 g_cond_timed_wait (GCond    *cond,
215                    GMutex   *entered_mutex,
216                    GTimeVal *abs_time)
217 {
218   if (abs_time)
219     {
220       gint64 micros;
221
222       micros = abs_time->tv_sec;
223       micros *= 1000000;
224       micros += abs_time->tv_usec;
225
226       return g_cond_timedwait (cond, entered_mutex, micros);
227     }
228   else
229     {
230       g_cond_wait (cond, entered_mutex);
231       return TRUE;
232     }
233 }
234
235 /* {{{1 GPrivate */
236
237 #include "glib.h"
238 #include "gthreadprivate.h"
239
240 #define win32_check_for_error(what) G_STMT_START{                       \
241   if (!(what))                                                          \
242     g_error ("file %s: line %d (%s): error %s during %s",               \
243              __FILE__, __LINE__, G_STRFUNC,                             \
244              g_win32_error_message (GetLastError ()), #what);           \
245   }G_STMT_END
246
247 #define G_MUTEX_SIZE (sizeof (gpointer))
248
249 static DWORD g_thread_self_tls;
250 static DWORD g_private_tls;
251 static CRITICAL_SECTION g_thread_global_spinlock;
252
253 typedef BOOL (__stdcall *GTryEnterCriticalSectionFunc) (CRITICAL_SECTION *);
254
255 /* As noted in the docs, GPrivate is a limited resource, here we take
256  * a rather low maximum to save memory, use GStaticPrivate instead. */
257 #define G_PRIVATE_MAX 100
258
259 static GDestroyNotify g_private_destructors[G_PRIVATE_MAX];
260
261 static guint g_private_next = 0;
262
263 typedef struct _GThreadData GThreadData;
264 struct _GThreadData
265 {
266   GThreadFunc func;
267   gpointer data;
268   HANDLE thread;
269   gboolean joinable;
270 };
271
272 static GPrivate *
273 g_private_new_win32_impl (GDestroyNotify destructor)
274 {
275   GPrivate *result;
276   EnterCriticalSection (&g_thread_global_spinlock);
277   if (g_private_next >= G_PRIVATE_MAX)
278     {
279       char buf[100];
280       sprintf (buf,
281                "Too many GPrivate allocated. Their number is limited to %d.",
282                G_PRIVATE_MAX);
283       MessageBox (NULL, buf, NULL, MB_ICONERROR|MB_SETFOREGROUND);
284       if (IsDebuggerPresent ())
285         G_BREAKPOINT ();
286       abort ();
287     }
288   g_private_destructors[g_private_next] = destructor;
289   result = GUINT_TO_POINTER (g_private_next);
290   g_private_next++;
291   LeaveCriticalSection (&g_thread_global_spinlock);
292
293   return result;
294 }
295
296 /* NOTE: the functions g_private_get and g_private_set may not use
297    functions from gmem.c and gmessages.c */
298
299 static void
300 g_private_set_win32_impl (GPrivate * private_key, gpointer value)
301 {
302   gpointer* array = TlsGetValue (g_private_tls);
303   guint index = GPOINTER_TO_UINT (private_key);
304
305   if (index >= G_PRIVATE_MAX)
306       return;
307
308   if (!array)
309     {
310       array = (gpointer*) calloc (G_PRIVATE_MAX, sizeof (gpointer));
311       TlsSetValue (g_private_tls, array);
312     }
313
314   array[index] = value;
315 }
316
317 static gpointer
318 g_private_get_win32_impl (GPrivate * private_key)
319 {
320   gpointer* array = TlsGetValue (g_private_tls);
321   guint index = GPOINTER_TO_UINT (private_key);
322
323   if (index >= G_PRIVATE_MAX || !array)
324     return NULL;
325
326   return array[index];
327 }
328
329 /* {{{1 GThread */
330
331 static void
332 g_thread_set_priority_win32_impl (gpointer thread, GThreadPriority priority)
333 {
334   GThreadData *target = *(GThreadData **)thread;
335   gint native_prio;
336
337   switch (priority)
338     {
339     case G_THREAD_PRIORITY_LOW:
340       native_prio = THREAD_PRIORITY_BELOW_NORMAL;
341       break;
342
343     case G_THREAD_PRIORITY_NORMAL:
344       native_prio = THREAD_PRIORITY_NORMAL;
345       break;
346
347     case G_THREAD_PRIORITY_HIGH:
348       native_prio = THREAD_PRIORITY_ABOVE_NORMAL;
349       break;
350
351     case G_THREAD_PRIORITY_URGENT:
352       native_prio = THREAD_PRIORITY_HIGHEST;
353       break;
354
355     default:
356       g_return_if_reached ();
357     }
358
359   win32_check_for_error (SetThreadPriority (target->thread, native_prio));
360 }
361
362 static void
363 g_thread_self_win32_impl (gpointer thread)
364 {
365   GThreadData *self = TlsGetValue (g_thread_self_tls);
366
367   if (!self)
368     {
369       /* This should only happen for the main thread! */
370       HANDLE handle = GetCurrentThread ();
371       HANDLE process = GetCurrentProcess ();
372       self = g_new (GThreadData, 1);
373       win32_check_for_error (DuplicateHandle (process, handle, process,
374                                               &self->thread, 0, FALSE,
375                                               DUPLICATE_SAME_ACCESS));
376       win32_check_for_error (TlsSetValue (g_thread_self_tls, self));
377       self->func = NULL;
378       self->data = NULL;
379       self->joinable = FALSE;
380     }
381
382   *(GThreadData **)thread = self;
383 }
384
385 static void
386 g_thread_exit_win32_impl (void)
387 {
388   GThreadData *self = TlsGetValue (g_thread_self_tls);
389   guint i, private_max;
390   gpointer *array = TlsGetValue (g_private_tls);
391
392   EnterCriticalSection (&g_thread_global_spinlock);
393   private_max = g_private_next;
394   LeaveCriticalSection (&g_thread_global_spinlock);
395
396   if (array)
397     {
398       gboolean some_data_non_null;
399
400       do {
401         some_data_non_null = FALSE;
402         for (i = 0; i < private_max; i++)
403           {
404             GDestroyNotify destructor = g_private_destructors[i];
405             GDestroyNotify data = array[i];
406
407             if (data)
408               some_data_non_null = TRUE;
409
410             array[i] = NULL;
411
412             if (destructor && data)
413               destructor (data);
414           }
415       } while (some_data_non_null);
416
417       free (array);
418
419       win32_check_for_error (TlsSetValue (g_private_tls, NULL));
420     }
421
422   if (self)
423     {
424       if (!self->joinable)
425         {
426           win32_check_for_error (CloseHandle (self->thread));
427           g_free (self);
428         }
429       win32_check_for_error (TlsSetValue (g_thread_self_tls, NULL));
430     }
431
432   if (g_thread_impl_vtable.CallThisOnThreadExit)
433     g_thread_impl_vtable.CallThisOnThreadExit ();
434
435   _endthreadex (0);
436 }
437
438 static guint __stdcall
439 g_thread_proxy (gpointer data)
440 {
441   GThreadData *self = (GThreadData*) data;
442
443   win32_check_for_error (TlsSetValue (g_thread_self_tls, self));
444
445   self->func (self->data);
446
447   g_thread_exit_win32_impl ();
448
449   g_assert_not_reached ();
450
451   return 0;
452 }
453
454 static void
455 g_thread_create_win32_impl (GThreadFunc func,
456                             gpointer data,
457                             gulong stack_size,
458                             gboolean joinable,
459                             gboolean bound,
460                             GThreadPriority priority,
461                             gpointer thread,
462                             GError **error)
463 {
464   guint ignore;
465   GThreadData *retval;
466
467   g_return_if_fail (func);
468   g_return_if_fail (priority >= G_THREAD_PRIORITY_LOW);
469   g_return_if_fail (priority <= G_THREAD_PRIORITY_URGENT);
470
471   retval = g_new(GThreadData, 1);
472   retval->func = func;
473   retval->data = data;
474
475   retval->joinable = joinable;
476
477   retval->thread = (HANDLE) _beginthreadex (NULL, stack_size, g_thread_proxy,
478                                             retval, 0, &ignore);
479
480   if (retval->thread == NULL)
481     {
482       gchar *win_error = g_win32_error_message (GetLastError ());
483       g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
484                    "Error creating thread: %s", win_error);
485       g_free (retval);
486       g_free (win_error);
487       return;
488     }
489
490   *(GThreadData **)thread = retval;
491
492   g_thread_set_priority_win32_impl (thread, priority);
493 }
494
495 static void
496 g_thread_yield_win32_impl (void)
497 {
498   Sleep(0);
499 }
500
501 static void
502 g_thread_join_win32_impl (gpointer thread)
503 {
504   GThreadData *target = *(GThreadData **)thread;
505
506   g_return_if_fail (target->joinable);
507
508   win32_check_for_error (WAIT_FAILED !=
509                          WaitForSingleObject (target->thread, INFINITE));
510
511   win32_check_for_error (CloseHandle (target->thread));
512   g_free (target);
513 }
514
515 /* {{{1 SRWLock and CONDITION_VARIABLE emulation (for Windows XP) */
516
517 static DWORD            g_thread_xp_waiter_tls;
518 static CRITICAL_SECTION g_thread_xp_lock;
519
520 /* {{{2 GThreadWaiter utility class for CONDITION_VARIABLE emulation */
521 typedef struct _GThreadXpWaiter GThreadXpWaiter;
522 struct _GThreadXpWaiter
523 {
524   HANDLE                    event;
525   volatile GThreadXpWaiter *next;
526 };
527
528 static GThreadXpWaiter *
529 g_thread_xp_waiter_get (void)
530 {
531   GThreadXpWaiter *waiter;
532
533   waiter = TlsGetValue (g_thread_xp_waiter_tls);
534
535   if G_UNLIKELY (waiter == NULL)
536     {
537       waiter = malloc (sizeof (GThreadXpWaiter));
538       if (waiter == NULL)
539         g_thread_abort (GetLastError (), "malloc");
540       waiter->event = CreateEvent (0, FALSE, FALSE, NULL);
541       if (waiter->event == NULL)
542         g_thread_abort (GetLastError (), "CreateEvent");
543
544       TlsSetValue (g_thread_xp_waiter_tls, waiter);
545     }
546
547   return waiter;
548 }
549
550 static void
551 g_thread_xp_CallThisOnThreadExit (void)
552 {
553   GThreadXpWaiter *waiter;
554
555   waiter = TlsGetValue (g_thread_xp_waiter_tls);
556
557   if (waiter != NULL)
558     {
559       TlsSetValue (g_thread_xp_waiter_tls, NULL);
560       CloseHandle (waiter->event);
561       free (waiter);
562     }
563 }
564
565 /* {{{2 SRWLock emulation */
566 typedef struct
567 {
568   CRITICAL_SECTION critical_section;
569 } GThreadSRWLock;
570
571 static void
572 g_thread_xp_InitializeSRWLock (gpointer mutex)
573 {
574   *(GThreadSRWLock * volatile *) mutex = NULL;
575 }
576
577 static void
578 g_thread_xp_DeleteSRWLock (gpointer mutex)
579 {
580   GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
581
582   if (lock)
583     {
584       DeleteCriticalSection (&lock->critical_section);
585       free (lock);
586     }
587 }
588
589 static GThreadSRWLock *
590 g_thread_xp_get_srwlock (GThreadSRWLock * volatile *lock)
591 {
592   GThreadSRWLock *result;
593
594   /* It looks like we're missing some barriers here, but this code only
595    * ever runs on Windows XP, which in turn only ever runs on hardware
596    * with a relatively rigid memory model.  The 'volatile' will take
597    * care of the compiler.
598    */
599   result = *lock;
600
601   if G_UNLIKELY (result == NULL)
602     {
603       EnterCriticalSection (&g_thread_xp_lock);
604
605       result = malloc (sizeof (GThreadSRWLock));
606
607       if (result == NULL)
608         g_thread_abort (errno, "malloc");
609
610       InitializeCriticalSection (&result->critical_section);
611       *lock = result;
612
613       LeaveCriticalSection (&g_thread_xp_lock);
614     }
615
616   return result;
617 }
618
619 static void
620 g_thread_xp_AcquireSRWLockExclusive (gpointer mutex)
621 {
622   GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
623
624   EnterCriticalSection (&lock->critical_section);
625 }
626
627 static BOOLEAN
628 g_thread_xp_TryAcquireSRWLockExclusive (gpointer mutex)
629 {
630   GThreadSRWLock *lock = g_thread_xp_get_srwlock (mutex);
631
632   return TryEnterCriticalSection (&lock->critical_section);
633 }
634
635 static void
636 g_thread_xp_ReleaseSRWLockExclusive (gpointer mutex)
637 {
638   GThreadSRWLock *lock = *(GThreadSRWLock * volatile *) mutex;
639
640   /* We need this until we fix some weird parts of GLib that try to
641    * unlock freshly-allocated mutexes.
642    */
643   if (lock != NULL)
644     LeaveCriticalSection (&lock->critical_section);
645 }
646
647 /* {{{2 CONDITION_VARIABLE emulation */
648 typedef struct
649 {
650   volatile GThreadXpWaiter  *first;
651   volatile GThreadXpWaiter **last_ptr;
652 } GThreadXpCONDITION_VARIABLE;
653
654 static void
655 g_thread_xp_InitializeConditionVariable (gpointer cond)
656 {
657   *(GThreadXpCONDITION_VARIABLE * volatile *) cond = NULL;
658 }
659
660 static void
661 g_thread_xp_DeleteConditionVariable (gpointer cond)
662 {
663   GThreadXpCONDITION_VARIABLE *cv = *(GThreadXpCONDITION_VARIABLE * volatile *) cond;
664
665   if (cv)
666     free (cv);
667 }
668
669 static GThreadXpCONDITION_VARIABLE *
670 g_thread_xp_get_condition_variable (GThreadXpCONDITION_VARIABLE * volatile *cond)
671 {
672   GThreadXpCONDITION_VARIABLE *result;
673
674   /* It looks like we're missing some barriers here, but this code only
675    * ever runs on Windows XP, which in turn only ever runs on hardware
676    * with a relatively rigid memory model.  The 'volatile' will take
677    * care of the compiler.
678    */
679   result = *cond;
680
681   if G_UNLIKELY (result == NULL)
682     {
683       result = malloc (sizeof (GThreadXpCONDITION_VARIABLE));
684
685       if (result == NULL)
686         g_thread_abort (errno, "malloc");
687
688       result->first = NULL;
689       result->last_ptr = &result->first;
690
691       if (InterlockedCompareExchangePointer (cond, result, NULL) != NULL)
692         {
693           free (result);
694           result = *cond;
695         }
696     }
697
698   return result;
699 }
700
701 static BOOL
702 g_thread_xp_SleepConditionVariableSRW (gpointer cond,
703                                        gpointer mutex,
704                                        DWORD    timeout,
705                                        ULONG    flags)
706 {
707   GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
708   GThreadXpWaiter *waiter = g_thread_xp_waiter_get ();
709   DWORD status;
710
711   waiter->next = NULL;
712
713   EnterCriticalSection (&g_thread_xp_lock);
714   *cv->last_ptr = waiter;
715   cv->last_ptr = &waiter->next;
716   LeaveCriticalSection (&g_thread_xp_lock);
717
718   g_mutex_unlock (mutex);
719   status = WaitForSingleObject (waiter->event, timeout);
720
721   if (status != WAIT_TIMEOUT && status != WAIT_OBJECT_0)
722     g_thread_abort (GetLastError (), "WaitForSingleObject");
723
724   g_mutex_lock (mutex);
725
726   return status == WAIT_OBJECT_0;
727 }
728
729 static void
730 g_thread_xp_WakeConditionVariable (gpointer cond)
731 {
732   GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
733   volatile GThreadXpWaiter *waiter;
734
735   EnterCriticalSection (&g_thread_xp_lock);
736   waiter = cv->first;
737   if (waiter != NULL)
738     {
739       cv->first = waiter->next;
740       if (cv->first == NULL)
741         cv->last_ptr = &cv->first;
742     }
743   LeaveCriticalSection (&g_thread_xp_lock);
744
745   if (waiter != NULL)
746     SetEvent (waiter->event);
747 }
748
749 static void
750 g_thread_xp_WakeAllConditionVariable (gpointer cond)
751 {
752   GThreadXpCONDITION_VARIABLE *cv = g_thread_xp_get_condition_variable (cond);
753   volatile GThreadXpWaiter *waiter;
754
755   EnterCriticalSection (&g_thread_xp_lock);
756   waiter = cv->first;
757   cv->first = NULL;
758   cv->last_ptr = &cv->first;
759   LeaveCriticalSection (&g_thread_xp_lock);
760
761   while (waiter != NULL)
762     {
763       volatile GThreadXpWaiter *next;
764
765       next = waiter->next;
766       SetEvent (waiter->event);
767       waiter = next;
768     }
769 }
770
771 /* {{{2 XP Setup */
772 static void
773 g_thread_xp_init (void)
774 {
775   static const GThreadImplVtable g_thread_xp_impl_vtable = {
776     g_thread_xp_CallThisOnThreadExit,
777     g_thread_xp_InitializeSRWLock,
778     g_thread_xp_DeleteSRWLock,
779     g_thread_xp_AcquireSRWLockExclusive,
780     g_thread_xp_TryAcquireSRWLockExclusive,
781     g_thread_xp_ReleaseSRWLockExclusive,
782     g_thread_xp_InitializeConditionVariable,
783     g_thread_xp_DeleteConditionVariable,
784     g_thread_xp_SleepConditionVariableSRW,
785     g_thread_xp_WakeAllConditionVariable,
786     g_thread_xp_WakeConditionVariable
787   };
788
789   InitializeCriticalSection (&g_thread_xp_lock);
790   g_thread_xp_waiter_tls = TlsAlloc ();
791
792   g_thread_impl_vtable = g_thread_xp_impl_vtable;
793 }
794
795 /* {{{1 Epilogue */
796
797 GThreadFunctions g_thread_functions_for_glib_use =
798 {
799   g_mutex_new,           /* mutex */
800   g_mutex_lock,
801   g_mutex_trylock,
802   g_mutex_unlock,
803   g_mutex_free,
804   g_cond_new,            /* condition */
805   g_cond_signal,
806   g_cond_broadcast,
807   g_cond_wait,
808   g_cond_timed_wait,
809   g_cond_free,
810   g_private_new_win32_impl,         /* private thread data */
811   g_private_get_win32_impl,
812   g_private_set_win32_impl,
813   g_thread_create_win32_impl,       /* thread */
814   g_thread_yield_win32_impl,
815   g_thread_join_win32_impl,
816   g_thread_exit_win32_impl,
817   g_thread_set_priority_win32_impl,
818   g_thread_self_win32_impl,
819   NULL                             /* no equal function necessary */
820 };
821
822 void
823 _g_thread_impl_init (void)
824 {
825   static gboolean beenhere = FALSE;
826
827   if (beenhere)
828     return;
829
830   beenhere = TRUE;
831
832   printf ("thread init\n");
833   win32_check_for_error (TLS_OUT_OF_INDEXES !=
834                          (g_thread_self_tls = TlsAlloc ()));
835   win32_check_for_error (TLS_OUT_OF_INDEXES !=
836                          (g_private_tls = TlsAlloc ()));
837   InitializeCriticalSection (&g_thread_global_spinlock);
838 }
839
840 static gboolean
841 g_thread_lookup_native_funcs (void)
842 {
843   GThreadImplVtable native_vtable = { 0, };
844   HMODULE kernel32;
845
846   kernel32 = GetModuleHandle ("KERNEL32.DLL");
847
848   if (kernel32 == NULL)
849     return FALSE;
850
851 #define GET_FUNC(name) if ((native_vtable.name = (void *) GetProcAddress (kernel32, #name)) == NULL) return FALSE
852   GET_FUNC(InitializeSRWLock);
853   GET_FUNC(AcquireSRWLockExclusive);
854   GET_FUNC(TryAcquireSRWLockExclusive);
855   GET_FUNC(ReleaseSRWLockExclusive);
856
857   GET_FUNC(InitializeConditionVariable);
858   GET_FUNC(SleepConditionVariableSRW);
859   GET_FUNC(WakeAllConditionVariable);
860   GET_FUNC(WakeConditionVariable);
861 #undef GET_FUNC
862
863   g_thread_impl_vtable = native_vtable;
864
865   return TRUE;
866 }
867
868 G_GNUC_INTERNAL void
869 g_thread_DllMain (void)
870 {
871   /* XXX This is broken right now for some unknown reason...
872
873   if (g_thread_lookup_native_funcs ())
874     fprintf (stderr, "(debug) GThread using native mode\n");
875   else
876 */
877     {
878       fprintf (stderr, "(debug) GThread using Windows XP mode\n");
879       g_thread_xp_init ();
880     }
881 }
882
883 /* vim:set foldmethod=marker: */
884