blob: 938bf1e3fed0c6c1a66022e36c9fa80615ce22f9 [file] [log] [blame]
Guido van Rossumc3f82b61995-01-17 16:29:31 +00001
2/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
Guido van Rossum706262b2000-05-04 18:47:15 +00003/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
Tim Peterse64ef932002-02-28 21:34:34 +00004/* Eliminated some memory leaks, gsw@agere.com */
Guido van Rossumc3f82b61995-01-17 16:29:31 +00005
Guido van Rossum49b12261997-08-14 20:12:58 +00006#include <windows.h>
7#include <limits.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +00008#ifdef HAVE_PROCESS_H
Guido van Rossum49b12261997-08-14 20:12:58 +00009#include <process.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000010#endif
Guido van Rossumc3f82b61995-01-17 16:29:31 +000011
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +000012/* options */
13#ifndef _PY_USE_CV_LOCKS
14#define _PY_USE_CV_LOCKS 1 /* use locks based on cond vars */
15#endif
16
17/* Now, define a non-recursive mutex using either condition variables
18 * and critical sections (fast) or using operating system mutexes
19 * (slow)
20 */
21
22#if _PY_USE_CV_LOCKS
23
24#include "condvar.h"
25
26typedef struct _NRMUTEX
27{
28 PyMUTEX_T cs;
29 PyCOND_T cv;
30 int locked;
31} NRMUTEX;
32typedef NRMUTEX *PNRMUTEX;
33
34PNRMUTEX
35AllocNonRecursiveMutex()
36{
37 PNRMUTEX m = (PNRMUTEX)malloc(sizeof(NRMUTEX));
38 if (!m)
39 return NULL;
40 if (PyCOND_INIT(&m->cv))
41 goto fail;
42 if (PyMUTEX_INIT(&m->cs)) {
43 PyCOND_FINI(&m->cv);
44 goto fail;
45 }
46 m->locked = 0;
47 return m;
48fail:
49 free(m);
50 return NULL;
51}
52
53VOID
54FreeNonRecursiveMutex(PNRMUTEX mutex)
55{
56 if (mutex) {
57 PyCOND_FINI(&mutex->cv);
58 PyMUTEX_FINI(&mutex->cs);
59 free(mutex);
60 }
61}
62
63DWORD
64EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds)
65{
66 DWORD result = WAIT_OBJECT_0;
67 if (PyMUTEX_LOCK(&mutex->cs))
68 return WAIT_FAILED;
69 if (milliseconds == INFINITE) {
70 while (mutex->locked) {
71 if (PyCOND_WAIT(&mutex->cv, &mutex->cs)) {
72 result = WAIT_FAILED;
73 break;
74 }
75 }
76 } else if (milliseconds != 0) {
77 /* wait at least until the target */
78 DWORD now, target = GetTickCount() + milliseconds;
79 while (mutex->locked) {
80 if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, milliseconds*1000) < 0) {
81 result = WAIT_FAILED;
82 break;
83 }
84 now = GetTickCount();
85 if (target <= now)
86 break;
87 milliseconds = target-now;
88 }
89 }
90 if (!mutex->locked) {
91 mutex->locked = 1;
92 result = WAIT_OBJECT_0;
93 } else if (result == WAIT_OBJECT_0)
94 result = WAIT_TIMEOUT;
95 /* else, it is WAIT_FAILED */
96 PyMUTEX_UNLOCK(&mutex->cs); /* must ignore result here */
97 return result;
98}
99
100BOOL
101LeaveNonRecursiveMutex(PNRMUTEX mutex)
102{
103 BOOL result;
104 if (PyMUTEX_LOCK(&mutex->cs))
105 return FALSE;
106 mutex->locked = 0;
107 result = PyCOND_SIGNAL(&mutex->cv);
108 result &= PyMUTEX_UNLOCK(&mutex->cs);
109 return result;
110}
111
112#else /* if ! _PY_USE_CV_LOCKS */
113
114/* NR-locks based on a kernel mutex */
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200115#define PNRMUTEX HANDLE
Guido van Rossum706262b2000-05-04 18:47:15 +0000116
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200117PNRMUTEX
118AllocNonRecursiveMutex()
Guido van Rossum706262b2000-05-04 18:47:15 +0000119{
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200120 return CreateSemaphore(NULL, 1, 1, NULL);
Guido van Rossum706262b2000-05-04 18:47:15 +0000121}
122
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000123VOID
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200124FreeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +0000125{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 /* No in-use check */
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200127 CloseHandle(mutex);
Guido van Rossum706262b2000-05-04 18:47:15 +0000128}
129
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000130DWORD
Antoine Pitrou7c3e5772010-04-14 15:44:10 +0000131EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds)
Guido van Rossum706262b2000-05-04 18:47:15 +0000132{
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200133 return WaitForSingleObject(mutex, milliseconds);
Guido van Rossum706262b2000-05-04 18:47:15 +0000134}
135
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000136BOOL
137LeaveNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +0000138{
Antoine Pitrou7899acf2011-03-31 01:00:32 +0200139 return ReleaseSemaphore(mutex, 1, NULL);
Guido van Rossum706262b2000-05-04 18:47:15 +0000140}
Kristján Valur Jónssone75ff352012-06-18 20:30:44 +0000141#endif /* _PY_USE_CV_LOCKS */
Guido van Rossum706262b2000-05-04 18:47:15 +0000142
Guido van Rossum65d5b571998-12-21 19:32:43 +0000143long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000144
145/*
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000146 * Initialization of the C package, should not be needed.
147 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000148static void
149PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000150{
151}
152
153/*
154 * Thread support.
155 */
Guido van Rossum3c288632001-10-16 21:13:49 +0000156
157typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 void (*func)(void*);
159 void *arg;
Guido van Rossum3c288632001-10-16 21:13:49 +0000160} callobj;
161
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000162/* thunker to call adapt between the function type used by the system's
163thread start function and the internally used one. */
164#if defined(MS_WINCE)
165static DWORD WINAPI
166#else
167static unsigned __stdcall
168#endif
Guido van Rossum3c288632001-10-16 21:13:49 +0000169bootstrap(void *call)
170{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 callobj *obj = (callobj*)call;
172 void (*func)(void*) = obj->func;
173 void *arg = obj->arg;
174 HeapFree(GetProcessHeap(), 0, obj);
175 func(arg);
176 return 0;
Guido van Rossum3c288632001-10-16 21:13:49 +0000177}
178
Tim Peters2e7e7df2003-07-04 04:40:45 +0000179long
180PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000181{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 HANDLE hThread;
183 unsigned threadID;
184 callobj *obj;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000185
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 dprintf(("%ld: PyThread_start_new_thread called\n",
187 PyThread_get_thread_ident()));
188 if (!initialized)
189 PyThread_init_thread();
190
191 obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
192 if (!obj)
193 return -1;
194 obj->func = func;
195 obj->arg = arg;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000196#if defined(MS_WINCE)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000197 hThread = CreateThread(NULL,
198 Py_SAFE_DOWNCAST(_pythread_stacksize, Py_ssize_t, SIZE_T),
199 bootstrap, obj, 0, &threadID);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000200#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 hThread = (HANDLE)_beginthreadex(0,
202 Py_SAFE_DOWNCAST(_pythread_stacksize,
203 Py_ssize_t, unsigned int),
204 bootstrap, obj,
205 0, &threadID);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000206#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 if (hThread == 0) {
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000208#if defined(MS_WINCE)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 /* Save error in variable, to prevent PyThread_get_thread_ident
210 from clobbering it. */
211 unsigned e = GetLastError();
212 dprintf(("%ld: PyThread_start_new_thread failed, win32 error code %u\n",
213 PyThread_get_thread_ident(), e));
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000214#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 /* I've seen errno == EAGAIN here, which means "there are
216 * too many threads".
217 */
218 int e = errno;
219 dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",
220 PyThread_get_thread_ident(), e));
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000221#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 threadID = (unsigned)-1;
223 HeapFree(GetProcessHeap(), 0, obj);
224 }
225 else {
226 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
227 PyThread_get_thread_ident(), (void*)hThread));
228 CloseHandle(hThread);
229 }
230 return (long) threadID;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000231}
232
233/*
234 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
235 * thread in the system
236 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000237long
238PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000239{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240 if (!initialized)
241 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 return GetCurrentThreadId();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000244}
245
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000246void
247PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000248{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
250 if (!initialized)
251 exit(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000252#if defined(MS_WINCE)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 ExitThread(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000254#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 _endthreadex(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000256#endif
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000257}
258
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000259/*
260 * Lock support. It has too be implemented as semaphores.
261 * I [Dag] tried to implement it with mutex but I could find a way to
262 * tell whether a thread already own the lock or not.
263 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000264PyThread_type_lock
265PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000266{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000268
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 dprintf(("PyThread_allocate_lock called\n"));
270 if (!initialized)
271 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000272
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000274
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000276
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000278}
279
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000280void
281PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000282{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000284
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000286}
287
288/*
289 * Return 1 on success if the lock was acquired
290 *
291 * and 0 if the lock was not acquired. This means a 0 is returned
292 * if the lock has already been acquired by this thread!
293 */
Antoine Pitrou810023d2010-12-15 22:59:16 +0000294PyLockStatus
295PyThread_acquire_lock_timed(PyThread_type_lock aLock,
296 PY_TIMEOUT_T microseconds, int intr_flag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000297{
Antoine Pitrou810023d2010-12-15 22:59:16 +0000298 /* Fow now, intr_flag does nothing on Windows, and lock acquires are
299 * uninterruptible. */
300 PyLockStatus success;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 PY_TIMEOUT_T milliseconds;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 if (microseconds >= 0) {
304 milliseconds = microseconds / 1000;
305 if (microseconds % 1000 > 0)
306 ++milliseconds;
307 if ((DWORD) milliseconds != milliseconds)
308 Py_FatalError("Timeout too large for a DWORD, "
309 "please check PY_TIMEOUT_MAX");
310 }
311 else
312 milliseconds = INFINITE;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000313
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 dprintf(("%ld: PyThread_acquire_lock_timed(%p, %lld) called\n",
315 PyThread_get_thread_ident(), aLock, microseconds));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000316
Antoine Pitrou810023d2010-12-15 22:59:16 +0000317 if (aLock && EnterNonRecursiveMutex((PNRMUTEX)aLock,
318 (DWORD)milliseconds) == WAIT_OBJECT_0) {
319 success = PY_LOCK_ACQUIRED;
320 }
321 else {
322 success = PY_LOCK_FAILURE;
323 }
Antoine Pitrou7c3e5772010-04-14 15:44:10 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 dprintf(("%ld: PyThread_acquire_lock(%p, %lld) -> %d\n",
326 PyThread_get_thread_ident(), aLock, microseconds, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000327
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 return success;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000329}
Antoine Pitrou7c3e5772010-04-14 15:44:10 +0000330int
331PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
332{
Antoine Pitrou810023d2010-12-15 22:59:16 +0000333 return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0, 0);
Antoine Pitrou7c3e5772010-04-14 15:44:10 +0000334}
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000335
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000336void
337PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000338{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000340
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
342 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock, GetLastError()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000343}
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000344
345/* minimum/maximum thread stack sizes supported */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000346#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
347#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000348
349/* set the thread stack size.
350 * Return 0 if size is valid, -1 otherwise.
351 */
352static int
353_pythread_nt_set_stacksize(size_t size)
354{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 /* set to default */
356 if (size == 0) {
357 _pythread_stacksize = 0;
358 return 0;
359 }
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000360
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 /* valid range? */
362 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
363 _pythread_stacksize = size;
364 return 0;
365 }
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 return -1;
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000368}
369
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000371
372
373/* use native Windows TLS functions */
374#define Py_HAVE_NATIVE_TLS
375
376#ifdef Py_HAVE_NATIVE_TLS
377int
378PyThread_create_key(void)
379{
Kristján Valur Jónsson2fea9b92010-09-20 02:11:49 +0000380 DWORD result= TlsAlloc();
381 if (result == TLS_OUT_OF_INDEXES)
382 return -1;
383 return (int)result;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000384}
385
386void
387PyThread_delete_key(int key)
388{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 TlsFree(key);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000390}
391
392/* We must be careful to emulate the strange semantics implemented in thread.c,
393 * where the value is only set if it hasn't been set before.
394 */
395int
396PyThread_set_key_value(int key, void *value)
397{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000398 BOOL ok;
399 void *oldvalue;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 assert(value != NULL);
402 oldvalue = TlsGetValue(key);
403 if (oldvalue != NULL)
404 /* ignore value if already set */
405 return 0;
406 ok = TlsSetValue(key, value);
407 if (!ok)
408 return -1;
409 return 0;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000410}
411
412void *
413PyThread_get_key_value(int key)
414{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000415 /* because TLS is used in the Py_END_ALLOW_THREAD macro,
416 * it is necessary to preserve the windows error state, because
417 * it is assumed to be preserved across the call to the macro.
418 * Ideally, the macro should be fixed, but it is simpler to
419 * do it here.
420 */
421 DWORD error = GetLastError();
422 void *result = TlsGetValue(key);
423 SetLastError(error);
424 return result;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000425}
426
427void
428PyThread_delete_key_value(int key)
429{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 /* NULL is used as "key missing", and it is also the default
431 * given by TlsGetValue() if nothing has been set yet.
432 */
433 TlsSetValue(key, NULL);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000434}
435
436/* reinitialization of TLS is not necessary after fork when using
437 * the native TLS functions. And forking isn't supported on Windows either.
438 */
439void
440PyThread_ReInitTLS(void)
441{}
442
443#endif