blob: 7512c730628ccaac5a969fe2a6f9b8b045df1a3b [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 {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000013 LONG owned ;
14 DWORD thread_id ;
15 HANDLE hevent ;
Guido van Rossum706262b2000-05-04 18:47:15 +000016} NRMUTEX, *PNRMUTEX ;
17
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000018
19BOOL
20InitializeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000021{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000028VOID
29DeleteNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000030{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000036DWORD
37EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
Guido van Rossum706262b2000-05-04 18:47:15 +000038{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000039 /* Assume that the thread waits successfully */
40 DWORD ret ;
Guido van Rossum706262b2000-05-04 18:47:15 +000041
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +000054 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
55 return ret ;
Guido van Rossum706262b2000-05-04 18:47:15 +000056}
57
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000058BOOL
59LeaveNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000060{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000068PNRMUTEX
69AllocNonRecursiveMutex(void)
Guido van Rossum706262b2000-05-04 18:47:15 +000070{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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
Andrew MacIntyre63f0db62006-06-04 12:59:59 +000080void
81FreeNonRecursiveMutex(PNRMUTEX mutex)
Guido van Rossum706262b2000-05-04 18:47:15 +000082{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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 */
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 {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000105 void (*func)(void*);
106 void *arg;
107 long id;
108 HANDLE done;
Guido van Rossum3c288632001-10-16 21:13:49 +0000109} callobj;
110
111static int
112bootstrap(void *call)
113{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000114 callobj *obj = (callobj*)call;
115 /* copy callobj since other thread might free it before we're done */
116 void (*func)(void*) = obj->func;
117 void *arg = obj->arg;
Guido van Rossum3c288632001-10-16 21:13:49 +0000118
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000119 obj->id = PyThread_get_thread_ident();
120 ReleaseSemaphore(obj->done, 1, NULL);
121 func(arg);
122 return 0;
Guido van Rossum3c288632001-10-16 21:13:49 +0000123}
124
Tim Peters2e7e7df2003-07-04 04:40:45 +0000125long
126PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000127{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000128 Py_uintptr_t rv;
129 callobj obj;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000130
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000131 dprintf(("%ld: PyThread_start_new_thread called\n",
132 PyThread_get_thread_ident()));
133 if (!initialized)
134 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000135
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000136 obj.id = -1; /* guilty until proved innocent */
137 obj.func = func;
138 obj.arg = arg;
139 obj.done = CreateSemaphore(NULL, 0, 1, NULL);
140 if (obj.done == NULL)
141 return -1;
Guido van Rossum3c288632001-10-16 21:13:49 +0000142
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000143 rv = _beginthread(bootstrap,
144 Py_SAFE_DOWNCAST(_pythread_stacksize,
145 Py_ssize_t, int),
146 &obj);
147 if (rv == (Py_uintptr_t)-1) {
148 /* I've seen errno == EAGAIN here, which means "there are
149 * too many threads".
150 */
151 dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n",
152 PyThread_get_thread_ident(), (void*)rv, errno));
153 obj.id = -1;
154 }
155 else {
156 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
157 PyThread_get_thread_ident(), (void*)rv));
158 /* wait for thread to initialize, so we can get its id */
159 WaitForSingleObject(obj.done, INFINITE);
160 assert(obj.id != -1);
161 }
162 CloseHandle((HANDLE)obj.done);
163 return obj.id;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000164}
165
166/*
167 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
168 * thread in the system
169 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000170long
171PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000172{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000173 if (!initialized)
174 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000175
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000176 return GetCurrentThreadId();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000177}
178
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000179static void
180do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000181{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000182 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
183 if (!initialized)
184 if (no_cleanup)
185 _exit(0);
186 else
187 exit(0);
188 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000189}
190
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000191void
192PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000193{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000194 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000195}
196
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000197void
198PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000199{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000200 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000201}
202
203#ifndef NO_EXIT_PROG
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000204static void
205do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000206{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000207 dprintf(("PyThread_exit_prog(%d) called\n", status));
208 if (!initialized)
209 if (no_cleanup)
210 _exit(status);
211 else
212 exit(status);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000213}
214
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000215void
216PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000217{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000218 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000219}
220
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000221void
222PyThread__exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000224 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000225}
226#endif /* NO_EXIT_PROG */
227
228/*
229 * Lock support. It has too be implemented as semaphores.
230 * I [Dag] tried to implement it with mutex but I could find a way to
231 * tell whether a thread already own the lock or not.
232 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000233PyThread_type_lock
234PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000235{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000236 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000237
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000238 dprintf(("PyThread_allocate_lock called\n"));
239 if (!initialized)
240 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000241
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000242 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000243
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000244 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000245
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000246 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000247}
248
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000249void
250PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000251{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000252 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000253
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000254 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000255}
256
257/*
258 * Return 1 on success if the lock was acquired
259 *
260 * and 0 if the lock was not acquired. This means a 0 is returned
261 * if the lock has already been acquired by this thread!
262 */
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000263int
264PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000265{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000266 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000267
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000268 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000269
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000270 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000271
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000272 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000273
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000274 return success;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000275}
276
Andrew MacIntyre63f0db62006-06-04 12:59:59 +0000277void
278PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000279{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000280 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000281
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000282 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
283 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 +0000284}
Andrew MacIntyre92913322006-06-13 15:04:24 +0000285
286/* minimum/maximum thread stack sizes supported */
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000287#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
288#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
Andrew MacIntyre92913322006-06-13 15:04:24 +0000289
290/* set the thread stack size.
291 * Return 0 if size is valid, -1 otherwise.
292 */
293static int
294_pythread_nt_set_stacksize(size_t size)
295{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000296 /* set to default */
297 if (size == 0) {
298 _pythread_stacksize = 0;
299 return 0;
300 }
Andrew MacIntyre92913322006-06-13 15:04:24 +0000301
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000302 /* valid range? */
303 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
304 _pythread_stacksize = size;
305 return 0;
306 }
Andrew MacIntyre92913322006-06-13 15:04:24 +0000307
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000308 return -1;
Andrew MacIntyre92913322006-06-13 15:04:24 +0000309}
310
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000311#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)