1 2 /* This code implemented by Dag.Gruneau (at) elsa.preseco.comm.se */ 3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch (at) iso.ru */ 4 /* Eliminated some memory leaks, gsw (at) agere.com */ 5 6 #include <windows.h> 7 #include <limits.h> 8 #ifdef HAVE_PROCESS_H 9 #include <process.h> 10 #endif 11 12 typedef struct NRMUTEX { 13 LONG owned ; 14 DWORD thread_id ; 15 HANDLE hevent ; 16 } NRMUTEX, *PNRMUTEX ; 17 18 19 BOOL 20 InitializeNonRecursiveMutex(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 28 VOID 29 DeleteNonRecursiveMutex(PNRMUTEX mutex) 30 { 31 /* No in-use check */ 32 CloseHandle(mutex->hevent) ; 33 mutex->hevent = NULL ; /* Just in case */ 34 } 35 36 DWORD 37 EnterNonRecursiveMutex(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 58 BOOL 59 LeaveNonRecursiveMutex(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 68 PNRMUTEX 69 AllocNonRecursiveMutex(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 80 void 81 FreeNonRecursiveMutex(PNRMUTEX mutex) 82 { 83 if (mutex) 84 { 85 DeleteNonRecursiveMutex(mutex) ; 86 free(mutex) ; 87 } 88 } 89 90 long PyThread_get_thread_ident(void); 91 92 /* 93 * Initialization of the C package, should not be needed. 94 */ 95 static void 96 PyThread__init_thread(void) 97 { 98 } 99 100 /* 101 * Thread support. 102 */ 103 104 typedef 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 110 thread start function and the internally used one. */ 111 #if defined(MS_WINCE) 112 static DWORD WINAPI 113 #else 114 static unsigned __stdcall 115 #endif 116 bootstrap(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 126 long 127 PyThread_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 */ 184 long 185 PyThread_get_thread_ident(void) 186 { 187 if (!initialized) 188 PyThread_init_thread(); 189 190 return GetCurrentThreadId(); 191 } 192 193 void 194 PyThread_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 */ 211 PyThread_type_lock 212 PyThread_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 227 void 228 PyThread_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 */ 241 int 242 PyThread_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 255 void 256 PyThread_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 */ 271 static 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 296 int 297 PyThread_create_key(void) 298 { 299 return (int) TlsAlloc(); 300 } 301 302 void 303 PyThread_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 */ 311 int 312 PyThread_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 328 void * 329 PyThread_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 343 void 344 PyThread_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 */ 355 void 356 PyThread_ReInitTLS(void) 357 {} 358 359 #endif 360