blob: 4e6198b3492894d2b482e037f3c2a82f1093a11c [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
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +000018typedef LONG WINAPI interlocked_cmp_xchg_t(LONG volatile *dest, LONG exc, LONG comperand) ;
Guido van Rossum706262b2000-05-04 18:47:15 +000019
20/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +000021static LONG WINAPI
22interlocked_cmp_xchg(LONG volatile *dest, LONG exc, LONG comperand)
Guido van Rossum706262b2000-05-04 18:47:15 +000023{
24 static LONG spinlock = 0 ;
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +000025 LONG result ;
Guido van Rossumede8c6e2000-05-11 12:53:51 +000026 DWORD dwSleep = 0;
Guido van Rossum706262b2000-05-04 18:47:15 +000027
28 /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */
Guido van Rossumede8c6e2000-05-11 12:53:51 +000029 while(InterlockedExchange(&spinlock, 1))
30 {
31 // Using Sleep(0) can cause a priority inversion.
32 // Sleep(0) only yields the processor if there's
33 // another thread of the same priority that's
34 // ready to run. If a high-priority thread is
35 // trying to acquire the lock, which is held by
36 // a low-priority thread, then the low-priority
37 // thread may never get scheduled and hence never
38 // free the lock. NT attempts to avoid priority
39 // inversions by temporarily boosting the priority
40 // of low-priority runnable threads, but the problem
41 // can still occur if there's a medium-priority
42 // thread that's always runnable. If Sleep(1) is used,
43 // then the thread unconditionally yields the CPU. We
44 // only do this for the second and subsequent even
45 // iterations, since a millisecond is a long time to wait
46 // if the thread can be scheduled in again sooner
47 // (~100,000 instructions).
48 // Avoid priority inversion: 0, 1, 0, 1,...
49 Sleep(dwSleep);
50 dwSleep = !dwSleep;
51 }
Guido van Rossum706262b2000-05-04 18:47:15 +000052 result = *dest ;
53 if (result == comperand)
54 *dest = exc ;
55 /* Release spinlock */
56 spinlock = 0 ;
57 return result ;
58} ;
59
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000060static interlocked_cmp_xchg_t *ixchg;
61
62BOOL
63InitializeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000064{
65 if (!ixchg)
66 {
67 /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */
68 HANDLE kernel = GetModuleHandle("kernel32.dll") ;
69 if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL)
70 ixchg = interlocked_cmp_xchg ;
71 }
72
73 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
74 mutex->thread_id = 0 ;
75 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
76 return mutex->hevent != NULL ; /* TRUE if the mutex is created */
77}
78
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +000079#ifndef MS_WIN64
Guido van Rossum582acec2000-06-28 22:07:35 +000080#ifdef InterlockedCompareExchange
81#undef InterlockedCompareExchange
82#endif
Guido van Rossum706262b2000-05-04 18:47:15 +000083#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +000084#endif
Guido van Rossum706262b2000-05-04 18:47:15 +000085
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000086VOID
87DeleteNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000088{
89 /* No in-use check */
90 CloseHandle(mutex->hevent) ;
91 mutex->hevent = NULL ; /* Just in case */
92}
93
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000094DWORD
95EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
Guido van Rossum706262b2000-05-04 18:47:15 +000096{
97 /* Assume that the thread waits successfully */
98 DWORD ret ;
99
100 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
101 if (!wait)
102 {
Kristján Valur Jónssonb4c285a2007-05-07 18:28:12 +0000103 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)
Guido van Rossum706262b2000-05-04 18:47:15 +0000104 return WAIT_TIMEOUT ;
105 ret = WAIT_OBJECT_0 ;
106 }
107 else
108 ret = InterlockedIncrement(&mutex->owned) ?
109 /* Some thread owns the mutex, let's wait... */
110 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
111
112 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
113 return ret ;
114}
115
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000116BOOL
117LeaveNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +0000118{
119 /* We don't own the mutex */
120 mutex->thread_id = 0 ;
121 return
122 InterlockedDecrement(&mutex->owned) < 0 ||
123 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
124}
125
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000126PNRMUTEX
127AllocNonRecursiveMutex(void)
Guido van Rossum706262b2000-05-04 18:47:15 +0000128{
129 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
130 if (mutex && !InitializeNonRecursiveMutex(mutex))
131 {
132 free(mutex) ;
133 mutex = NULL ;
134 }
135 return mutex ;
136}
137
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000138void
139FreeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +0000140{
141 if (mutex)
142 {
143 DeleteNonRecursiveMutex(mutex) ;
144 free(mutex) ;
145 }
146}
147
Guido van Rossum65d5b571998-12-21 19:32:43 +0000148long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000149
150/*
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000151 * Initialization of the C package, should not be needed.
152 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000153static void
154PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000155{
156}
157
158/*
159 * Thread support.
160 */
Guido van Rossum3c288632001-10-16 21:13:49 +0000161
162typedef struct {
163 void (*func)(void*);
Tim Peters2e7e7df2003-07-04 04:40:45 +0000164 void *arg;
Guido van Rossum3c288632001-10-16 21:13:49 +0000165 long id;
166 HANDLE done;
167} callobj;
168
169static int
170bootstrap(void *call)
171{
172 callobj *obj = (callobj*)call;
173 /* copy callobj since other thread might free it before we're done */
174 void (*func)(void*) = obj->func;
175 void *arg = obj->arg;
176
177 obj->id = PyThread_get_thread_ident();
178 ReleaseSemaphore(obj->done, 1, NULL);
179 func(arg);
180 return 0;
181}
182
Tim Peters2e7e7df2003-07-04 04:40:45 +0000183long
184PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000185{
Martin v. Löwisa43190b2006-05-22 09:15:18 +0000186 Py_uintptr_t rv;
Tim Peters2e7e7df2003-07-04 04:40:45 +0000187 callobj obj;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000188
Tim Peters2e7e7df2003-07-04 04:40:45 +0000189 dprintf(("%ld: PyThread_start_new_thread called\n",
190 PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000191 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000192 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000193
Tim Peters2e7e7df2003-07-04 04:40:45 +0000194 obj.id = -1; /* guilty until proved innocent */
195 obj.func = func;
196 obj.arg = arg;
197 obj.done = CreateSemaphore(NULL, 0, 1, NULL);
198 if (obj.done == NULL)
199 return -1;
Guido van Rossum3c288632001-10-16 21:13:49 +0000200
Andrew MacIntyre92913322006-06-13 15:04:24 +0000201 rv = _beginthread(bootstrap, _pythread_stacksize, &obj);
Martin v. Löwisa43190b2006-05-22 09:15:18 +0000202 if (rv == (Py_uintptr_t)-1) {
Tim Peters2e7e7df2003-07-04 04:40:45 +0000203 /* I've seen errno == EAGAIN here, which means "there are
204 * too many threads".
205 */
206 dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n",
Kristján Valur Jónsson5e4e31f2007-04-21 12:46:49 +0000207 PyThread_get_thread_ident(), (void*)rv, errno));
Tim Peters2e7e7df2003-07-04 04:40:45 +0000208 obj.id = -1;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000209 }
Tim Peters2e7e7df2003-07-04 04:40:45 +0000210 else {
211 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
Kristján Valur Jónsson5e4e31f2007-04-21 12:46:49 +0000212 PyThread_get_thread_ident(), (void*)rv));
Tim Peters2e7e7df2003-07-04 04:40:45 +0000213 /* wait for thread to initialize, so we can get its id */
214 WaitForSingleObject(obj.done, INFINITE);
215 assert(obj.id != -1);
216 }
217 CloseHandle((HANDLE)obj.done);
218 return obj.id;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000219}
220
221/*
222 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
223 * thread in the system
224 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000225long
226PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000227{
228 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000229 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000230
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000231 return GetCurrentThreadId();
232}
233
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000234static void
235do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000236{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000237 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000238 if (!initialized)
239 if (no_cleanup)
240 _exit(0);
241 else
242 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000243 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000244}
245
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000246void
247PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000248{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000249 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000250}
251
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000252void
253PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000254{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000255 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000256}
257
258#ifndef NO_EXIT_PROG
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000259static void
260do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000261{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000262 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000263 if (!initialized)
264 if (no_cleanup)
265 _exit(status);
266 else
267 exit(status);
268}
269
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000270void
271PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000272{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000273 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000274}
275
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000276void
277PyThread__exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000278{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000279 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000280}
281#endif /* NO_EXIT_PROG */
282
283/*
284 * Lock support. It has too be implemented as semaphores.
285 * I [Dag] tried to implement it with mutex but I could find a way to
286 * tell whether a thread already own the lock or not.
287 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000288PyThread_type_lock
289PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000290{
Guido van Rossum706262b2000-05-04 18:47:15 +0000291 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000292
Guido van Rossum65d5b571998-12-21 19:32:43 +0000293 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000294 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000295 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000296
Guido van Rossum706262b2000-05-04 18:47:15 +0000297 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000298
Fred Drakea44d3532000-06-30 15:01:00 +0000299 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000300
Guido van Rossum65d5b571998-12-21 19:32:43 +0000301 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000302}
303
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000304void
305PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000306{
Fred Drakea44d3532000-06-30 15:01:00 +0000307 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000308
Guido van Rossum706262b2000-05-04 18:47:15 +0000309 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000310}
311
312/*
313 * Return 1 on success if the lock was acquired
314 *
315 * and 0 if the lock was not acquired. This means a 0 is returned
316 * if the lock has already been acquired by this thread!
317 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000318int
319PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000320{
Guido van Rossum706262b2000-05-04 18:47:15 +0000321 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000322
Fred Drakea44d3532000-06-30 15:01:00 +0000323 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000324
Georg Brandlaf410b52005-07-08 22:26:13 +0000325 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000326
Fred Drakea44d3532000-06-30 15:01:00 +0000327 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000328
329 return success;
330}
331
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000332void
333PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000334{
Fred Drakea44d3532000-06-30 15:01:00 +0000335 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000336
Guido van Rossum706262b2000-05-04 18:47:15 +0000337 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Kristján Valur Jónsson5e4e31f2007-04-21 12:46:49 +0000338 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 +0000339}
Andrew MacIntyre92913322006-06-13 15:04:24 +0000340
341/* minimum/maximum thread stack sizes supported */
342#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
343#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
344
345/* set the thread stack size.
346 * Return 0 if size is valid, -1 otherwise.
347 */
348static int
349_pythread_nt_set_stacksize(size_t size)
350{
351 /* set to default */
352 if (size == 0) {
353 _pythread_stacksize = 0;
354 return 0;
355 }
356
357 /* valid range? */
358 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
359 _pythread_stacksize = size;
360 return 0;
361 }
362
363 return -1;
364}
365
366#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)