1 2/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ 3/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ 4/* Eliminated some memory leaks, gsw@agere.com */ 5 6#include <windows.h> 7#include <limits.h> 8#ifdef HAVE_PROCESS_H 9#include <process.h> 10#endif 11 12typedef struct NRMUTEX { 13 LONG owned ; 14 DWORD thread_id ; 15 HANDLE hevent ; 16} NRMUTEX, *PNRMUTEX ; 17 18 19BOOL 20InitializeNonRecursiveMutex(PNRMUTEX mutex) 21{ 22 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ 23 mutex->thread_id = 0 ; 24 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; 25 return mutex->hevent != NULL ; /* TRUE if the mutex is created */ 26} 27 28VOID 29DeleteNonRecursiveMutex(PNRMUTEX mutex) 30{ 31 /* No in-use check */ 32 CloseHandle(mutex->hevent) ; 33 mutex->hevent = NULL ; /* Just in case */ 34} 35 36DWORD 37EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) 38{ 39 /* Assume that the thread waits successfully */ 40 DWORD ret ; 41 42 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */ 43 if (!wait) 44 { 45 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) 46 return WAIT_TIMEOUT ; 47 ret = WAIT_OBJECT_0 ; 48 } 49 else 50 ret = InterlockedIncrement(&mutex->owned) ? 51 /* Some thread owns the mutex, let's wait... */ 52 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ; 53 54 mutex->thread_id = GetCurrentThreadId() ; /* We own it */ 55 return ret ; 56} 57 58BOOL 59LeaveNonRecursiveMutex(PNRMUTEX mutex) 60{ 61 /* We don't own the mutex */ 62 mutex->thread_id = 0 ; 63 return 64 InterlockedDecrement(&mutex->owned) < 0 || 65 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */ 66} 67 68PNRMUTEX 69AllocNonRecursiveMutex(void) 70{ 71 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ; 72 if (mutex && !InitializeNonRecursiveMutex(mutex)) 73 { 74 free(mutex) ; 75 mutex = NULL ; 76 } 77 return mutex ; 78} 79 80void 81FreeNonRecursiveMutex(PNRMUTEX mutex) 82{ 83 if (mutex) 84 { 85 DeleteNonRecursiveMutex(mutex) ; 86 free(mutex) ; 87 } 88} 89 90long PyThread_get_thread_ident(void); 91 92/* 93 * Initialization of the C package, should not be needed. 94 */ 95static void 96PyThread__init_thread(void) 97{ 98} 99 100/* 101 * Thread support. 102 */ 103 104typedef struct { 105 void (*func)(void*); 106 void *arg; 107} callobj; 108 109/* thunker to call adapt between the function type used by the system's 110thread start function and the internally used one. */ 111#if defined(MS_WINCE) 112static DWORD WINAPI 113#else 114static unsigned __stdcall 115#endif 116bootstrap(void *call) 117{ 118 callobj *obj = (callobj*)call; 119 void (*func)(void*) = obj->func; 120 void *arg = obj->arg; 121 HeapFree(GetProcessHeap(), 0, obj); 122 func(arg); 123 return 0; 124} 125 126long 127PyThread_start_new_thread(void (*func)(void *), void *arg) 128{ 129 HANDLE hThread; 130 unsigned threadID; 131 callobj *obj; 132 133 dprintf(("%ld: PyThread_start_new_thread called\n", 134 PyThread_get_thread_ident())); 135 if (!initialized) 136 PyThread_init_thread(); 137 138 obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); 139 if (!obj) 140 return -1; 141 obj->func = func; 142 obj->arg = arg; 143#if defined(MS_WINCE) 144 hThread = CreateThread(NULL, 145 Py_SAFE_DOWNCAST(_pythread_stacksize, Py_ssize_t, SIZE_T), 146 bootstrap, obj, 0, &threadID); 147#else 148 hThread = (HANDLE)_beginthreadex(0, 149 Py_SAFE_DOWNCAST(_pythread_stacksize, 150 Py_ssize_t, unsigned int), 151 bootstrap, obj, 152 0, &threadID); 153#endif 154 if (hThread == 0) { 155#if defined(MS_WINCE) 156 /* Save error in variable, to prevent PyThread_get_thread_ident 157 from clobbering it. */ 158 unsigned e = GetLastError(); 159 dprintf(("%ld: PyThread_start_new_thread failed, win32 error code %u\n", 160 PyThread_get_thread_ident(), e)); 161#else 162 /* I've seen errno == EAGAIN here, which means "there are 163 * too many threads". 164 */ 165 int e = errno; 166 dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n", 167 PyThread_get_thread_ident(), e)); 168#endif 169 threadID = (unsigned)-1; 170 HeapFree(GetProcessHeap(), 0, obj); 171 } 172 else { 173 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", 174 PyThread_get_thread_ident(), (void*)hThread)); 175 CloseHandle(hThread); 176 } 177 return (long) threadID; 178} 179 180/* 181 * Return the thread Id instead of a handle. The Id is said to uniquely identify the 182 * thread in the system 183 */ 184long 185PyThread_get_thread_ident(void) 186{ 187 if (!initialized) 188 PyThread_init_thread(); 189 190 return GetCurrentThreadId(); 191} 192 193void 194PyThread_exit_thread(void) 195{ 196 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident())); 197 if (!initialized) 198 exit(0); 199#if defined(MS_WINCE) 200 ExitThread(0); 201#else 202 _endthreadex(0); 203#endif 204} 205 206/* 207 * Lock support. It has too be implemented as semaphores. 208 * I [Dag] tried to implement it with mutex but I could find a way to 209 * tell whether a thread already own the lock or not. 210 */ 211PyThread_type_lock 212PyThread_allocate_lock(void) 213{ 214 PNRMUTEX aLock; 215 216 dprintf(("PyThread_allocate_lock called\n")); 217 if (!initialized) 218 PyThread_init_thread(); 219 220 aLock = AllocNonRecursiveMutex() ; 221 222 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); 223 224 return (PyThread_type_lock) aLock; 225} 226 227void 228PyThread_free_lock(PyThread_type_lock aLock) 229{ 230 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); 231 232 FreeNonRecursiveMutex(aLock) ; 233} 234 235/* 236 * Return 1 on success if the lock was acquired 237 * 238 * and 0 if the lock was not acquired. This means a 0 is returned 239 * if the lock has already been acquired by this thread! 240 */ 241int 242PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) 243{ 244 int success ; 245 246 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); 247 248 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ; 249 250 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); 251 252 return success; 253} 254 255void 256PyThread_release_lock(PyThread_type_lock aLock) 257{ 258 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); 259 260 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) 261 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock, GetLastError())); 262} 263 264/* minimum/maximum thread stack sizes supported */ 265#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ 266#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ 267 268/* set the thread stack size. 269 * Return 0 if size is valid, -1 otherwise. 270 */ 271static int 272_pythread_nt_set_stacksize(size_t size) 273{ 274 /* set to default */ 275 if (size == 0) { 276 _pythread_stacksize = 0; 277 return 0; 278 } 279 280 /* valid range? */ 281 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { 282 _pythread_stacksize = size; 283 return 0; 284 } 285 286 return -1; 287} 288 289#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x) 290 291 292/* use native Windows TLS functions */ 293#define Py_HAVE_NATIVE_TLS 294 295#ifdef Py_HAVE_NATIVE_TLS 296int 297PyThread_create_key(void) 298{ 299 return (int) TlsAlloc(); 300} 301 302void 303PyThread_delete_key(int key) 304{ 305 TlsFree(key); 306} 307 308/* We must be careful to emulate the strange semantics implemented in thread.c, 309 * where the value is only set if it hasn't been set before. 310 */ 311int 312PyThread_set_key_value(int key, void *value) 313{ 314 BOOL ok; 315 void *oldvalue; 316 317 assert(value != NULL); 318 oldvalue = TlsGetValue(key); 319 if (oldvalue != NULL) 320 /* ignore value if already set */ 321 return 0; 322 ok = TlsSetValue(key, value); 323 if (!ok) 324 return -1; 325 return 0; 326} 327 328void * 329PyThread_get_key_value(int key) 330{ 331 /* because TLS is used in the Py_END_ALLOW_THREAD macro, 332 * it is necessary to preserve the windows error state, because 333 * it is assumed to be preserved across the call to the macro. 334 * Ideally, the macro should be fixed, but it is simpler to 335 * do it here. 336 */ 337 DWORD error = GetLastError(); 338 void *result = TlsGetValue(key); 339 SetLastError(error); 340 return result; 341} 342 343void 344PyThread_delete_key_value(int key) 345{ 346 /* NULL is used as "key missing", and it is also the default 347 * given by TlsGetValue() if nothing has been set yet. 348 */ 349 TlsSetValue(key, NULL); 350} 351 352/* reinitialization of TLS is not necessary after fork when using 353 * the native TLS functions. And forking isn't supported on Windows either. 354 */ 355void 356PyThread_ReInitTLS(void) 357{} 358 359#endif 360