blob: fb04f830ee845652fe6b032c2c323858f9287879 [file] [log] [blame]
Guido van Rossumc3f82b61995-01-17 16:29:31 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
Guido van Rossumd266eb41996-10-25 14:44:06 +00007Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
Guido van Rossumc3f82b61995-01-17 16:29:31 +00009provided that the above copyright notice appear in all copies and that
Guido van Rossumd266eb41996-10-25 14:44:06 +000010both that copyright notice and this permission notice appear in
Guido van Rossumc3f82b61995-01-17 16:29:31 +000011supporting documentation, and that the names of Stichting Mathematisch
Guido van Rossumd266eb41996-10-25 14:44:06 +000012Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
Guido van Rossumc3f82b61995-01-17 16:29:31 +000016
Guido van Rossumd266eb41996-10-25 14:44:06 +000017While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
Guido van Rossumc3f82b61995-01-17 16:29:31 +000029
30******************************************************************/
31
32/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
Guido van Rossum706262b2000-05-04 18:47:15 +000033/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
Guido van Rossumc3f82b61995-01-17 16:29:31 +000034
Guido van Rossum49b12261997-08-14 20:12:58 +000035#include <windows.h>
36#include <limits.h>
37#include <process.h>
Guido van Rossumc3f82b61995-01-17 16:29:31 +000038
Guido van Rossum706262b2000-05-04 18:47:15 +000039typedef struct NRMUTEX {
40 LONG owned ;
41 DWORD thread_id ;
42 HANDLE hevent ;
43} NRMUTEX, *PNRMUTEX ;
44
45
46typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ;
47
48/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */
49static PVOID WINAPI interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand)
50{
51 static LONG spinlock = 0 ;
52 PVOID result ;
Guido van Rossumede8c6e2000-05-11 12:53:51 +000053 DWORD dwSleep = 0;
Guido van Rossum706262b2000-05-04 18:47:15 +000054
55 /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */
Guido van Rossumede8c6e2000-05-11 12:53:51 +000056 while(InterlockedExchange(&spinlock, 1))
57 {
58 // Using Sleep(0) can cause a priority inversion.
59 // Sleep(0) only yields the processor if there's
60 // another thread of the same priority that's
61 // ready to run. If a high-priority thread is
62 // trying to acquire the lock, which is held by
63 // a low-priority thread, then the low-priority
64 // thread may never get scheduled and hence never
65 // free the lock. NT attempts to avoid priority
66 // inversions by temporarily boosting the priority
67 // of low-priority runnable threads, but the problem
68 // can still occur if there's a medium-priority
69 // thread that's always runnable. If Sleep(1) is used,
70 // then the thread unconditionally yields the CPU. We
71 // only do this for the second and subsequent even
72 // iterations, since a millisecond is a long time to wait
73 // if the thread can be scheduled in again sooner
74 // (~100,000 instructions).
75 // Avoid priority inversion: 0, 1, 0, 1,...
76 Sleep(dwSleep);
77 dwSleep = !dwSleep;
78 }
Guido van Rossum706262b2000-05-04 18:47:15 +000079 result = *dest ;
80 if (result == comperand)
81 *dest = exc ;
82 /* Release spinlock */
83 spinlock = 0 ;
84 return result ;
85} ;
86
87static interlocked_cmp_xchg_t *ixchg ;
88BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)
89{
90 if (!ixchg)
91 {
92 /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */
93 HANDLE kernel = GetModuleHandle("kernel32.dll") ;
94 if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL)
95 ixchg = interlocked_cmp_xchg ;
96 }
97
98 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
99 mutex->thread_id = 0 ;
100 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
101 return mutex->hevent != NULL ; /* TRUE if the mutex is created */
102}
103
Guido van Rossum582acec2000-06-28 22:07:35 +0000104#ifdef InterlockedCompareExchange
105#undef InterlockedCompareExchange
106#endif
Guido van Rossum706262b2000-05-04 18:47:15 +0000107#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
108
109VOID DeleteNonRecursiveMutex(PNRMUTEX mutex)
110{
111 /* No in-use check */
112 CloseHandle(mutex->hevent) ;
113 mutex->hevent = NULL ; /* Just in case */
114}
115
116DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
117{
118 /* Assume that the thread waits successfully */
119 DWORD ret ;
120
121 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
122 if (!wait)
123 {
124 if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1)
125 return WAIT_TIMEOUT ;
126 ret = WAIT_OBJECT_0 ;
127 }
128 else
129 ret = InterlockedIncrement(&mutex->owned) ?
130 /* Some thread owns the mutex, let's wait... */
131 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
132
133 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
134 return ret ;
135}
136
137BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
138{
139 /* We don't own the mutex */
140 mutex->thread_id = 0 ;
141 return
142 InterlockedDecrement(&mutex->owned) < 0 ||
143 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
144}
145
146PNRMUTEX AllocNonRecursiveMutex()
147{
148 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
149 if (mutex && !InitializeNonRecursiveMutex(mutex))
150 {
151 free(mutex) ;
152 mutex = NULL ;
153 }
154 return mutex ;
155}
156
157void FreeNonRecursiveMutex(PNRMUTEX mutex)
158{
159 if (mutex)
160 {
161 DeleteNonRecursiveMutex(mutex) ;
162 free(mutex) ;
163 }
164}
165
Guido van Rossum65d5b571998-12-21 19:32:43 +0000166long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000167
168/*
169 * Change all headers to pure ANSI as no one will use K&R style on an
170 * NT
171 */
172
173/*
174 * Initialization of the C package, should not be needed.
175 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000176static void PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000177{
178}
179
180/*
181 * Thread support.
182 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000183int PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000184{
Fredrik Lundh34a96372000-06-29 17:25:30 +0000185#if _MSC_VER >= 1200
Guido van Rossum582acec2000-06-28 22:07:35 +0000186 INT_PTR rv;
Fredrik Lundh34a96372000-06-29 17:25:30 +0000187#else
188 unsigned long rv;
189#endif
Guido van Rossum49b12261997-08-14 20:12:58 +0000190 int success = 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000191
Guido van Rossum65d5b571998-12-21 19:32:43 +0000192 dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000193 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000194 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000195
Guido van Rossum49b12261997-08-14 20:12:58 +0000196 rv = _beginthread(func, 0, arg); /* use default stack size */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000197
Guido van Rossum49b12261997-08-14 20:12:58 +0000198 if (rv != -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
203 return success;
204}
205
206/*
207 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
208 * thread in the system
209 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000210long PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000211{
212 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000213 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000214
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000215 return GetCurrentThreadId();
216}
217
Guido van Rossum65d5b571998-12-21 19:32:43 +0000218static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000219{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000220 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000221 if (!initialized)
222 if (no_cleanup)
223 _exit(0);
224 else
225 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000226 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000227}
228
Guido van Rossum65d5b571998-12-21 19:32:43 +0000229void PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000230{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000231 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000232}
233
Guido van Rossum65d5b571998-12-21 19:32:43 +0000234void PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000235{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000236 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000237}
238
239#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000240static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000241{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000242 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000243 if (!initialized)
244 if (no_cleanup)
245 _exit(status);
246 else
247 exit(status);
248}
249
Guido van Rossum65d5b571998-12-21 19:32:43 +0000250void PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000251{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000252 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000253}
254
Guido van Rossum65d5b571998-12-21 19:32:43 +0000255void PyThread__exit_prog _P1(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000256{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000257 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000258}
259#endif /* NO_EXIT_PROG */
260
261/*
262 * Lock support. It has too be implemented as semaphores.
263 * I [Dag] tried to implement it with mutex but I could find a way to
264 * tell whether a thread already own the lock or not.
265 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000266PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000267{
Guido van Rossum706262b2000-05-04 18:47:15 +0000268 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000269
Guido van Rossum65d5b571998-12-21 19:32:43 +0000270 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000271 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000272 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000273
Guido van Rossum706262b2000-05-04 18:47:15 +0000274 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000275
Guido van Rossum65d5b571998-12-21 19:32:43 +0000276 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000277
Guido van Rossum65d5b571998-12-21 19:32:43 +0000278 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000279}
280
Guido van Rossum65d5b571998-12-21 19:32:43 +0000281void PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000282{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000283 dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000284
Guido van Rossum706262b2000-05-04 18:47:15 +0000285 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000286}
287
288/*
289 * Return 1 on success if the lock was acquired
290 *
291 * and 0 if the lock was not acquired. This means a 0 is returned
292 * if the lock has already been acquired by this thread!
293 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000294int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000295{
Guido van Rossum706262b2000-05-04 18:47:15 +0000296 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000297
Guido van Rossum65d5b571998-12-21 19:32:43 +0000298 dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000299
Guido van Rossum706262b2000-05-04 18:47:15 +0000300 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000301
Guido van Rossum65d5b571998-12-21 19:32:43 +0000302 dprintf(("%ld: PyThread_acquire_lock(%lx, %d) -> %d\n", PyThread_get_thread_ident(),(long)aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000303
304 return success;
305}
306
Guido van Rossum65d5b571998-12-21 19:32:43 +0000307void PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000308{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000309 dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000310
Guido van Rossum706262b2000-05-04 18:47:15 +0000311 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Guido van Rossum65d5b571998-12-21 19:32:43 +0000312 dprintf(("%ld: Could not PyThread_release_lock(%lx) error: %l\n", PyThread_get_thread_ident(), (long)aLock, GetLastError()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000313}
314
315/*
316 * Semaphore support.
317 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000318PyThread_type_sema PyThread_allocate_sema(int value)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000319{
320 HANDLE aSemaphore;
321
Guido van Rossum65d5b571998-12-21 19:32:43 +0000322 dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000323 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000324 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000325
326 aSemaphore = CreateSemaphore( NULL, /* Security attributes */
Guido van Rossum706262b2000-05-04 18:47:15 +0000327 value, /* Initial value */
328 INT_MAX, /* Maximum value */
329 NULL); /* Name of semaphore */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000330
Guido van Rossum65d5b571998-12-21 19:32:43 +0000331 dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000332
Guido van Rossum65d5b571998-12-21 19:32:43 +0000333 return (PyThread_type_sema) aSemaphore;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000334}
335
Guido van Rossum65d5b571998-12-21 19:32:43 +0000336void PyThread_free_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000337{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000338 dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000339
340 CloseHandle((HANDLE) aSemaphore);
341}
342
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000343/*
344 XXX must do something about waitflag
345 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000346int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000347{
348 DWORD waitResult;
349
Guido van Rossum65d5b571998-12-21 19:32:43 +0000350 dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000351
352 waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
353
Guido van Rossum65d5b571998-12-21 19:32:43 +0000354 dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000355 return 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000356}
357
Guido van Rossum65d5b571998-12-21 19:32:43 +0000358void PyThread_up_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000359{
360 ReleaseSemaphore(
361 (HANDLE) aSemaphore, /* Handle of semaphore */
362 1, /* increment count by one */
363 NULL); /* not interested in previous count */
364
Guido van Rossum65d5b571998-12-21 19:32:43 +0000365 dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000366}