1117395Skan/* Implementation of W32-specific threads compatibility routines for 2132718Skan libgcc2. */ 3117395Skan 4132718Skan/* Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation, Inc. 5117395Skan Contributed by Mumit Khan <khan@xraylith.wisc.edu>. 6117395Skan Modified and moved to separate file by Danny Smith 7117395Skan <dannysmith@users.sourceforge.net>. 8117395Skan 9117395SkanThis file is part of GCC. 10117395Skan 11117395SkanGCC is free software; you can redistribute it and/or modify it under 12117395Skanthe terms of the GNU General Public License as published by the Free 13117395SkanSoftware Foundation; either version 2, or (at your option) any later 14117395Skanversion. 15117395Skan 16117395SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 17117395SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 18117395SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19117395Skanfor more details. 20117395Skan 21117395SkanYou should have received a copy of the GNU General Public License 22117395Skanalong with GCC; see the file COPYING. If not, write to the Free 23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 24169689Skan02110-1301, USA. */ 25117395Skan 26117395Skan/* As a special exception, if you link this library with other files, 27117395Skan some of which are compiled with GCC, to produce an executable, 28117395Skan this library does not by itself cause the resulting executable 29117395Skan to be covered by the GNU General Public License. 30117395Skan This exception does not however invalidate any other reasons why 31117395Skan the executable file might be covered by the GNU General Public License. */ 32117395Skan 33117395Skan 34146895Skan#include <windows.h> 35117395Skan#ifndef __GTHREAD_HIDE_WIN32API 36119256Skan# define __GTHREAD_HIDE_WIN32API 1 37117395Skan#endif 38146895Skan#undef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES 39146895Skan#define __GTHREAD_I486_INLINE_LOCK_PRIMITIVES 40117395Skan#include <gthr-win32.h> 41117395Skan 42117395Skan/* Windows32 threads specific definitions. The windows32 threading model 43117395Skan does not map well into pthread-inspired gcc's threading model, and so 44117395Skan there are caveats one needs to be aware of. 45117395Skan 46117395Skan 1. The destructor supplied to __gthread_key_create is ignored for 47117395Skan generic x86-win32 ports. This will certainly cause memory leaks 48117395Skan due to unreclaimed eh contexts (sizeof (eh_context) is at least 49117395Skan 24 bytes for x86 currently). 50117395Skan 51117395Skan This memory leak may be significant for long-running applications 52117395Skan that make heavy use of C++ EH. 53117395Skan 54117395Skan However, Mingw runtime (version 0.3 or newer) provides a mechanism 55117395Skan to emulate pthreads key dtors; the runtime provides a special DLL, 56117395Skan linked in if -mthreads option is specified, that runs the dtors in 57117395Skan the reverse order of registration when each thread exits. If 58117395Skan -mthreads option is not given, a stub is linked in instead of the 59117395Skan DLL, which results in memory leak. Other x86-win32 ports can use 60117395Skan the same technique of course to avoid the leak. 61117395Skan 62117395Skan 2. The error codes returned are non-POSIX like, and cast into ints. 63117395Skan This may cause incorrect error return due to truncation values on 64117395Skan hw where sizeof (DWORD) > sizeof (int). 65117395Skan 66146895Skan 3. We are currently using a special mutex instead of the Critical 67146895Skan Sections, since Win9x does not support TryEnterCriticalSection 68146895Skan (while NT does). 69117395Skan 70117395Skan The basic framework should work well enough. In the long term, GCC 71117395Skan needs to use Structured Exception Handling on Windows32. */ 72117395Skan 73117395Skanint 74117395Skan__gthr_win32_once (__gthread_once_t *once, void (*func) (void)) 75117395Skan{ 76117395Skan if (once == NULL || func == NULL) 77117395Skan return EINVAL; 78117395Skan 79117395Skan if (! once->done) 80117395Skan { 81117395Skan if (InterlockedIncrement (&(once->started)) == 0) 82117395Skan { 83117395Skan (*func) (); 84117395Skan once->done = TRUE; 85117395Skan } 86117395Skan else 87117395Skan { 88117395Skan /* Another thread is currently executing the code, so wait for it 89117395Skan to finish; yield the CPU in the meantime. If performance 90117395Skan does become an issue, the solution is to use an Event that 91117395Skan we wait on here (and set above), but that implies a place to 92117395Skan create the event before this routine is called. */ 93117395Skan while (! once->done) 94117395Skan Sleep (0); 95117395Skan } 96117395Skan } 97117395Skan return 0; 98117395Skan} 99117395Skan 100117395Skan/* Windows32 thread local keys don't support destructors; this leads to 101117395Skan leaks, especially in threaded applications making extensive use of 102117395Skan C++ EH. Mingw uses a thread-support DLL to work-around this problem. */ 103117395Skan 104117395Skanint 105117395Skan__gthr_win32_key_create (__gthread_key_t *key, void (*dtor) (void *)) 106117395Skan{ 107117395Skan int status = 0; 108117395Skan DWORD tls_index = TlsAlloc (); 109117395Skan if (tls_index != 0xFFFFFFFF) 110117395Skan { 111117395Skan *key = tls_index; 112117395Skan#ifdef MINGW32_SUPPORTS_MT_EH 113117395Skan /* Mingw runtime will run the dtors in reverse order for each thread 114117395Skan when the thread exits. */ 115117395Skan status = __mingwthr_key_dtor (*key, dtor); 116117395Skan#endif 117117395Skan } 118117395Skan else 119117395Skan status = (int) GetLastError (); 120117395Skan return status; 121117395Skan} 122117395Skan 123117395Skanint 124117395Skan__gthr_win32_key_delete (__gthread_key_t key) 125117395Skan{ 126117395Skan return (TlsFree (key) != 0) ? 0 : (int) GetLastError (); 127117395Skan} 128117395Skan 129117395Skanvoid * 130117395Skan__gthr_win32_getspecific (__gthread_key_t key) 131117395Skan{ 132117395Skan DWORD lasterror; 133117395Skan void *ptr; 134117395Skan lasterror = GetLastError(); 135117395Skan ptr = TlsGetValue(key); 136117395Skan SetLastError( lasterror ); 137117395Skan return ptr; 138117395Skan} 139117395Skan 140117395Skanint 141117395Skan__gthr_win32_setspecific (__gthread_key_t key, const void *ptr) 142117395Skan{ 143117395Skan return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError (); 144117395Skan} 145117395Skan 146117395Skanvoid 147117395Skan__gthr_win32_mutex_init_function (__gthread_mutex_t *mutex) 148117395Skan{ 149146895Skan mutex->counter = -1; 150146895Skan mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL); 151117395Skan} 152117395Skan 153117395Skanint 154117395Skan__gthr_win32_mutex_lock (__gthread_mutex_t *mutex) 155117395Skan{ 156146895Skan if (InterlockedIncrement (&mutex->counter) == 0 || 157146895Skan WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0) 158117395Skan return 0; 159117395Skan else 160146895Skan { 161146895Skan /* WaitForSingleObject returns WAIT_FAILED, and we can only do 162146895Skan some best-effort cleanup here. */ 163146895Skan InterlockedDecrement (&mutex->counter); 164146895Skan return 1; 165146895Skan } 166117395Skan} 167117395Skan 168117395Skanint 169117395Skan__gthr_win32_mutex_trylock (__gthread_mutex_t *mutex) 170117395Skan{ 171146895Skan if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0) 172117395Skan return 0; 173117395Skan else 174117395Skan return 1; 175117395Skan} 176117395Skan 177117395Skanint 178117395Skan__gthr_win32_mutex_unlock (__gthread_mutex_t *mutex) 179117395Skan{ 180146895Skan if (InterlockedDecrement (&mutex->counter) >= 0) 181146895Skan return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1; 182146895Skan else 183146895Skan return 0; 184117395Skan} 185169689Skan 186169689Skanvoid 187169689Skan__gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex) 188169689Skan{ 189169689Skan mutex->counter = -1; 190169689Skan mutex->depth = 0; 191169689Skan mutex->owner = 0; 192169689Skan mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL); 193169689Skan} 194169689Skan 195169689Skanint 196169689Skan__gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex) 197169689Skan{ 198169689Skan DWORD me = GetCurrentThreadId(); 199169689Skan if (InterlockedIncrement (&mutex->counter) == 0) 200169689Skan { 201169689Skan mutex->depth = 1; 202169689Skan mutex->owner = me; 203169689Skan } 204169689Skan else if (mutex->owner == me) 205169689Skan { 206169689Skan InterlockedDecrement (&mutex->counter); 207169689Skan ++(mutex->depth); 208169689Skan } 209169689Skan else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0) 210169689Skan { 211169689Skan mutex->depth = 1; 212169689Skan mutex->owner = me; 213169689Skan } 214169689Skan else 215169689Skan { 216169689Skan /* WaitForSingleObject returns WAIT_FAILED, and we can only do 217169689Skan some best-effort cleanup here. */ 218169689Skan InterlockedDecrement (&mutex->counter); 219169689Skan return 1; 220169689Skan } 221169689Skan return 0; 222169689Skan} 223169689Skan 224169689Skanint 225169689Skan__gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex) 226169689Skan{ 227169689Skan DWORD me = GetCurrentThreadId(); 228169689Skan if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0) 229169689Skan { 230169689Skan mutex->depth = 1; 231169689Skan mutex->owner = me; 232169689Skan } 233169689Skan else if (mutex->owner == me) 234169689Skan ++(mutex->depth); 235169689Skan else 236169689Skan return 1; 237169689Skan 238169689Skan return 0; 239169689Skan} 240169689Skan 241169689Skanint 242169689Skan__gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex) 243169689Skan{ 244169689Skan --(mutex->depth); 245169689Skan if (mutex->depth == 0) 246169689Skan { 247169689Skan mutex->owner = 0; 248169689Skan 249169689Skan if (InterlockedDecrement (&mutex->counter) >= 0) 250169689Skan return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1; 251169689Skan } 252169689Skan 253169689Skan return 0; 254169689Skan} 255