blob: 5ec15f6a931957348060ca0e6ef1183ecc4c3e6f [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>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +00008#ifdef HAVE_PROCESS_H
Guido van Rossum49b12261997-08-14 20:12:58 +00009#include <process.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000010#endif
Guido van Rossumc3f82b61995-01-17 16:29:31 +000011
Guido van Rossum706262b2000-05-04 18:47:15 +000012typedef struct NRMUTEX {
13 LONG owned ;
14 DWORD thread_id ;
15 HANDLE hevent ;
16} NRMUTEX, *PNRMUTEX ;
17
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000018
19BOOL
20InitializeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000021{
Guido van Rossum706262b2000-05-04 18:47:15 +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 */
26}
27
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000028VOID
29DeleteNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000030{
31 /* No in-use check */
32 CloseHandle(mutex->hevent) ;
33 mutex->hevent = NULL ; /* Just in case */
34}
35
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000036DWORD
37EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
Guido van Rossum706262b2000-05-04 18:47:15 +000038{
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 {
Kristján Valur Jónssonf0303942007-05-03 20:27:03 +000045 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)
Guido van Rossum706262b2000-05-04 18:47:15 +000046 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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000058BOOL
59LeaveNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000060{
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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000068PNRMUTEX
69AllocNonRecursiveMutex(void)
Guido van Rossum706262b2000-05-04 18:47:15 +000070{
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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000080void
81FreeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000082{
83 if (mutex)
84 {
85 DeleteNonRecursiveMutex(mutex) ;
86 free(mutex) ;
87 }
88}
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 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +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 {
105 void (*func)(void*);
Tim Peters2e7e7df2003-07-04 04:40:45 +0000106 void *arg;
Guido van Rossum3c288632001-10-16 21:13:49 +0000107} callobj;
108
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000109/* thunker to call a __cdecl function instead of a __stdcall */
110static unsigned __stdcall
Guido van Rossum3c288632001-10-16 21:13:49 +0000111bootstrap(void *call)
112{
113 callobj *obj = (callobj*)call;
Guido van Rossum3c288632001-10-16 21:13:49 +0000114 void (*func)(void*) = obj->func;
115 void *arg = obj->arg;
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000116 HeapFree(GetProcessHeap(), 0, obj);
Guido van Rossum3c288632001-10-16 21:13:49 +0000117 func(arg);
118 return 0;
119}
120
Tim Peters2e7e7df2003-07-04 04:40:45 +0000121long
122PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000123{
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000124 HANDLE hThread;
125 unsigned threadID;
126 callobj *obj;
127
Tim Peters2e7e7df2003-07-04 04:40:45 +0000128 dprintf(("%ld: PyThread_start_new_thread called\n",
129 PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000130 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000131 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000132
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000133 obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
134 if (!obj)
Tim Peters2e7e7df2003-07-04 04:40:45 +0000135 return -1;
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000136 obj->func = func;
137 obj->arg = arg;
138 hThread = (HANDLE)_beginthreadex(0,
Kristján Valur Jónssonf0303942007-05-03 20:27:03 +0000139 Py_SAFE_DOWNCAST(_pythread_stacksize,
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000140 Py_ssize_t, unsigned int),
141 bootstrap, obj,
142 0, &threadID);
143 if (hThread == 0) {
Tim Peters2e7e7df2003-07-04 04:40:45 +0000144 /* I've seen errno == EAGAIN here, which means "there are
145 * too many threads".
146 */
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000147 dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",
148 PyThread_get_thread_ident(), errno));
149 threadID = (unsigned)-1;
150 HeapFree(GetProcessHeap(), 0, obj);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000151 }
Tim Peters2e7e7df2003-07-04 04:40:45 +0000152 else {
153 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000154 PyThread_get_thread_ident(), (void*)hThread));
Tim Peters2e7e7df2003-07-04 04:40:45 +0000155 /* wait for thread to initialize, so we can get its id */
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000156 CloseHandle(hThread);
Tim Peters2e7e7df2003-07-04 04:40:45 +0000157 }
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000158 return (long) threadID;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000159}
160
161/*
162 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
163 * thread in the system
164 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000165long
166PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000167{
168 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000169 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000170
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000171 return GetCurrentThreadId();
172}
173
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000174void
175PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000176{
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000177 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
178 if (!initialized)
179 exit(0);
180 _endthreadex(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000181}
182
183#ifndef NO_EXIT_PROG
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000184void
185PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000186{
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000187 dprintf(("PyThread_exit_prog(%d) called\n", status));
188 if (!initialized)
189 exit(status);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000190}
191#endif /* NO_EXIT_PROG */
192
193/*
194 * Lock support. It has too be implemented as semaphores.
195 * I [Dag] tried to implement it with mutex but I could find a way to
196 * tell whether a thread already own the lock or not.
197 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000198PyThread_type_lock
199PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000200{
Guido van Rossum706262b2000-05-04 18:47:15 +0000201 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000202
Guido van Rossum65d5b571998-12-21 19:32:43 +0000203 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000204 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000205 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000206
Guido van Rossum706262b2000-05-04 18:47:15 +0000207 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000208
Fred Drakea44d3532000-06-30 15:01:00 +0000209 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000210
Guido van Rossum65d5b571998-12-21 19:32:43 +0000211 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000212}
213
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000214void
215PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000216{
Fred Drakea44d3532000-06-30 15:01:00 +0000217 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000218
Guido van Rossum706262b2000-05-04 18:47:15 +0000219 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000220}
221
222/*
223 * Return 1 on success if the lock was acquired
224 *
225 * and 0 if the lock was not acquired. This means a 0 is returned
226 * if the lock has already been acquired by this thread!
227 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000228int
229PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000230{
Guido van Rossum706262b2000-05-04 18:47:15 +0000231 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000232
Fred Drakea44d3532000-06-30 15:01:00 +0000233 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000234
Georg Brandlaf410b52005-07-08 22:26:13 +0000235 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000236
Fred Drakea44d3532000-06-30 15:01:00 +0000237 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000238
239 return success;
240}
241
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000242void
243PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000244{
Fred Drakea44d3532000-06-30 15:01:00 +0000245 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000246
Guido van Rossum706262b2000-05-04 18:47:15 +0000247 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Kristján Valur Jónsson17b8e972007-04-25 00:10:50 +0000248 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 +0000249}
Andrew MacIntyre92913322006-06-13 15:04:24 +0000250
251/* minimum/maximum thread stack sizes supported */
252#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
253#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
254
255/* set the thread stack size.
256 * Return 0 if size is valid, -1 otherwise.
257 */
258static int
259_pythread_nt_set_stacksize(size_t size)
260{
261 /* set to default */
262 if (size == 0) {
263 _pythread_stacksize = 0;
264 return 0;
265 }
266
267 /* valid range? */
268 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
269 _pythread_stacksize = size;
270 return 0;
271 }
272
273 return -1;
274}
275
276#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)
Kristján Valur Jónsson00f2df42009-01-09 20:03:27 +0000277
278
279/* use native Windows TLS functions */
280#define Py_HAVE_NATIVE_TLS
281
282#ifdef Py_HAVE_NATIVE_TLS
283int
284PyThread_create_key(void)
285{
286 return (int) TlsAlloc();
287}
288
289void
290PyThread_delete_key(int key)
291{
292 TlsFree(key);
293}
294
295/* We must be careful to emulate the strange semantics implemented in thread.c,
296 * where the value is only set if it hasn't been set before.
297 */
298int
299PyThread_set_key_value(int key, void *value)
300{
301 BOOL ok;
302 void *oldvalue;
303
304 assert(value != NULL);
305 oldvalue = TlsGetValue(key);
306 if (oldvalue != NULL)
307 /* ignore value if already set */
308 return 0;
309 ok = TlsSetValue(key, value);
310 if (!ok)
311 return -1;
312 return 0;
313}
314
315void *
316PyThread_get_key_value(int key)
317{
318 return TlsGetValue(key);
319}
320
321void
322PyThread_delete_key_value(int key)
323{
324 /* NULL is used as "key missing", and it is also the default
325 * given by TlsGetValue() if nothing has been set yet.
326 */
327 TlsSetValue(key, NULL);
328}
329
330/* reinitialization of TLS is not necessary after fork when using
331 * the native TLS functions. And forking isn't supported on Windows either.
332 */
333void
334PyThread_ReInitTLS(void)
335{}
336
337#endif