| OLD | NEW |
| 1 | 1 |
| 2 /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ | 2 /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ |
| 3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ | 3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ |
| 4 /* Eliminated some memory leaks, gsw@agere.com */ | 4 /* Eliminated some memory leaks, gsw@agere.com */ |
| 5 /* EXPERIMENTAL critical section & semaphore code by Phillip Sitbon, phillip@sit
bon.net */ |
| 5 | 6 |
| 6 #include <windows.h> | 7 #include <windows.h> |
| 7 #include <limits.h> | 8 #include <limits.h> |
| 8 #ifdef HAVE_PROCESS_H | 9 #ifdef HAVE_PROCESS_H |
| 9 #include <process.h> | 10 #include <process.h> |
| 10 #endif | 11 #endif |
| 11 | 12 |
| 12 typedef struct NRMUTEX { | 13 #define WITH_CRITICAL_SECTION_LOCKING_BREAKING_THREAD_LOCKS |
| 14 /* #define WITH_SEMAPHORE_LOCKING */ |
| 15 |
| 16 #ifdef WITH_CRITICAL_SECTION_LOCKING_BREAKING_THREAD_LOCKS |
| 17 /* Implement locking as a pseudo-recursive critical section */ |
| 18 |
| 19 typedef CRITICAL_SECTION NTMUTEX; |
| 20 typedef LPCRITICAL_SECTION PNTMUTEX; |
| 21 |
| 22 BOOL |
| 23 InitializeNtMutex(PNTMUTEX mutex) |
| 24 { |
| 25 » InitializeCriticalSection(mutex); |
| 26 » /* Spin mutex would be: InitializeCriticalSectionAndSpinCount(mutex, Spi
nCount#); */ |
| 27 » return TRUE; /* failure is a segfault for this function */ |
| 28 } |
| 29 |
| 30 VOID |
| 31 DeleteNtMutex(PNTMUTEX mutex) |
| 32 { |
| 33 » /* ideally would set the pointer to zero here, might be a good reason to |
| 34 » encapsulate CRITICAL_SECTION */ |
| 35 » DeleteCriticalSection(mutex); |
| 36 } |
| 37 |
| 38 |
| 39 DWORD |
| 40 EnterNtMutex(PNTMUTEX mutex, BOOL wait) |
| 41 { |
| 42 » const DWORD ThisThread = GetCurrentThreadId(); |
| 43 |
| 44 » /* |
| 45 » We can only effectively disallow recursion when the |
| 46 » caller doesn't want to wait. There are two other options |
| 47 » in the presence of recursion: |
| 48 » (1) allow recursion no matter what, or |
| 49 » (2) force a deadlock (i.e. acquire an unused semaphore). |
| 50 » |
| 51 » Option 1 breaks code that does sanity checks assuming that |
| 52 » we can't lock it if we own it already without blocking. |
| 53 » Option 2 preserves semantics, but is not desirable. |
| 54 |
| 55 » The solution here disallows recursion when wait == 0, and |
| 56 » silently allows it otherwise. |
| 57 » */ |
| 58 |
| 59 » if ( !wait ) |
| 60 » { |
| 61 » » /* warning: using NT internals. this value is always the thread
id, |
| 62 » » but we are bypassing the opaqueness of CRITICAL_SECTION */ |
| 63 » » if ( ((DWORD)(mutex->OwningThread) == ThisThread) || |
| 64 » » (TryEnterCriticalSection(mutex) == FALSE) ) /* try to acqui
re if not owner */ |
| 65 » » » return WAIT_TIMEOUT; /* recursion or unavailable */ |
| 66 » } |
| 67 » else /* wait always passed as INFINITE anyway, so ignore it */ |
| 68 » » EnterCriticalSection(mutex); |
| 69 |
| 70 » return WAIT_OBJECT_0; |
| 71 } |
| 72 |
| 73 BOOL |
| 74 LeaveNtMutex(PNTMUTEX mutex) |
| 75 { |
| 76 » /* It might be important here to fail if a thread not owning this object |
| 77 » tries to release it. It will work with events AFAIK, but not critical |
| 78 » sections. |
| 79 » */ |
| 80 » LeaveCriticalSection(mutex); |
| 81 » return TRUE; |
| 82 } |
| 83 |
| 84 #elif defined(WITH_SEMAPHORE_LOCKING) |
| 85 /* Implement locking as a semaphore */ |
| 86 |
| 87 typedef HANDLE NTMUTEX; |
| 88 typedef LPHANDLE PNTMUTEX; |
| 89 |
| 90 BOOL |
| 91 InitializeNtMutex(PNTMUTEX mutex) |
| 92 { |
| 93 » *mutex = CreateSemaphore(NULL, 1, LONG_MAX, NULL); |
| 94 » return *mutex != NULL; |
| 95 } |
| 96 |
| 97 VOID |
| 98 DeleteNtMutex(PNTMUTEX mutex) |
| 99 { |
| 100 » CloseHandle(*mutex); |
| 101 } |
| 102 |
| 103 |
| 104 DWORD |
| 105 EnterNtMutex(PNTMUTEX mutex, DWORD wait) /* second parameter type changed to DWO
RD */ |
| 106 { |
| 107 » return WaitForSingleObject(*mutex, wait); |
| 108 } |
| 109 |
| 110 BOOL |
| 111 LeaveNtMutex(PNTMUTEX mutex) |
| 112 { |
| 113 » return ReleaseSemaphore(*mutex, 1, NULL); |
| 114 } |
| 115 |
| 116 #else /* Use an event-based non-recursive mutex */ |
| 117 |
| 118 typedef struct NTMUTEX { |
| 13 LONG owned ; | 119 LONG owned ; |
| 14 DWORD thread_id ; | 120 DWORD thread_id ; |
| 15 HANDLE hevent ; | 121 HANDLE hevent ; |
| 16 } NRMUTEX, *PNRMUTEX ; | 122 } NTMUTEX, *PNTMUTEX ; |
| 17 | 123 |
| 18 | 124 |
| 19 BOOL | 125 BOOL |
| 20 InitializeNonRecursiveMutex(PNRMUTEX mutex) | 126 InitializeNtMutex(PNTMUTEX mutex) |
| 21 { | 127 { |
| 22 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ | 128 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ |
| 23 mutex->thread_id = 0 ; | 129 mutex->thread_id = 0 ; |
| 24 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; | 130 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; |
| 25 return mutex->hevent != NULL ; /* TRUE if the mutex is created */ | 131 return mutex->hevent != NULL ; /* TRUE if the mutex is created */ |
| 26 } | 132 } |
| 27 | 133 |
| 28 VOID | 134 VOID |
| 29 DeleteNonRecursiveMutex(PNRMUTEX mutex) | 135 DeleteNtMutex(PNTMUTEX mutex) |
| 30 { | 136 { |
| 31 /* No in-use check */ | 137 /* No in-use check */ |
| 32 CloseHandle(mutex->hevent) ; | 138 CloseHandle(mutex->hevent) ; |
| 33 mutex->hevent = NULL ; /* Just in case */ | 139 mutex->hevent = NULL ; /* Just in case */ |
| 34 } | 140 } |
| 35 | 141 |
| 36 DWORD | 142 DWORD |
| 37 EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) | 143 EnterNtMutex(PNTMUTEX mutex, BOOL wait) |
| 38 { | 144 { |
| 39 /* Assume that the thread waits successfully */ | 145 /* Assume that the thread waits successfully */ |
| 40 DWORD ret ; | 146 DWORD ret ; |
| 41 | 147 |
| 42 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread current
ly owns the mutex */ | 148 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread current
ly owns the mutex */ |
| 43 if (!wait) | 149 if (!wait) |
| 44 { | 150 { |
| 45 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) | 151 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) |
| 46 return WAIT_TIMEOUT ; | 152 return WAIT_TIMEOUT ; |
| 47 ret = WAIT_OBJECT_0 ; | 153 ret = WAIT_OBJECT_0 ; |
| 48 } | 154 } |
| 49 else | 155 else |
| 50 ret = InterlockedIncrement(&mutex->owned) ? | 156 ret = InterlockedIncrement(&mutex->owned) ? |
| 51 /* Some thread owns the mutex, let's wait... */ | 157 /* Some thread owns the mutex, let's wait... */ |
| 52 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJE
CT_0 ; | 158 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJE
CT_0 ; |
| 53 | 159 |
| 54 mutex->thread_id = GetCurrentThreadId() ; /* We own it */ | 160 mutex->thread_id = GetCurrentThreadId() ; /* We own it */ |
| 55 return ret ; | 161 return ret ; |
| 56 } | 162 } |
| 57 | 163 |
| 58 BOOL | 164 BOOL |
| 59 LeaveNonRecursiveMutex(PNRMUTEX mutex) | 165 LeaveNtMutex(PNTMUTEX mutex) |
| 60 { | 166 { |
| 61 /* We don't own the mutex */ | 167 /* We don't own the mutex */ |
| 62 mutex->thread_id = 0 ; | 168 mutex->thread_id = 0 ; |
| 63 return | 169 return |
| 64 InterlockedDecrement(&mutex->owned) < 0 || | 170 InterlockedDecrement(&mutex->owned) < 0 || |
| 65 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one
on them up */ | 171 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one
on them up */ |
| 66 } | 172 } |
| 67 | 173 |
| 68 PNRMUTEX | 174 #endif /* WITH_CRITICAL_SECTION_GIL */ |
| 69 AllocNonRecursiveMutex(void) | 175 |
| 176 |
| 177 PNTMUTEX |
| 178 AllocNtMutex(void) |
| 70 { | 179 { |
| 71 » PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ; | 180 » PNTMUTEX mutex = (PNTMUTEX)malloc(sizeof(NTMUTEX)) ; |
| 72 » if (mutex && !InitializeNonRecursiveMutex(mutex)) | 181 » if (mutex && !InitializeNtMutex(mutex)) |
| 73 { | 182 { |
| 74 free(mutex) ; | 183 free(mutex) ; |
| 75 mutex = NULL ; | 184 mutex = NULL ; |
| 76 } | 185 } |
| 77 return mutex ; | 186 return mutex ; |
| 78 } | 187 } |
| 79 | 188 |
| 80 void | 189 void |
| 81 FreeNonRecursiveMutex(PNRMUTEX mutex) | 190 FreeNtMutex(PNTMUTEX mutex) |
| 82 { | 191 { |
| 83 if (mutex) | 192 if (mutex) |
| 84 { | 193 { |
| 85 » » DeleteNonRecursiveMutex(mutex) ; | 194 » » DeleteNtMutex(mutex) ; |
| 86 free(mutex) ; | 195 free(mutex) ; |
| 87 } | 196 } |
| 88 } | 197 } |
| 89 | 198 |
| 90 long PyThread_get_thread_ident(void); | 199 long PyThread_get_thread_ident(void); |
| 91 | 200 |
| 92 /* | 201 /* |
| 93 * Initialization of the C package, should not be needed. | 202 * Initialization of the C package, should not be needed. |
| 94 */ | 203 */ |
| 95 static void | 204 static void |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 #ifndef NO_EXIT_PROG | 315 #ifndef NO_EXIT_PROG |
| 207 void | 316 void |
| 208 PyThread_exit_prog(int status) | 317 PyThread_exit_prog(int status) |
| 209 { | 318 { |
| 210 dprintf(("PyThread_exit_prog(%d) called\n", status)); | 319 dprintf(("PyThread_exit_prog(%d) called\n", status)); |
| 211 if (!initialized) | 320 if (!initialized) |
| 212 exit(status); | 321 exit(status); |
| 213 } | 322 } |
| 214 #endif /* NO_EXIT_PROG */ | 323 #endif /* NO_EXIT_PROG */ |
| 215 | 324 |
| 216 /* | |
| 217 * Lock support. It has too be implemented as semaphores. | |
| 218 * I [Dag] tried to implement it with mutex but I could find a way to | |
| 219 * tell whether a thread already own the lock or not. | |
| 220 */ | |
| 221 PyThread_type_lock | 325 PyThread_type_lock |
| 222 PyThread_allocate_lock(void) | 326 PyThread_allocate_lock(void) |
| 223 { | 327 { |
| 224 » PNRMUTEX aLock; | 328 » PNTMUTEX aLock; |
| 225 | 329 |
| 226 dprintf(("PyThread_allocate_lock called\n")); | 330 dprintf(("PyThread_allocate_lock called\n")); |
| 227 if (!initialized) | 331 if (!initialized) |
| 228 PyThread_init_thread(); | 332 PyThread_init_thread(); |
| 229 | 333 |
| 230 » aLock = AllocNonRecursiveMutex() ; | 334 » aLock = AllocNtMutex() ; |
| 231 | 335 |
| 232 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_id
ent(), aLock)); | 336 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_id
ent(), aLock)); |
| 233 | 337 |
| 234 return (PyThread_type_lock) aLock; | 338 return (PyThread_type_lock) aLock; |
| 235 } | 339 } |
| 236 | 340 |
| 237 void | 341 void |
| 238 PyThread_free_lock(PyThread_type_lock aLock) | 342 PyThread_free_lock(PyThread_type_lock aLock) |
| 239 { | 343 { |
| 240 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ide
nt(),aLock)); | 344 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ide
nt(),aLock)); |
| 241 | 345 |
| 242 » FreeNonRecursiveMutex(aLock) ; | 346 » FreeNtMutex(aLock) ; |
| 243 } | 347 } |
| 244 | 348 |
| 245 /* | 349 /* |
| 246 * Return 1 on success if the lock was acquired | 350 * Return 1 on success if the lock was acquired |
| 247 * | 351 * |
| 248 * and 0 if the lock was not acquired. This means a 0 is returned | 352 * and 0 if the lock was not acquired. This means a 0 is returned |
| 249 * if the lock has already been acquired by this thread! | 353 * if the lock has already been acquired by this thread! |
| 250 */ | 354 */ |
| 251 int | 355 int |
| 252 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) | 356 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) |
| 253 { | 357 { |
| 254 int success ; | 358 int success ; |
| 255 | 359 |
| 256 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thr
ead_ident(),aLock, waitflag)); | 360 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thr
ead_ident(),aLock, waitflag)); |
| 257 | 361 |
| 258 » success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ?
INFINITE : 0)) == WAIT_OBJECT_0 ; | 362 » success = aLock && EnterNtMutex((PNTMUTEX) aLock, (waitflag ? INFINITE :
0)) == WAIT_OBJECT_0 ; |
| 259 | 363 |
| 260 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thre
ad_ident(),aLock, waitflag, success)); | 364 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thre
ad_ident(),aLock, waitflag, success)); |
| 261 | 365 |
| 262 return success; | 366 return success; |
| 263 } | 367 } |
| 264 | 368 |
| 265 void | 369 void |
| 266 PyThread_release_lock(PyThread_type_lock aLock) | 370 PyThread_release_lock(PyThread_type_lock aLock) |
| 267 { | 371 { |
| 268 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_
ident(),aLock)); | 372 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_
ident(),aLock)); |
| 269 | 373 |
| 270 » if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) | 374 » if (!(aLock && LeaveNtMutex((PNTMUTEX) aLock))) |
| 271 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n"
, PyThread_get_thread_ident(), aLock, GetLastError())); | 375 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n"
, PyThread_get_thread_ident(), aLock, GetLastError())); |
| 272 } | 376 } |
| 273 | 377 |
| 274 /* minimum/maximum thread stack sizes supported */ | 378 /* minimum/maximum thread stack sizes supported */ |
| 275 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ | 379 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ |
| 276 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ | 380 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ |
| 277 | 381 |
| 278 /* set the thread stack size. | 382 /* set the thread stack size. |
| 279 * Return 0 if size is valid, -1 otherwise. | 383 * Return 0 if size is valid, -1 otherwise. |
| 280 */ | 384 */ |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 } | 464 } |
| 361 | 465 |
| 362 /* reinitialization of TLS is not necessary after fork when using | 466 /* reinitialization of TLS is not necessary after fork when using |
| 363 * the native TLS functions. And forking isn't supported on Windows either. | 467 * the native TLS functions. And forking isn't supported on Windows either. |
| 364 */ | 468 */ |
| 365 void | 469 void |
| 366 PyThread_ReInitTLS(void) | 470 PyThread_ReInitTLS(void) |
| 367 {} | 471 {} |
| 368 | 472 |
| 369 #endif | 473 #endif |
| OLD | NEW |