blob: e3a3387f8d10f72f30573b64b3fdb598064676ae [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
Guido van Rossum706262b2000-05-04 18:47:15 +000012typedef struct NRMUTEX {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000013 LONG owned ;
14 DWORD thread_id ;
15 HANDLE hevent ;
Guido van Rossum706262b2000-05-04 18:47:15 +000016} NRMUTEX, *PNRMUTEX ;
17
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000018
19BOOL
20InitializeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000021{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000022 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 */
Guido van Rossum706262b2000-05-04 18:47:15 +000026}
27
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000028VOID
29DeleteNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000030{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000031 /* No in-use check */
32 CloseHandle(mutex->hevent) ;
33 mutex->hevent = NULL ; /* Just in case */
Guido van Rossum706262b2000-05-04 18:47:15 +000034}
35
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000036DWORD
37EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
Guido van Rossum706262b2000-05-04 18:47:15 +000038{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000039 /* Assume that the thread waits successfully */
40 DWORD ret ;
Guido van Rossum706262b2000-05-04 18:47:15 +000041
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000042 /* 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 ;
Guido van Rossum706262b2000-05-04 18:47:15 +000053
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000054 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
55 return ret ;
Guido van Rossum706262b2000-05-04 18:47:15 +000056}
57
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000058BOOL
59LeaveNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000060{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000061 /* 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 */
Guido van Rossum706262b2000-05-04 18:47:15 +000066}
67
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000068PNRMUTEX
69AllocNonRecursiveMutex(void)
Guido van Rossum706262b2000-05-04 18:47:15 +000070{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000071 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
72 if (mutex && !InitializeNonRecursiveMutex(mutex))
73 {
74 free(mutex) ;
75 mutex = NULL ;
76 }
77 return mutex ;
Guido van Rossum706262b2000-05-04 18:47:15 +000078}
79
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000080void
81FreeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000082{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000083 if (mutex)
84 {
85 DeleteNonRecursiveMutex(mutex) ;
86 free(mutex) ;
87 }
Guido van Rossum706262b2000-05-04 18:47:15 +000088}
89
Guido van Rossum65d5b571998-12-21 19:32:43 +000090long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +000091
92/*
Guido van Rossumc3f82b61995-01-17 16:29:31 +000093 * Initialization of the C package, should not be needed.
94 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000095static void
96PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +000097{
98}
99
100/*
101 * Thread support.
102 */
Guido van Rossum3c288632001-10-16 21:13:49 +0000103
104typedef struct {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000105 void (*func)(void*);
106 void *arg;
Guido van Rossum3c288632001-10-16 21:13:49 +0000107} callobj;
108
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000109/* 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
Guido van Rossum3c288632001-10-16 21:13:49 +0000116bootstrap(void *call)
117{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000118 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;
Guido van Rossum3c288632001-10-16 21:13:49 +0000124}
125
Tim Peters2e7e7df2003-07-04 04:40:45 +0000126long
127PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000128{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000129 HANDLE hThread;
130 unsigned threadID;
131 callobj *obj;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000132
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000133 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;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000143#if defined(MS_WINCE)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000144 hThread = CreateThread(NULL,
145 Py_SAFE_DOWNCAST(_pythread_stacksize, Py_ssize_t, SIZE_T),
146 bootstrap, obj, 0, &threadID);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000147#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000148 hThread = (HANDLE)_beginthreadex(0,
149 Py_SAFE_DOWNCAST(_pythread_stacksize,
150 Py_ssize_t, unsigned int),
151 bootstrap, obj,
152 0, &threadID);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000153#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000154 if (hThread == 0) {
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000155#if defined(MS_WINCE)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000156 /* 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));
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000161#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000162 /* 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));
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000168#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000169 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;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000178}
179
180/*
181 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
182 * thread in the system
183 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000184long
185PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000186{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000187 if (!initialized)
188 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000189
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000190 return GetCurrentThreadId();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000191}
192
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000193void
194PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000195{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000196 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
197 if (!initialized)
198 exit(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000199#if defined(MS_WINCE)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000200 ExitThread(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000201#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000202 _endthreadex(0);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000203#endif
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000204}
205
206#ifndef NO_EXIT_PROG
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000207void
208PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000209{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000210 dprintf(("PyThread_exit_prog(%d) called\n", status));
211 if (!initialized)
212 exit(status);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000213}
214#endif /* NO_EXIT_PROG */
215
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 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000221PyThread_type_lock
222PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000224 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000225
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000226 dprintf(("PyThread_allocate_lock called\n"));
227 if (!initialized)
228 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000229
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000230 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000231
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000232 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000233
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000234 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000235}
236
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000237void
238PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000239{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000240 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000241
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000242 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000243}
244
245/*
246 * Return 1 on success if the lock was acquired
247 *
248 * 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!
250 */
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000251int
252PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000253{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000254 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000255
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000256 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000257
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000258 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000259
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000260 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000261
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000262 return success;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000263}
264
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000265void
266PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000267{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000268 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000269
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000270 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
271 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 +0000272}
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000273
274/* minimum/maximum thread stack sizes supported */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000275#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
276#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000277
278/* set the thread stack size.
279 * Return 0 if size is valid, -1 otherwise.
280 */
281static int
282_pythread_nt_set_stacksize(size_t size)
283{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000284 /* set to default */
285 if (size == 0) {
286 _pythread_stacksize = 0;
287 return 0;
288 }
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000289
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000290 /* valid range? */
291 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
292 _pythread_stacksize = size;
293 return 0;
294 }
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000295
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000296 return -1;
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000297}
298
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000299#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000300
301
302/* use native Windows TLS functions */
303#define Py_HAVE_NATIVE_TLS
304
305#ifdef Py_HAVE_NATIVE_TLS
306int
307PyThread_create_key(void)
308{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000309 return (int) TlsAlloc();
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000310}
311
312void
313PyThread_delete_key(int key)
314{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000315 TlsFree(key);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000316}
317
318/* We must be careful to emulate the strange semantics implemented in thread.c,
319 * where the value is only set if it hasn't been set before.
320 */
321int
322PyThread_set_key_value(int key, void *value)
323{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000324 BOOL ok;
325 void *oldvalue;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000326
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000327 assert(value != NULL);
328 oldvalue = TlsGetValue(key);
329 if (oldvalue != NULL)
330 /* ignore value if already set */
331 return 0;
332 ok = TlsSetValue(key, value);
333 if (!ok)
334 return -1;
335 return 0;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000336}
337
338void *
339PyThread_get_key_value(int key)
340{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000341 /* because TLS is used in the Py_END_ALLOW_THREAD macro,
342 * it is necessary to preserve the windows error state, because
343 * it is assumed to be preserved across the call to the macro.
344 * Ideally, the macro should be fixed, but it is simpler to
345 * do it here.
346 */
347 DWORD error = GetLastError();
348 void *result = TlsGetValue(key);
349 SetLastError(error);
350 return result;
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000351}
352
353void
354PyThread_delete_key_value(int key)
355{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000356 /* NULL is used as "key missing", and it is also the default
357 * given by TlsGetValue() if nothing has been set yet.
358 */
359 TlsSetValue(key, NULL);
Martin v. Löwis7c2b66c2009-01-12 08:21:03 +0000360}
361
362/* reinitialization of TLS is not necessary after fork when using
363 * the native TLS functions. And forking isn't supported on Windows either.
364 */
365void
366PyThread_ReInitTLS(void)
367{}
368
369#endif