blob: 9e82a9408f2d4f09ef145efb7bd5595044286acc [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{
Guido van Rossum582acec2000-06-28 22:07:35 +0000185 INT_PTR rv;
Guido van Rossum49b12261997-08-14 20:12:58 +0000186 int success = 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000187
Guido van Rossum65d5b571998-12-21 19:32:43 +0000188 dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000189 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000190 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000191
Guido van Rossum49b12261997-08-14 20:12:58 +0000192 rv = _beginthread(func, 0, arg); /* use default stack size */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000193
Guido van Rossum49b12261997-08-14 20:12:58 +0000194 if (rv != -1) {
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000195 success = 1;
Guido van Rossum582acec2000-06-28 22:07:35 +0000196 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", PyThread_get_thread_ident(), rv));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000197 }
198
199 return success;
200}
201
202/*
203 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
204 * thread in the system
205 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000206long PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000207{
208 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000209 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000210
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000211 return GetCurrentThreadId();
212}
213
Guido van Rossum65d5b571998-12-21 19:32:43 +0000214static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000215{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000216 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000217 if (!initialized)
218 if (no_cleanup)
219 _exit(0);
220 else
221 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000222 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223}
224
Guido van Rossum65d5b571998-12-21 19:32:43 +0000225void PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000226{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000227 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000228}
229
Guido van Rossum65d5b571998-12-21 19:32:43 +0000230void PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000231{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000232 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000233}
234
235#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000236static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000237{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000238 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000239 if (!initialized)
240 if (no_cleanup)
241 _exit(status);
242 else
243 exit(status);
244}
245
Guido van Rossum65d5b571998-12-21 19:32:43 +0000246void PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000247{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000248 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000249}
250
Guido van Rossum65d5b571998-12-21 19:32:43 +0000251void PyThread__exit_prog _P1(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000252{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000253 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000254}
255#endif /* NO_EXIT_PROG */
256
257/*
258 * Lock support. It has too be implemented as semaphores.
259 * I [Dag] tried to implement it with mutex but I could find a way to
260 * tell whether a thread already own the lock or not.
261 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000262PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000263{
Guido van Rossum706262b2000-05-04 18:47:15 +0000264 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000265
Guido van Rossum65d5b571998-12-21 19:32:43 +0000266 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000267 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000268 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000269
Guido van Rossum706262b2000-05-04 18:47:15 +0000270 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000271
Guido van Rossum65d5b571998-12-21 19:32:43 +0000272 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000273
Guido van Rossum65d5b571998-12-21 19:32:43 +0000274 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000275}
276
Guido van Rossum65d5b571998-12-21 19:32:43 +0000277void PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000278{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000279 dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000280
Guido van Rossum706262b2000-05-04 18:47:15 +0000281 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000282}
283
284/*
285 * Return 1 on success if the lock was acquired
286 *
287 * and 0 if the lock was not acquired. This means a 0 is returned
288 * if the lock has already been acquired by this thread!
289 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000290int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000291{
Guido van Rossum706262b2000-05-04 18:47:15 +0000292 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000293
Guido van Rossum65d5b571998-12-21 19:32:43 +0000294 dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000295
Guido van Rossum706262b2000-05-04 18:47:15 +0000296 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
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) -> %d\n", PyThread_get_thread_ident(),(long)aLock, waitflag, success));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000299
300 return success;
301}
302
Guido van Rossum65d5b571998-12-21 19:32:43 +0000303void PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000304{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000305 dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000306
Guido van Rossum706262b2000-05-04 18:47:15 +0000307 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Guido van Rossum65d5b571998-12-21 19:32:43 +0000308 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 +0000309}
310
311/*
312 * Semaphore support.
313 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000314PyThread_type_sema PyThread_allocate_sema(int value)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000315{
316 HANDLE aSemaphore;
317
Guido van Rossum65d5b571998-12-21 19:32:43 +0000318 dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000319 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000320 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000321
322 aSemaphore = CreateSemaphore( NULL, /* Security attributes */
Guido van Rossum706262b2000-05-04 18:47:15 +0000323 value, /* Initial value */
324 INT_MAX, /* Maximum value */
325 NULL); /* Name of semaphore */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000326
Guido van Rossum65d5b571998-12-21 19:32:43 +0000327 dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000328
Guido van Rossum65d5b571998-12-21 19:32:43 +0000329 return (PyThread_type_sema) aSemaphore;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000330}
331
Guido van Rossum65d5b571998-12-21 19:32:43 +0000332void PyThread_free_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000333{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000334 dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000335
336 CloseHandle((HANDLE) aSemaphore);
337}
338
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000339/*
340 XXX must do something about waitflag
341 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000342int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000343{
344 DWORD waitResult;
345
Guido van Rossum65d5b571998-12-21 19:32:43 +0000346 dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000347
348 waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
349
Guido van Rossum65d5b571998-12-21 19:32:43 +0000350 dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000351 return 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000352}
353
Guido van Rossum65d5b571998-12-21 19:32:43 +0000354void PyThread_up_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000355{
356 ReleaseSemaphore(
357 (HANDLE) aSemaphore, /* Handle of semaphore */
358 1, /* increment count by one */
359 NULL); /* not interested in previous count */
360
Guido van Rossum65d5b571998-12-21 19:32:43 +0000361 dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000362}