blob: 6eac020ee04808226530a3cc2f4d1bdec4fe6f7e [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 */
Guido van Rossumc3f82b61995-01-17 16:29:31 +00004
Guido van Rossum49b12261997-08-14 20:12:58 +00005#include <windows.h>
6#include <limits.h>
7#include <process.h>
Guido van Rossum3c288632001-10-16 21:13:49 +00008#include <Python.h>
Guido van Rossumc3f82b61995-01-17 16:29:31 +00009
Guido van Rossum706262b2000-05-04 18:47:15 +000010typedef struct NRMUTEX {
11 LONG owned ;
12 DWORD thread_id ;
13 HANDLE hevent ;
14} NRMUTEX, *PNRMUTEX ;
15
Guido van Rossum3c288632001-10-16 21:13:49 +000016/* dictionary to correlate thread ids with the handle needed to terminate them*/
17static PyObject *threads = NULL;
Guido van Rossum706262b2000-05-04 18:47:15 +000018
19typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ;
20
21/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */
22static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand)
23{
24 static LONG spinlock = 0 ;
25 PVOID 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
60static interlocked_cmp_xchg_t *ixchg ;
61BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)
62{
63 if (!ixchg)
64 {
65 /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */
66 HANDLE kernel = GetModuleHandle("kernel32.dll") ;
67 if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL)
68 ixchg = interlocked_cmp_xchg ;
69 }
70
71 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
72 mutex->thread_id = 0 ;
73 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
74 return mutex->hevent != NULL ; /* TRUE if the mutex is created */
75}
76
Guido van Rossum582acec2000-06-28 22:07:35 +000077#ifdef InterlockedCompareExchange
78#undef InterlockedCompareExchange
79#endif
Guido van Rossum706262b2000-05-04 18:47:15 +000080#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
81
82VOID DeleteNonRecursiveMutex(PNRMUTEX mutex)
83{
84 /* No in-use check */
85 CloseHandle(mutex->hevent) ;
86 mutex->hevent = NULL ; /* Just in case */
87}
88
89DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
90{
91 /* Assume that the thread waits successfully */
92 DWORD ret ;
93
94 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
95 if (!wait)
96 {
97 if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1)
98 return WAIT_TIMEOUT ;
99 ret = WAIT_OBJECT_0 ;
100 }
101 else
102 ret = InterlockedIncrement(&mutex->owned) ?
103 /* Some thread owns the mutex, let's wait... */
104 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
105
106 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
107 return ret ;
108}
109
110BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
111{
112 /* We don't own the mutex */
113 mutex->thread_id = 0 ;
114 return
115 InterlockedDecrement(&mutex->owned) < 0 ||
116 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
117}
118
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000119PNRMUTEX AllocNonRecursiveMutex(void)
Guido van Rossum706262b2000-05-04 18:47:15 +0000120{
121 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
122 if (mutex && !InitializeNonRecursiveMutex(mutex))
123 {
124 free(mutex) ;
125 mutex = NULL ;
126 }
127 return mutex ;
128}
129
130void FreeNonRecursiveMutex(PNRMUTEX mutex)
131{
132 if (mutex)
133 {
134 DeleteNonRecursiveMutex(mutex) ;
135 free(mutex) ;
136 }
137}
138
Guido van Rossum65d5b571998-12-21 19:32:43 +0000139long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000140
141/*
142 * Change all headers to pure ANSI as no one will use K&R style on an
143 * NT
144 */
145
146/*
147 * Initialization of the C package, should not be needed.
148 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000149static void PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000150{
Guido van Rossum3c288632001-10-16 21:13:49 +0000151 threads = PyDict_New();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000152}
153
154/*
155 * Thread support.
156 */
Guido van Rossum3c288632001-10-16 21:13:49 +0000157
158typedef struct {
159 void (*func)(void*);
160 void *arg;
161 long id;
162 HANDLE done;
163} callobj;
164
165static int
166bootstrap(void *call)
167{
168 callobj *obj = (callobj*)call;
169 /* copy callobj since other thread might free it before we're done */
170 void (*func)(void*) = obj->func;
171 void *arg = obj->arg;
172
173 obj->id = PyThread_get_thread_ident();
174 ReleaseSemaphore(obj->done, 1, NULL);
175 func(arg);
176 return 0;
177}
178
179long PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000180{
Tim Peters79248aa2001-08-29 21:37:10 +0000181 unsigned long rv;
Guido van Rossum49b12261997-08-14 20:12:58 +0000182 int success = 0;
Guido van Rossum3c288632001-10-16 21:13:49 +0000183 callobj *obj;
184 int id;
185 PyObject *key, *val;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000186
Guido van Rossum65d5b571998-12-21 19:32:43 +0000187 dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000188 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000189 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000190
Guido van Rossum3c288632001-10-16 21:13:49 +0000191 obj = malloc(sizeof(callobj));
192 obj->func = func;
193 obj->arg = arg;
194 obj->done = CreateSemaphore(NULL, 0, 1, NULL);
195
Guido van Rossum2c40adb2001-10-16 21:50:04 +0000196 rv = _beginthread(bootstrap, 0, obj); /* use default stack size */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000197
Tim Peters79248aa2001-08-29 21:37:10 +0000198 if (rv != (unsigned long)-1) {
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000199 success = 1;
Guido van Rossum582acec2000-06-28 22:07:35 +0000200 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", PyThread_get_thread_ident(), rv));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000201 }
202
Guido van Rossum3c288632001-10-16 21:13:49 +0000203 /* wait for thread to initialize and retrieve id */
204 WaitForSingleObject(obj->done, 5000); /* maybe INFINITE instead of 5000? */
205 CloseHandle((HANDLE)obj->done);
206 key = PyLong_FromLong(obj->id);
207 val = PyLong_FromLong((long)rv);
208 PyDict_SetItem(threads, key, val);
209 id = obj->id;
210 free(obj);
211 return id;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000212}
213
214/*
215 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
216 * thread in the system
217 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000218long PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000219{
220 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000221 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000222
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223 return GetCurrentThreadId();
224}
225
Guido van Rossum65d5b571998-12-21 19:32:43 +0000226static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000227{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000228 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000229 if (!initialized)
230 if (no_cleanup)
231 _exit(0);
232 else
233 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000234 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000235}
236
Guido van Rossum65d5b571998-12-21 19:32:43 +0000237void PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000238{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000239 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000240}
241
Guido van Rossum65d5b571998-12-21 19:32:43 +0000242void PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000243{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000244 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000245}
246
247#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000248static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000249{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000250 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000251 if (!initialized)
252 if (no_cleanup)
253 _exit(status);
254 else
255 exit(status);
256}
257
Guido van Rossum65d5b571998-12-21 19:32:43 +0000258void PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000259{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000260 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000261}
262
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000263void PyThread__exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000264{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000265 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000266}
267#endif /* NO_EXIT_PROG */
268
269/*
270 * Lock support. It has too be implemented as semaphores.
271 * I [Dag] tried to implement it with mutex but I could find a way to
272 * tell whether a thread already own the lock or not.
273 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000274PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000275{
Guido van Rossum706262b2000-05-04 18:47:15 +0000276 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000277
Guido van Rossum65d5b571998-12-21 19:32:43 +0000278 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000279 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000280 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000281
Guido van Rossum706262b2000-05-04 18:47:15 +0000282 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000283
Fred Drakea44d3532000-06-30 15:01:00 +0000284 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000285
Guido van Rossum65d5b571998-12-21 19:32:43 +0000286 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000287}
288
Guido van Rossum65d5b571998-12-21 19:32:43 +0000289void PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000290{
Fred Drakea44d3532000-06-30 15:01:00 +0000291 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000292
Guido van Rossum706262b2000-05-04 18:47:15 +0000293 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000294}
295
296/*
297 * Return 1 on success if the lock was acquired
298 *
299 * and 0 if the lock was not acquired. This means a 0 is returned
300 * if the lock has already been acquired by this thread!
301 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000302int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000303{
Guido van Rossum706262b2000-05-04 18:47:15 +0000304 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000305
Fred Drakea44d3532000-06-30 15:01:00 +0000306 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000307
Guido van Rossum706262b2000-05-04 18:47:15 +0000308 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000309
Fred Drakea44d3532000-06-30 15:01:00 +0000310 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000311
312 return success;
313}
314
Guido van Rossum65d5b571998-12-21 19:32:43 +0000315void PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000316{
Fred Drakea44d3532000-06-30 15:01:00 +0000317 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000318
Guido van Rossum706262b2000-05-04 18:47:15 +0000319 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Fred Drakea44d3532000-06-30 15:01:00 +0000320 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000321}
322
323/*
324 * Semaphore support.
325 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000326PyThread_type_sema PyThread_allocate_sema(int value)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000327{
328 HANDLE aSemaphore;
329
Guido van Rossum65d5b571998-12-21 19:32:43 +0000330 dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000331 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000332 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000333
334 aSemaphore = CreateSemaphore( NULL, /* Security attributes */
Guido van Rossum706262b2000-05-04 18:47:15 +0000335 value, /* Initial value */
336 INT_MAX, /* Maximum value */
337 NULL); /* Name of semaphore */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000338
Fred Drakea44d3532000-06-30 15:01:00 +0000339 dprintf(("%ld: PyThread_allocate_sema() -> %p\n", PyThread_get_thread_ident(), aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000340
Guido van Rossum65d5b571998-12-21 19:32:43 +0000341 return (PyThread_type_sema) aSemaphore;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000342}
343
Guido van Rossum65d5b571998-12-21 19:32:43 +0000344void PyThread_free_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000345{
Fred Drakea44d3532000-06-30 15:01:00 +0000346 dprintf(("%ld: PyThread_free_sema(%p) called\n", PyThread_get_thread_ident(), aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000347
348 CloseHandle((HANDLE) aSemaphore);
349}
350
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000351/*
352 XXX must do something about waitflag
353 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000354int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000355{
356 DWORD waitResult;
357
Fred Drakea44d3532000-06-30 15:01:00 +0000358 dprintf(("%ld: PyThread_down_sema(%p) called\n", PyThread_get_thread_ident(), aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000359
360 waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
361
Fred Drakea44d3532000-06-30 15:01:00 +0000362 dprintf(("%ld: PyThread_down_sema(%p) return: %l\n", PyThread_get_thread_ident(), aSemaphore, waitResult));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000363 return 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000364}
365
Guido van Rossum65d5b571998-12-21 19:32:43 +0000366void PyThread_up_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000367{
368 ReleaseSemaphore(
369 (HANDLE) aSemaphore, /* Handle of semaphore */
370 1, /* increment count by one */
371 NULL); /* not interested in previous count */
372
Fred Drakea44d3532000-06-30 15:01:00 +0000373 dprintf(("%ld: PyThread_up_sema(%p)\n", PyThread_get_thread_ident(), aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000374}