Subversion Repositories Kolibri OS

Rev

Rev 4383 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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