196263Sobrien/* Threads compatibility routines for libgcc2 and libobjc. */ 296263Sobrien/* Compile this one with gcc. */ 3169689Skan 4169689Skan/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 5169689Skan Free Software Foundation, Inc. 696263Sobrien Contributed by Mumit Khan <khan@xraylith.wisc.edu>. 796263Sobrien 896263SobrienThis file is part of GCC. 996263Sobrien 1096263SobrienGCC is free software; you can redistribute it and/or modify it under 1196263Sobrienthe terms of the GNU General Public License as published by the Free 1296263SobrienSoftware Foundation; either version 2, or (at your option) any later 1396263Sobrienversion. 1496263Sobrien 1596263SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1696263SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1796263SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1896263Sobrienfor more details. 1996263Sobrien 2096263SobrienYou should have received a copy of the GNU General Public License 2196263Sobrienalong with GCC; see the file COPYING. If not, write to the Free 22169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 23169689Skan02110-1301, USA. */ 2496263Sobrien 2596263Sobrien/* As a special exception, if you link this library with other files, 2696263Sobrien some of which are compiled with GCC, to produce an executable, 2796263Sobrien this library does not by itself cause the resulting executable 2896263Sobrien to be covered by the GNU General Public License. 2996263Sobrien This exception does not however invalidate any other reasons why 3096263Sobrien the executable file might be covered by the GNU General Public License. */ 3196263Sobrien 3296263Sobrien#ifndef GCC_GTHR_WIN32_H 3396263Sobrien#define GCC_GTHR_WIN32_H 3496263Sobrien 3596263Sobrien/* Windows32 threads specific definitions. The windows32 threading model 36117395Skan does not map well into pthread-inspired gcc's threading model, and so 3796263Sobrien there are caveats one needs to be aware of. 3896263Sobrien 3996263Sobrien 1. The destructor supplied to __gthread_key_create is ignored for 40117395Skan generic x86-win32 ports. This will certainly cause memory leaks 41117395Skan due to unreclaimed eh contexts (sizeof (eh_context) is at least 4296263Sobrien 24 bytes for x86 currently). 4396263Sobrien 4496263Sobrien This memory leak may be significant for long-running applications 4596263Sobrien that make heavy use of C++ EH. 4696263Sobrien 4796263Sobrien However, Mingw runtime (version 0.3 or newer) provides a mechanism 4896263Sobrien to emulate pthreads key dtors; the runtime provides a special DLL, 4996263Sobrien linked in if -mthreads option is specified, that runs the dtors in 5096263Sobrien the reverse order of registration when each thread exits. If 5196263Sobrien -mthreads option is not given, a stub is linked in instead of the 52117395Skan DLL, which results in memory leak. Other x86-win32 ports can use 5396263Sobrien the same technique of course to avoid the leak. 5496263Sobrien 5596263Sobrien 2. The error codes returned are non-POSIX like, and cast into ints. 56117395Skan This may cause incorrect error return due to truncation values on 5796263Sobrien hw where sizeof (DWORD) > sizeof (int). 58117395Skan 59146895Skan 3. We are currently using a special mutex instead of the Critical 60146895Skan Sections, since Win9x does not support TryEnterCriticalSection 61146895Skan (while NT does). 62117395Skan 6396263Sobrien The basic framework should work well enough. In the long term, GCC 6496263Sobrien needs to use Structured Exception Handling on Windows32. */ 6596263Sobrien 6696263Sobrien#define __GTHREADS 1 6796263Sobrien 6896263Sobrien#include <errno.h> 6996263Sobrien#ifdef __MINGW32__ 7096263Sobrien#include <_mingw.h> 7196263Sobrien#endif 7296263Sobrien 7396263Sobrien#ifdef _LIBOBJC 7496263Sobrien 7596263Sobrien/* This is necessary to prevent windef.h (included from windows.h) from 76169689Skan defining its own BOOL as a typedef. */ 7796263Sobrien#ifndef __OBJC__ 7896263Sobrien#define __OBJC__ 7996263Sobrien#endif 8096263Sobrien#include <windows.h> 81117395Skan/* Now undef the windows BOOL. */ 8296263Sobrien#undef BOOL 8396263Sobrien 8496263Sobrien/* Key structure for maintaining thread specific storage */ 85117395Skanstatic DWORD __gthread_objc_data_tls = (DWORD) -1; 8696263Sobrien 8796263Sobrien/* Backend initialization functions */ 8896263Sobrien 8996263Sobrien/* Initialize the threads subsystem. */ 9096263Sobrienint 91117395Skan__gthread_objc_init_thread_system (void) 9296263Sobrien{ 93169689Skan /* Initialize the thread storage key. */ 94117395Skan if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1) 9596263Sobrien return 0; 9696263Sobrien else 9796263Sobrien return -1; 9896263Sobrien} 9996263Sobrien 10096263Sobrien/* Close the threads subsystem. */ 10196263Sobrienint 102117395Skan__gthread_objc_close_thread_system (void) 10396263Sobrien{ 104117395Skan if (__gthread_objc_data_tls != (DWORD) -1) 105117395Skan TlsFree (__gthread_objc_data_tls); 10696263Sobrien return 0; 10796263Sobrien} 10896263Sobrien 10996263Sobrien/* Backend thread functions */ 11096263Sobrien 11196263Sobrien/* Create a new thread of execution. */ 11296263Sobrienobjc_thread_t 113117395Skan__gthread_objc_thread_detach (void (*func)(void *arg), void *arg) 11496263Sobrien{ 11596263Sobrien DWORD thread_id = 0; 11696263Sobrien HANDLE win32_handle; 11796263Sobrien 118117395Skan if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func, 119117395Skan arg, 0, &thread_id))) 12096263Sobrien thread_id = 0; 121117395Skan 122117395Skan return (objc_thread_t) thread_id; 12396263Sobrien} 12496263Sobrien 12596263Sobrien/* Set the current thread's priority. */ 12696263Sobrienint 127117395Skan__gthread_objc_thread_set_priority (int priority) 12896263Sobrien{ 12996263Sobrien int sys_priority = 0; 13096263Sobrien 13196263Sobrien switch (priority) 13296263Sobrien { 13396263Sobrien case OBJC_THREAD_INTERACTIVE_PRIORITY: 13496263Sobrien sys_priority = THREAD_PRIORITY_NORMAL; 13596263Sobrien break; 13696263Sobrien default: 13796263Sobrien case OBJC_THREAD_BACKGROUND_PRIORITY: 13896263Sobrien sys_priority = THREAD_PRIORITY_BELOW_NORMAL; 13996263Sobrien break; 14096263Sobrien case OBJC_THREAD_LOW_PRIORITY: 14196263Sobrien sys_priority = THREAD_PRIORITY_LOWEST; 14296263Sobrien break; 14396263Sobrien } 14496263Sobrien 14596263Sobrien /* Change priority */ 146117395Skan if (SetThreadPriority (GetCurrentThread (), sys_priority)) 14796263Sobrien return 0; 14896263Sobrien else 14996263Sobrien return -1; 15096263Sobrien} 15196263Sobrien 15296263Sobrien/* Return the current thread's priority. */ 15396263Sobrienint 154117395Skan__gthread_objc_thread_get_priority (void) 15596263Sobrien{ 15696263Sobrien int sys_priority; 15796263Sobrien 158117395Skan sys_priority = GetThreadPriority (GetCurrentThread ()); 159117395Skan 16096263Sobrien switch (sys_priority) 16196263Sobrien { 16296263Sobrien case THREAD_PRIORITY_HIGHEST: 16396263Sobrien case THREAD_PRIORITY_TIME_CRITICAL: 16496263Sobrien case THREAD_PRIORITY_ABOVE_NORMAL: 16596263Sobrien case THREAD_PRIORITY_NORMAL: 16696263Sobrien return OBJC_THREAD_INTERACTIVE_PRIORITY; 16796263Sobrien 16896263Sobrien default: 16996263Sobrien case THREAD_PRIORITY_BELOW_NORMAL: 17096263Sobrien return OBJC_THREAD_BACKGROUND_PRIORITY; 171117395Skan 17296263Sobrien case THREAD_PRIORITY_IDLE: 17396263Sobrien case THREAD_PRIORITY_LOWEST: 17496263Sobrien return OBJC_THREAD_LOW_PRIORITY; 17596263Sobrien } 17696263Sobrien 17796263Sobrien /* Couldn't get priority. */ 17896263Sobrien return -1; 17996263Sobrien} 18096263Sobrien 18196263Sobrien/* Yield our process time to another thread. */ 18296263Sobrienvoid 183117395Skan__gthread_objc_thread_yield (void) 18496263Sobrien{ 185117395Skan Sleep (0); 18696263Sobrien} 18796263Sobrien 18896263Sobrien/* Terminate the current thread. */ 18996263Sobrienint 190117395Skan__gthread_objc_thread_exit (void) 19196263Sobrien{ 19296263Sobrien /* exit the thread */ 193117395Skan ExitThread (__objc_thread_exit_status); 19496263Sobrien 19596263Sobrien /* Failed if we reached here */ 19696263Sobrien return -1; 19796263Sobrien} 19896263Sobrien 19996263Sobrien/* Returns an integer value which uniquely describes a thread. */ 20096263Sobrienobjc_thread_t 201117395Skan__gthread_objc_thread_id (void) 20296263Sobrien{ 203117395Skan return (objc_thread_t) GetCurrentThreadId (); 20496263Sobrien} 20596263Sobrien 20696263Sobrien/* Sets the thread's local storage pointer. */ 20796263Sobrienint 208117395Skan__gthread_objc_thread_set_data (void *value) 20996263Sobrien{ 210117395Skan if (TlsSetValue (__gthread_objc_data_tls, value)) 21196263Sobrien return 0; 21296263Sobrien else 21396263Sobrien return -1; 21496263Sobrien} 21596263Sobrien 21696263Sobrien/* Returns the thread's local storage pointer. */ 21796263Sobrienvoid * 218117395Skan__gthread_objc_thread_get_data (void) 21996263Sobrien{ 22096263Sobrien DWORD lasterror; 22196263Sobrien void *ptr; 22296263Sobrien 223117395Skan lasterror = GetLastError (); 22496263Sobrien 225117395Skan ptr = TlsGetValue (__gthread_objc_data_tls); /* Return thread data. */ 22696263Sobrien 227117395Skan SetLastError (lasterror); 22896263Sobrien 22996263Sobrien return ptr; 23096263Sobrien} 23196263Sobrien 23296263Sobrien/* Backend mutex functions */ 23396263Sobrien 23496263Sobrien/* Allocate a mutex. */ 23596263Sobrienint 236117395Skan__gthread_objc_mutex_allocate (objc_mutex_t mutex) 23796263Sobrien{ 238117395Skan if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL) 23996263Sobrien return -1; 24096263Sobrien else 24196263Sobrien return 0; 24296263Sobrien} 24396263Sobrien 24496263Sobrien/* Deallocate a mutex. */ 24596263Sobrienint 246117395Skan__gthread_objc_mutex_deallocate (objc_mutex_t mutex) 24796263Sobrien{ 248117395Skan CloseHandle ((HANDLE) (mutex->backend)); 24996263Sobrien return 0; 25096263Sobrien} 25196263Sobrien 25296263Sobrien/* Grab a lock on a mutex. */ 25396263Sobrienint 254117395Skan__gthread_objc_mutex_lock (objc_mutex_t mutex) 25596263Sobrien{ 25696263Sobrien int status; 25796263Sobrien 258117395Skan status = WaitForSingleObject ((HANDLE) (mutex->backend), INFINITE); 25996263Sobrien if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) 26096263Sobrien return -1; 26196263Sobrien else 26296263Sobrien return 0; 26396263Sobrien} 26496263Sobrien 26596263Sobrien/* Try to grab a lock on a mutex. */ 26696263Sobrienint 267117395Skan__gthread_objc_mutex_trylock (objc_mutex_t mutex) 26896263Sobrien{ 26996263Sobrien int status; 27096263Sobrien 271117395Skan status = WaitForSingleObject ((HANDLE) (mutex->backend), 0); 27296263Sobrien if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED) 27396263Sobrien return -1; 27496263Sobrien else 27596263Sobrien return 0; 27696263Sobrien} 27796263Sobrien 27896263Sobrien/* Unlock the mutex */ 27996263Sobrienint 280117395Skan__gthread_objc_mutex_unlock (objc_mutex_t mutex) 28196263Sobrien{ 282117395Skan if (ReleaseMutex ((HANDLE) (mutex->backend)) == 0) 28396263Sobrien return -1; 28496263Sobrien else 28596263Sobrien return 0; 28696263Sobrien} 28796263Sobrien 28896263Sobrien/* Backend condition mutex functions */ 28996263Sobrien 29096263Sobrien/* Allocate a condition. */ 29196263Sobrienint 292117395Skan__gthread_objc_condition_allocate (objc_condition_t condition) 29396263Sobrien{ 29496263Sobrien /* Unimplemented. */ 29596263Sobrien return -1; 29696263Sobrien} 29796263Sobrien 29896263Sobrien/* Deallocate a condition. */ 29996263Sobrienint 300117395Skan__gthread_objc_condition_deallocate (objc_condition_t condition) 30196263Sobrien{ 30296263Sobrien /* Unimplemented. */ 30396263Sobrien return -1; 30496263Sobrien} 30596263Sobrien 30696263Sobrien/* Wait on the condition */ 30796263Sobrienint 308117395Skan__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex) 30996263Sobrien{ 31096263Sobrien /* Unimplemented. */ 31196263Sobrien return -1; 31296263Sobrien} 31396263Sobrien 31496263Sobrien/* Wake up all threads waiting on this condition. */ 31596263Sobrienint 316117395Skan__gthread_objc_condition_broadcast (objc_condition_t condition) 31796263Sobrien{ 31896263Sobrien /* Unimplemented. */ 31996263Sobrien return -1; 32096263Sobrien} 32196263Sobrien 32296263Sobrien/* Wake up one thread waiting on this condition. */ 32396263Sobrienint 324117395Skan__gthread_objc_condition_signal (objc_condition_t condition) 32596263Sobrien{ 32696263Sobrien /* Unimplemented. */ 32796263Sobrien return -1; 32896263Sobrien} 32996263Sobrien 33096263Sobrien#else /* _LIBOBJC */ 33196263Sobrien 332117395Skan#ifdef __cplusplus 333117395Skanextern "C" { 334117395Skan#endif 33596263Sobrien 336117395Skantypedef unsigned long __gthread_key_t; 33796263Sobrien 33896263Sobrientypedef struct { 33996263Sobrien int done; 34096263Sobrien long started; 34196263Sobrien} __gthread_once_t; 34296263Sobrien 343146895Skantypedef struct { 344146895Skan long counter; 345146895Skan void *sema; 346146895Skan} __gthread_mutex_t; 34796263Sobrien 348169689Skantypedef struct { 349169689Skan long counter; 350169689Skan long depth; 351169689Skan unsigned long owner; 352169689Skan void *sema; 353169689Skan} __gthread_recursive_mutex_t; 354169689Skan 355117395Skan#define __GTHREAD_ONCE_INIT {0, -1} 35696263Sobrien#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function 357146895Skan#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0} 358169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \ 359169689Skan __gthread_recursive_mutex_init_function 360169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0} 36196263Sobrien 36296263Sobrien#if __MINGW32_MAJOR_VERSION >= 1 || \ 36396263Sobrien (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2) 36496263Sobrien#define MINGW32_SUPPORTS_MT_EH 1 365117395Skan/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero 366117395Skan if -mthreads option was specified, or 0 otherwise. This is to get around 36796263Sobrien the lack of weak symbols in PE-COFF. */ 36896263Sobrienextern int _CRT_MT; 369117395Skanextern int __mingwthr_key_dtor (unsigned long, void (*) (void *)); 370117395Skan#endif /* __MINGW32__ version */ 37196263Sobrien 372169689Skan/* The Windows95 kernel does not export InterlockedCompareExchange. 373169689Skan This provides a substitute. When building apps that reference 374169689Skan gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES 375169689Skan macro must be defined if Windows95 is a target. Currently 376169689Skan gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */ 377146895Skan#ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES 378146895Skanstatic inline long 379146895Skan__gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand) 380146895Skan{ 381146895Skan long result; 382146895Skan __asm__ __volatile__ ("\n\ 383146895Skan lock\n\ 384146895Skan cmpxchg{l} {%4, %1|%1, %4}\n" 385146895Skan : "=a" (result), "=m" (*dest) 386146895Skan : "0" (comperand), "m" (*dest), "r" (xchg) 387146895Skan : "cc"); 388146895Skan return result; 389146895Skan} 390146895Skan#define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg 391146895Skan#else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */ 392146895Skan#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange 393146895Skan#endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */ 394146895Skan 39596263Sobrienstatic inline int 39696263Sobrien__gthread_active_p (void) 39796263Sobrien{ 39896263Sobrien#ifdef MINGW32_SUPPORTS_MT_EH 39996263Sobrien return _CRT_MT; 40096263Sobrien#else 40196263Sobrien return 1; 40296263Sobrien#endif 40396263Sobrien} 40496263Sobrien 405132718Skan#if __GTHREAD_HIDE_WIN32API 406117395Skan 407117395Skan/* The implementations are in config/i386/gthr-win32.c in libgcc.a. 408117395Skan Only stubs are exposed to avoid polluting the C++ namespace with 409117395Skan windows api definitions. */ 410117395Skan 411117395Skanextern int __gthr_win32_once (__gthread_once_t *, void (*) (void)); 412117395Skanextern int __gthr_win32_key_create (__gthread_key_t *, void (*) (void*)); 413117395Skanextern int __gthr_win32_key_delete (__gthread_key_t); 414117395Skanextern void * __gthr_win32_getspecific (__gthread_key_t); 415117395Skanextern int __gthr_win32_setspecific (__gthread_key_t, const void *); 416117395Skanextern void __gthr_win32_mutex_init_function (__gthread_mutex_t *); 417117395Skanextern int __gthr_win32_mutex_lock (__gthread_mutex_t *); 418117395Skanextern int __gthr_win32_mutex_trylock (__gthread_mutex_t *); 419117395Skanextern int __gthr_win32_mutex_unlock (__gthread_mutex_t *); 420169689Skanextern void 421169689Skan __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *); 422169689Skanextern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *); 423169689Skanextern int 424169689Skan __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *); 425169689Skanextern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *); 426117395Skan 42796263Sobrienstatic inline int 42896263Sobrien__gthread_once (__gthread_once_t *once, void (*func) (void)) 42996263Sobrien{ 430117395Skan if (__gthread_active_p ()) 431117395Skan return __gthr_win32_once (once, func); 432117395Skan else 433117395Skan return -1; 434117395Skan} 435117395Skan 436117395Skanstatic inline int 437117395Skan__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) 438117395Skan{ 439117395Skan return __gthr_win32_key_create (key, dtor); 440117395Skan} 441117395Skan 442117395Skanstatic inline int 443117395Skan__gthread_key_delete (__gthread_key_t key) 444117395Skan{ 445117395Skan return __gthr_win32_key_delete (key); 446117395Skan} 447117395Skan 448117395Skanstatic inline void * 449117395Skan__gthread_getspecific (__gthread_key_t key) 450117395Skan{ 451117395Skan return __gthr_win32_getspecific (key); 452117395Skan} 453117395Skan 454117395Skanstatic inline int 455117395Skan__gthread_setspecific (__gthread_key_t key, const void *ptr) 456117395Skan{ 457117395Skan return __gthr_win32_setspecific (key, ptr); 458117395Skan} 459117395Skan 460117395Skanstatic inline void 461117395Skan__gthread_mutex_init_function (__gthread_mutex_t *mutex) 462117395Skan{ 463117395Skan __gthr_win32_mutex_init_function (mutex); 464117395Skan} 465117395Skan 466117395Skanstatic inline int 467117395Skan__gthread_mutex_lock (__gthread_mutex_t *mutex) 468117395Skan{ 469117395Skan if (__gthread_active_p ()) 470117395Skan return __gthr_win32_mutex_lock (mutex); 471117395Skan else 472117395Skan return 0; 473117395Skan} 474117395Skan 475117395Skanstatic inline int 476117395Skan__gthread_mutex_trylock (__gthread_mutex_t *mutex) 477117395Skan{ 478117395Skan if (__gthread_active_p ()) 479117395Skan return __gthr_win32_mutex_trylock (mutex); 480117395Skan else 481117395Skan return 0; 482117395Skan} 483117395Skan 484117395Skanstatic inline int 485117395Skan__gthread_mutex_unlock (__gthread_mutex_t *mutex) 486117395Skan{ 487117395Skan if (__gthread_active_p ()) 488117395Skan return __gthr_win32_mutex_unlock (mutex); 489117395Skan else 490117395Skan return 0; 491117395Skan} 492117395Skan 493169689Skanstatic inline void 494169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex) 495169689Skan{ 496169689Skan __gthr_win32_recursive_mutex_init_function (mutex); 497169689Skan} 498169689Skan 499169689Skanstatic inline int 500169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) 501169689Skan{ 502169689Skan if (__gthread_active_p ()) 503169689Skan return __gthr_win32_recursive_mutex_lock (mutex); 504169689Skan else 505169689Skan return 0; 506169689Skan} 507169689Skan 508169689Skanstatic inline int 509169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) 510169689Skan{ 511169689Skan if (__gthread_active_p ()) 512169689Skan return __gthr_win32_recursive_mutex_trylock (mutex); 513169689Skan else 514169689Skan return 0; 515169689Skan} 516169689Skan 517169689Skanstatic inline int 518169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) 519169689Skan{ 520169689Skan if (__gthread_active_p ()) 521169689Skan return __gthr_win32_recursive_mutex_unlock (mutex); 522169689Skan else 523169689Skan return 0; 524169689Skan} 525169689Skan 526117395Skan#else /* ! __GTHREAD_HIDE_WIN32API */ 527117395Skan 528117395Skan#include <windows.h> 529117395Skan#include <errno.h> 530117395Skan 531117395Skanstatic inline int 532117395Skan__gthread_once (__gthread_once_t *once, void (*func) (void)) 533117395Skan{ 53496263Sobrien if (! __gthread_active_p ()) 53596263Sobrien return -1; 53696263Sobrien else if (once == NULL || func == NULL) 53796263Sobrien return EINVAL; 53896263Sobrien 53996263Sobrien if (! once->done) 54096263Sobrien { 54196263Sobrien if (InterlockedIncrement (&(once->started)) == 0) 542117395Skan { 54396263Sobrien (*func) (); 54496263Sobrien once->done = TRUE; 54596263Sobrien } 54696263Sobrien else 54796263Sobrien { 548117395Skan /* Another thread is currently executing the code, so wait for it 549117395Skan to finish; yield the CPU in the meantime. If performance 550117395Skan does become an issue, the solution is to use an Event that 551117395Skan we wait on here (and set above), but that implies a place to 552117395Skan create the event before this routine is called. */ 55396263Sobrien while (! once->done) 55496263Sobrien Sleep (0); 55596263Sobrien } 55696263Sobrien } 557117395Skan 55896263Sobrien return 0; 55996263Sobrien} 56096263Sobrien 56196263Sobrien/* Windows32 thread local keys don't support destructors; this leads to 562117395Skan leaks, especially in threaded applications making extensive use of 56396263Sobrien C++ EH. Mingw uses a thread-support DLL to work-around this problem. */ 56496263Sobrienstatic inline int 56596263Sobrien__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *)) 56696263Sobrien{ 56796263Sobrien int status = 0; 56896263Sobrien DWORD tls_index = TlsAlloc (); 56996263Sobrien if (tls_index != 0xFFFFFFFF) 57096263Sobrien { 57196263Sobrien *key = tls_index; 57296263Sobrien#ifdef MINGW32_SUPPORTS_MT_EH 57396263Sobrien /* Mingw runtime will run the dtors in reverse order for each thread 57496263Sobrien when the thread exits. */ 57596263Sobrien status = __mingwthr_key_dtor (*key, dtor); 57696263Sobrien#endif 57796263Sobrien } 57896263Sobrien else 57996263Sobrien status = (int) GetLastError (); 58096263Sobrien return status; 58196263Sobrien} 58296263Sobrien 58396263Sobrienstatic inline int 58496263Sobrien__gthread_key_delete (__gthread_key_t key) 58596263Sobrien{ 58696263Sobrien return (TlsFree (key) != 0) ? 0 : (int) GetLastError (); 58796263Sobrien} 58896263Sobrien 58996263Sobrienstatic inline void * 59096263Sobrien__gthread_getspecific (__gthread_key_t key) 59196263Sobrien{ 59296263Sobrien DWORD lasterror; 59396263Sobrien void *ptr; 59496263Sobrien 595117395Skan lasterror = GetLastError (); 59696263Sobrien 597117395Skan ptr = TlsGetValue (key); 59896263Sobrien 599117395Skan SetLastError (lasterror); 60096263Sobrien 60196263Sobrien return ptr; 60296263Sobrien} 60396263Sobrien 60496263Sobrienstatic inline int 60596263Sobrien__gthread_setspecific (__gthread_key_t key, const void *ptr) 60696263Sobrien{ 60796263Sobrien return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError (); 60896263Sobrien} 60996263Sobrien 61096263Sobrienstatic inline void 61196263Sobrien__gthread_mutex_init_function (__gthread_mutex_t *mutex) 61296263Sobrien{ 613146895Skan mutex->counter = -1; 614146895Skan mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL); 61596263Sobrien} 61696263Sobrien 61796263Sobrienstatic inline int 61896263Sobrien__gthread_mutex_lock (__gthread_mutex_t *mutex) 61996263Sobrien{ 62096263Sobrien int status = 0; 62196263Sobrien 62296263Sobrien if (__gthread_active_p ()) 62396263Sobrien { 624146895Skan if (InterlockedIncrement (&mutex->counter) == 0 || 625146895Skan WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0) 62696263Sobrien status = 0; 62796263Sobrien else 628146895Skan { 629146895Skan /* WaitForSingleObject returns WAIT_FAILED, and we can only do 630146895Skan some best-effort cleanup here. */ 631146895Skan InterlockedDecrement (&mutex->counter); 632146895Skan status = 1; 633146895Skan } 63496263Sobrien } 63596263Sobrien return status; 63696263Sobrien} 63796263Sobrien 63896263Sobrienstatic inline int 63996263Sobrien__gthread_mutex_trylock (__gthread_mutex_t *mutex) 64096263Sobrien{ 64196263Sobrien int status = 0; 64296263Sobrien 64396263Sobrien if (__gthread_active_p ()) 64496263Sobrien { 645146895Skan if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0) 64696263Sobrien status = 0; 64796263Sobrien else 64896263Sobrien status = 1; 64996263Sobrien } 65096263Sobrien return status; 65196263Sobrien} 65296263Sobrien 65396263Sobrienstatic inline int 65496263Sobrien__gthread_mutex_unlock (__gthread_mutex_t *mutex) 65596263Sobrien{ 65696263Sobrien if (__gthread_active_p ()) 657146895Skan { 658146895Skan if (InterlockedDecrement (&mutex->counter) >= 0) 659146895Skan return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1; 660146895Skan } 661146895Skan return 0; 66296263Sobrien} 66396263Sobrien 664169689Skanstatic inline void 665169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex) 666169689Skan{ 667169689Skan mutex->counter = -1; 668169689Skan mutex->depth = 0; 669169689Skan mutex->owner = 0; 670169689Skan mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL); 671169689Skan} 672169689Skan 673169689Skanstatic inline int 674169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) 675169689Skan{ 676169689Skan if (__gthread_active_p ()) 677169689Skan { 678169689Skan DWORD me = GetCurrentThreadId(); 679169689Skan if (InterlockedIncrement (&mutex->counter) == 0) 680169689Skan { 681169689Skan mutex->depth = 1; 682169689Skan mutex->owner = me; 683169689Skan } 684169689Skan else if (mutex->owner == me) 685169689Skan { 686169689Skan InterlockedDecrement (&mutex->counter); 687169689Skan ++(mutex->depth); 688169689Skan } 689169689Skan else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0) 690169689Skan { 691169689Skan mutex->depth = 1; 692169689Skan mutex->owner = me; 693169689Skan } 694169689Skan else 695169689Skan { 696169689Skan /* WaitForSingleObject returns WAIT_FAILED, and we can only do 697169689Skan some best-effort cleanup here. */ 698169689Skan InterlockedDecrement (&mutex->counter); 699169689Skan return 1; 700169689Skan } 701169689Skan } 702169689Skan return 0; 703169689Skan} 704169689Skan 705169689Skanstatic inline int 706169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) 707169689Skan{ 708169689Skan if (__gthread_active_p ()) 709169689Skan { 710169689Skan DWORD me = GetCurrentThreadId(); 711169689Skan if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0) 712169689Skan { 713169689Skan mutex->depth = 1; 714169689Skan mutex->owner = me; 715169689Skan } 716169689Skan else if (mutex->owner == me) 717169689Skan ++(mutex->depth); 718169689Skan else 719169689Skan return 1; 720169689Skan } 721169689Skan return 0; 722169689Skan} 723169689Skan 724169689Skanstatic inline int 725169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) 726169689Skan{ 727169689Skan if (__gthread_active_p ()) 728169689Skan { 729169689Skan --(mutex->depth); 730169689Skan if (mutex->depth == 0) 731169689Skan { 732169689Skan mutex->owner = 0; 733169689Skan 734169689Skan if (InterlockedDecrement (&mutex->counter) >= 0) 735169689Skan return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1; 736169689Skan } 737169689Skan } 738169689Skan return 0; 739169689Skan} 740169689Skan 741117395Skan#endif /* __GTHREAD_HIDE_WIN32API */ 742117395Skan 743117395Skan#ifdef __cplusplus 744117395Skan} 745117395Skan#endif 746117395Skan 74796263Sobrien#endif /* _LIBOBJC */ 74896263Sobrien 74996263Sobrien#endif /* ! GCC_GTHR_WIN32_H */ 750