Subversion Repositories Kolibri OS

Rev

Rev 4383 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4383 Serge 1
/* Threads compatibility routines for libgcc2 and libobjc.  */
2
/* Compile this one with gcc.  */
3
 
4
/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2008, 2009
5
   Free Software Foundation, Inc.
6
   Contributed by Mumit Khan .
7
 
8
This file is part of GCC.
9
 
10
GCC is free software; you can redistribute it and/or modify it under
11
the terms of the GNU General Public License as published by the Free
12
Software Foundation; either version 3, or (at your option) any later
13
version.
14
 
15
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16
WARRANTY; without even the implied warranty of MERCHANTABILITY or
17
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18
for more details.
19
 
20
Under Section 7 of GPL version 3, you are granted additional
21
permissions described in the GCC Runtime Library Exception, version
22
3.1, as published by the Free Software Foundation.
23
 
24
You should have received a copy of the GNU General Public License and
25
a copy of the GCC Runtime Library Exception along with this program;
26
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
27
.  */
28
 
29
#ifndef GCC_GTHR_WIN32_H
30
#define GCC_GTHR_WIN32_H
31
 
32
/* Make sure CONST_CAST2 (origin in system.h) is declared.  */
33
#ifndef CONST_CAST2
34
#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
35
#endif
36
 
37
/* Windows32 threads specific definitions. The windows32 threading model
38
   does not map well into pthread-inspired gcc's threading model, and so
39
   there are caveats one needs to be aware of.
40
 
41
   1. The destructor supplied to __gthread_key_create is ignored for
42
      generic x86-win32 ports. This will certainly cause memory leaks
43
      due to unreclaimed eh contexts (sizeof (eh_context) is at least
44
      24 bytes for x86 currently).
45
 
46
      This memory leak may be significant for long-running applications
47
      that make heavy use of C++ EH.
48
 
49
      However, Mingw runtime (version 0.3 or newer) provides a mechanism
50
      to emulate pthreads key dtors; the runtime provides a special DLL,
51
      linked in if -mthreads option is specified, that runs the dtors in
52
      the reverse order of registration when each thread exits. If
53
      -mthreads option is not given, a stub is linked in instead of the
54
      DLL, which results in memory leak. Other x86-win32 ports can use
55
      the same technique of course to avoid the leak.
56
 
57
   2. The error codes returned are non-POSIX like, and cast into ints.
58
      This may cause incorrect error return due to truncation values on
59
      hw where sizeof (DWORD) > sizeof (int).
60
 
61
   3. We are currently using a special mutex instead of the Critical
62
      Sections, since Win9x does not support TryEnterCriticalSection
63
      (while NT does).
64
 
65
   The basic framework should work well enough. In the long term, GCC
66
   needs to use Structured Exception Handling on Windows32.  */
67
 
68
#define __GTHREADS 1
69
 
70
#include 
71
#ifdef __MINGW32__
72
#include <_mingw.h>
73
#endif
74
 
4396 Serge 75
#ifndef __UNUSED_PARAM
76
#define __UNUSED_PARAM(x) x
4383 Serge 77
#endif
78
 
79
#ifdef _LIBOBJC
80
 
81
/* This is necessary to prevent windef.h (included from windows.h) from
82
   defining its own BOOL as a typedef.  */
83
#ifndef __OBJC__
84
#define __OBJC__
85
#endif
86
#include 
87
/* Now undef the windows BOOL.  */
88
#undef BOOL
89
 
90
/* Key structure for maintaining thread specific storage */
91
static DWORD	__gthread_objc_data_tls = (DWORD) -1;
92
 
93
/* Backend initialization functions */
94
 
95
/* Initialize the threads subsystem.  */
96
int
97
__gthread_objc_init_thread_system (void)
98
{
99
  /* Initialize the thread storage key.  */
100
  if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
101
    return 0;
102
  else
103
    return -1;
104
}
105
 
106
/* Close the threads subsystem.  */
107
int
108
__gthread_objc_close_thread_system (void)
109
{
110
  if (__gthread_objc_data_tls != (DWORD) -1)
111
    TlsFree (__gthread_objc_data_tls);
112
  return 0;
113
}
114
 
115
/* Backend thread functions */
116
 
117
/* Create a new thread of execution.  */
118
objc_thread_t
119
__gthread_objc_thread_detach (void (*func)(void *arg), void *arg)
120
{
121
  DWORD	thread_id = 0;
122
  HANDLE win32_handle;
123
 
124
  if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
125
				     arg, 0, &thread_id)))
126
    thread_id = 0;
127
 
128
  return (objc_thread_t) (INT_PTR) thread_id;
129
}
130
 
131
/* Set the current thread's priority.  */
132
int
133
__gthread_objc_thread_set_priority (int priority)
134
{
135
  int sys_priority = 0;
136
 
137
  switch (priority)
138
    {
139
    case OBJC_THREAD_INTERACTIVE_PRIORITY:
140
      sys_priority = THREAD_PRIORITY_NORMAL;
141
      break;
142
    default:
143
    case OBJC_THREAD_BACKGROUND_PRIORITY:
144
      sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
145
      break;
146
    case OBJC_THREAD_LOW_PRIORITY:
147
      sys_priority = THREAD_PRIORITY_LOWEST;
148
      break;
149
    }
150
 
151
  /* Change priority */
152
  if (SetThreadPriority (GetCurrentThread (), sys_priority))
153
    return 0;
154
  else
155
    return -1;
156
}
157
 
158
/* Return the current thread's priority.  */
159
int
160
__gthread_objc_thread_get_priority (void)
161
{
162
  int sys_priority;
163
 
164
  sys_priority = GetThreadPriority (GetCurrentThread ());
165
 
166
  switch (sys_priority)
167
    {
168
    case THREAD_PRIORITY_HIGHEST:
169
    case THREAD_PRIORITY_TIME_CRITICAL:
170
    case THREAD_PRIORITY_ABOVE_NORMAL:
171
    case THREAD_PRIORITY_NORMAL:
172
      return OBJC_THREAD_INTERACTIVE_PRIORITY;
173
 
174
    default:
175
    case THREAD_PRIORITY_BELOW_NORMAL:
176
      return OBJC_THREAD_BACKGROUND_PRIORITY;
177
 
178
    case THREAD_PRIORITY_IDLE:
179
    case THREAD_PRIORITY_LOWEST:
180
      return OBJC_THREAD_LOW_PRIORITY;
181
    }
182
 
183
  /* Couldn't get priority.  */
184
  return -1;
185
}
186
 
187
/* Yield our process time to another thread.  */
188
void
189
__gthread_objc_thread_yield (void)
190
{
191
  Sleep (0);
192
}
193
 
194
/* Terminate the current thread.  */
195
int
196
__gthread_objc_thread_exit (void)
197
{
198
  /* exit the thread */
199
  ExitThread (__objc_thread_exit_status);
200
 
201
  /* Failed if we reached here */
202
  return -1;
203
}
204
 
205
/* Returns an integer value which uniquely describes a thread.  */
206
objc_thread_t
207
__gthread_objc_thread_id (void)
208
{
209
  return (objc_thread_t) (INT_PTR) GetCurrentThreadId ();
210
}
211
 
212
/* Sets the thread's local storage pointer.  */
213
int
214
__gthread_objc_thread_set_data (void *value)
215
{
216
  if (TlsSetValue (__gthread_objc_data_tls, value))
217
    return 0;
218
  else
219
    return -1;
220
}
221
 
222
/* Returns the thread's local storage pointer.  */
223
void *
224
__gthread_objc_thread_get_data (void)
225
{
226
  DWORD lasterror;
227
  void *ptr;
228
 
229
  lasterror = GetLastError ();
230
 
231
  ptr = TlsGetValue (__gthread_objc_data_tls);          /* Return thread data.  */
232
 
233
  SetLastError (lasterror);
234
 
235
  return ptr;
236
}
237
 
238
/* Backend mutex functions */
239
 
240
/* Allocate a mutex.  */
241
int
242
__gthread_objc_mutex_allocate (objc_mutex_t mutex)
243
{
244
  if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
245
    return -1;
246
  else
247
    return 0;
248
}
249
 
250
/* Deallocate a mutex.  */
251
int
252
__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
253
{
254
  CloseHandle ((HANDLE) (mutex->backend));
255
  return 0;
256
}
257
 
258
/* Grab a lock on a mutex.  */
259
int
260
__gthread_objc_mutex_lock (objc_mutex_t mutex)
261
{
262
  int status;
263
 
264
  status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE);
265
  if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
266
    return -1;
267
  else
268
    return 0;
269
}
270
 
271
/* Try to grab a lock on a mutex.  */
272
int
273
__gthread_objc_mutex_trylock (objc_mutex_t mutex)
274
{
275
  int status;
276
 
277
  status = WaitForSingleObject ((HANDLE) (mutex->backend), 0);
278
  if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
279
    return -1;
280
  else
281
    return 0;
282
}
283
 
284
/* Unlock the mutex */
285
int
286
__gthread_objc_mutex_unlock (objc_mutex_t mutex)
287
{
288
  if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0)
289
    return -1;
290
  else
291
    return 0;
292
}
293
 
294
/* Backend condition mutex functions */
295
 
296
/* Allocate a condition.  */
297
int
4396 Serge 298
__gthread_objc_condition_allocate (objc_condition_t __UNUSED_PARAM(condition))
4383 Serge 299
{
300
  /* Unimplemented.  */
301
  return -1;
302
}
303
 
304
/* Deallocate a condition.  */
305
int
4396 Serge 306
__gthread_objc_condition_deallocate (objc_condition_t __UNUSED_PARAM(condition))
4383 Serge 307
{
308
  /* Unimplemented.  */
309
  return -1;
310
}
311
 
312
/* Wait on the condition */
313
int
4396 Serge 314
__gthread_objc_condition_wait (objc_condition_t __UNUSED_PARAM(condition),
315
			       objc_mutex_t __UNUSED_PARAM(mutex))
4383 Serge 316
{
317
  /* Unimplemented.  */
318
  return -1;
319
}
320
 
321
/* Wake up all threads waiting on this condition.  */
322
int
4396 Serge 323
__gthread_objc_condition_broadcast (objc_condition_t __UNUSED_PARAM(condition))
4383 Serge 324
{
325
  /* Unimplemented.  */
326
  return -1;
327
}
328
 
329
/* Wake up one thread waiting on this condition.  */
330
int
4396 Serge 331
__gthread_objc_condition_signal (objc_condition_t __UNUSED_PARAM(condition))
4383 Serge 332
{
333
  /* Unimplemented.  */
334
  return -1;
335
}
336
 
337
#else /* _LIBOBJC */
338
 
339
#ifdef __cplusplus
340
extern "C" {
341
#endif
342
 
343
typedef unsigned long __gthread_key_t;
344
 
345
typedef struct {
346
  int done;
347
  long started;
348
} __gthread_once_t;
349
 
350
typedef struct {
351
  long counter;
352
  void *sema;
353
} __gthread_mutex_t;
354
 
355
typedef struct {
356
  long counter;
357
  long depth;
358
  unsigned long owner;
359
  void *sema;
360
} __gthread_recursive_mutex_t;
361
 
362
#define __GTHREAD_ONCE_INIT {0, -1}
363
#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
364
#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
365
#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
366
  __gthread_recursive_mutex_init_function
367
#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
368
 
369
#if defined (_WIN32) && !defined(__CYGWIN__)
370
#define MINGW32_SUPPORTS_MT_EH 1
371
/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
372
   if -mthreads option was specified, or 0 otherwise. This is to get around
373
   the lack of weak symbols in PE-COFF.  */
374
extern int _CRT_MT;
375
extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
376
#endif /* _WIN32 && !__CYGWIN__ */
377
 
378
/* The Windows95 kernel does not export InterlockedCompareExchange.
379
   This provides a substitute.   When building apps that reference
380
   gthread_mutex_try_lock, the  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
381
   macro  must be defined if Windows95 is a target.  Currently
382
   gthread_mutex_try_lock is not referenced by libgcc or libstdc++.  */
383
#ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
384
static inline long
385
__gthr_i486_lock_cmp_xchg(long *__dest, long __xchg, long __comperand)
386
{
387
  long result;
388
  __asm__ __volatile__ ("\n\
389
	lock\n\
390
	cmpxchg{l} {%4, %1|%1, %4}\n"
391
	: "=a" (result), "=m" (*__dest)
392
	: "0" (__comperand), "m" (*__dest), "r" (__xchg)
393
	: "cc");
394
  return result;
395
}
396
#define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
397
#else  /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
398
#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
399
#endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
400
 
401
static inline int
402
__gthread_active_p (void)
403
{
404
#ifdef MINGW32_SUPPORTS_MT_EH
405
  return _CRT_MT;
406
#else
407
  return 1;
408
#endif
409
}
410
 
411
#if __GTHREAD_HIDE_WIN32API
412
 
413
/* The implementations are in config/i386/gthr-win32.c in libgcc.a.
414
   Only stubs are exposed to avoid polluting the C++ namespace with
415
   windows api definitions.  */
416
 
417
extern int __gthr_win32_once (__gthread_once_t *, void (*) (void));
418
extern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*));
419
extern int __gthr_win32_key_delete (__gthread_key_t);
420
extern void * __gthr_win32_getspecific (__gthread_key_t);
421
extern int __gthr_win32_setspecific (__gthread_key_t, const void *);
422
extern void __gthr_win32_mutex_init_function (__gthread_mutex_t *);
423
extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
424
extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
425
extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
426
extern void
427
  __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
428
extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
429
extern int
430
  __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
431
extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
432
extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
433
 
434
static inline int
435
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
436
{
437
  if (__gthread_active_p ())
438
    return __gthr_win32_once (__once, __func);
439
  else
440
    return -1;
441
}
442
 
443
static inline int
444
__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
445
{
446
  return __gthr_win32_key_create (__key, __dtor);
447
}
448
 
449
static inline int
450
__gthread_key_delete (__gthread_key_t __key)
451
{
452
  return __gthr_win32_key_delete (__key);
453
}
454
 
455
static inline void *
456
__gthread_getspecific (__gthread_key_t __key)
457
{
458
  return __gthr_win32_getspecific (__key);
459
}
460
 
461
static inline int
462
__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
463
{
464
  return __gthr_win32_setspecific (__key, __ptr);
465
}
466
 
467
static inline void
468
__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
469
{
470
  __gthr_win32_mutex_init_function (__mutex);
471
}
472
 
473
static inline void
474
__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
475
{
476
  __gthr_win32_mutex_destroy (__mutex);
477
}
478
 
479
static inline int
480
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
481
{
482
  if (__gthread_active_p ())
483
    return __gthr_win32_mutex_lock (__mutex);
484
  else
485
    return 0;
486
}
487
 
488
static inline int
489
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
490
{
491
  if (__gthread_active_p ())
492
    return __gthr_win32_mutex_trylock (__mutex);
493
  else
494
    return 0;
495
}
496
 
497
static inline int
498
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
499
{
500
  if (__gthread_active_p ())
501
    return __gthr_win32_mutex_unlock (__mutex);
502
  else
503
    return 0;
504
}
505
 
506
static inline void
507
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
508
{
509
   __gthr_win32_recursive_mutex_init_function (__mutex);
510
}
511
 
512
static inline int
513
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
514
{
515
  if (__gthread_active_p ())
516
    return __gthr_win32_recursive_mutex_lock (__mutex);
517
  else
518
    return 0;
519
}
520
 
521
static inline int
522
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
523
{
524
  if (__gthread_active_p ())
525
    return __gthr_win32_recursive_mutex_trylock (__mutex);
526
  else
527
    return 0;
528
}
529
 
530
static inline int
531
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
532
{
533
  if (__gthread_active_p ())
534
    return __gthr_win32_recursive_mutex_unlock (__mutex);
535
  else
536
    return 0;
537
}
538
 
539
#else /* ! __GTHREAD_HIDE_WIN32API */
540
 
541
#include 
542
#include 
543
 
544
static inline int
545
__gthread_once (__gthread_once_t *__once, void (*__func) (void))
546
{
547
  if (! __gthread_active_p ())
548
    return -1;
549
  else if (__once == NULL || __func == NULL)
550
    return EINVAL;
551
 
552
  if (! __once->done)
553
    {
554
      if (InterlockedIncrement (&(__once->started)) == 0)
555
	{
556
	  (*__func) ();
557
	  __once->done = TRUE;
558
	}
559
      else
560
	{
561
	  /* Another thread is currently executing the code, so wait for it
562
	     to finish; yield the CPU in the meantime.  If performance
563
	     does become an issue, the solution is to use an Event that
564
	     we wait on here (and set above), but that implies a place to
565
	     create the event before this routine is called.  */
566
	  while (! __once->done)
567
	    Sleep (0);
568
	}
569
    }
570
 
571
  return 0;
572
}
573
 
574
/* Windows32 thread local keys don't support destructors; this leads to
575
   leaks, especially in threaded applications making extensive use of
576
   C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
577
static inline int
578
__gthread_key_create (__gthread_key_t *__key,
579
		      void (*__dtor) (void *) __attribute__((unused)))
580
{
581
  int __status = 0;
582
  DWORD __tls_index = TlsAlloc ();
583
  if (__tls_index != 0xFFFFFFFF)
584
    {
585
      *__key = __tls_index;
586
#ifdef MINGW32_SUPPORTS_MT_EH
587
      /* Mingw runtime will run the dtors in reverse order for each thread
588
         when the thread exits.  */
589
      __status = __mingwthr_key_dtor (*__key, __dtor);
590
#endif
591
    }
592
  else
593
    __status = (int) GetLastError ();
594
  return __status;
595
}
596
 
597
static inline int
598
__gthread_key_delete (__gthread_key_t __key)
599
{
600
  return (TlsFree (__key) != 0) ? 0 : (int) GetLastError ();
601
}
602
 
603
static inline void *
604
__gthread_getspecific (__gthread_key_t __key)
605
{
606
  DWORD __lasterror;
607
  void *__ptr;
608
 
609
  __lasterror = GetLastError ();
610
 
611
  __ptr = TlsGetValue (__key);
612
 
613
  SetLastError (__lasterror);
614
 
615
  return __ptr;
616
}
617
 
618
static inline int
619
__gthread_setspecific (__gthread_key_t __key, const void *__ptr)
620
{
621
  if (TlsSetValue (__key, CONST_CAST2(void *, const void *, __ptr)) != 0)
622
    return 0;
623
  else
624
    return GetLastError ();
625
}
626
 
627
static inline void
628
__gthread_mutex_init_function (__gthread_mutex_t *__mutex)
629
{
630
  __mutex->counter = -1;
631
  __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
632
}
633
 
634
static inline void
635
__gthread_mutex_destroy (__gthread_mutex_t *__mutex)
636
{
637
  CloseHandle ((HANDLE) __mutex->sema);
638
}
639
 
640
static inline int
641
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
642
{
643
  int __status = 0;
644
 
645
  if (__gthread_active_p ())
646
    {
647
      if (InterlockedIncrement (&__mutex->counter) == 0 ||
648
	  WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
649
	__status = 0;
650
      else
651
	{
652
	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
653
	     some best-effort cleanup here.  */
654
	  InterlockedDecrement (&__mutex->counter);
655
	  __status = 1;
656
	}
657
    }
658
  return __status;
659
}
660
 
661
static inline int
662
__gthread_mutex_trylock (__gthread_mutex_t *__mutex)
663
{
664
  int __status = 0;
665
 
666
  if (__gthread_active_p ())
667
    {
668
      if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
669
	__status = 0;
670
      else
671
	__status = 1;
672
    }
673
  return __status;
674
}
675
 
676
static inline int
677
__gthread_mutex_unlock (__gthread_mutex_t *__mutex)
678
{
679
  if (__gthread_active_p ())
680
    {
681
      if (InterlockedDecrement (&__mutex->counter) >= 0)
682
	return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
683
    }
684
  return 0;
685
}
686
 
687
static inline void
688
__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
689
{
690
  __mutex->counter = -1;
691
  __mutex->depth = 0;
692
  __mutex->owner = 0;
693
  __mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
694
}
695
 
696
static inline int
697
__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
698
{
699
  if (__gthread_active_p ())
700
    {
701
      DWORD __me = GetCurrentThreadId();
702
      if (InterlockedIncrement (&__mutex->counter) == 0)
703
	{
704
	  __mutex->depth = 1;
705
	  __mutex->owner = __me;
706
	}
707
      else if (__mutex->owner == __me)
708
	{
709
	  InterlockedDecrement (&__mutex->counter);
710
	  ++(__mutex->depth);
711
	}
712
      else if (WaitForSingleObject (__mutex->sema, INFINITE) == WAIT_OBJECT_0)
713
	{
714
	  __mutex->depth = 1;
715
	  __mutex->owner = __me;
716
	}
717
      else
718
	{
719
	  /* WaitForSingleObject returns WAIT_FAILED, and we can only do
720
	     some best-effort cleanup here.  */
721
	  InterlockedDecrement (&__mutex->counter);
722
	  return 1;
723
	}
724
    }
725
  return 0;
726
}
727
 
728
static inline int
729
__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
730
{
731
  if (__gthread_active_p ())
732
    {
733
      DWORD __me = GetCurrentThreadId();
734
      if (__GTHR_W32_InterlockedCompareExchange (&__mutex->counter, 0, -1) < 0)
735
	{
736
	  __mutex->depth = 1;
737
	  __mutex->owner = __me;
738
	}
739
      else if (__mutex->owner == __me)
740
	++(__mutex->depth);
741
      else
742
	return 1;
743
    }
744
  return 0;
745
}
746
 
747
static inline int
748
__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
749
{
750
  if (__gthread_active_p ())
751
    {
752
      --(__mutex->depth);
753
      if (__mutex->depth == 0)
754
	{
755
	  __mutex->owner = 0;
756
 
757
	  if (InterlockedDecrement (&__mutex->counter) >= 0)
758
	    return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
759
	}
760
    }
761
  return 0;
762
}
763
 
764
#endif /*  __GTHREAD_HIDE_WIN32API */
765
 
766
#ifdef __cplusplus
767
}
768
#endif
769
 
770
#endif /* _LIBOBJC */
771
 
772
#endif /* ! GCC_GTHR_WIN32_H */