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