blob: c8ed6cd70e642bc1a2a5f5fc1a2aa567f565a34d [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
104#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
105
106VOID DeleteNonRecursiveMutex(PNRMUTEX mutex)
107{
108 /* No in-use check */
109 CloseHandle(mutex->hevent) ;
110 mutex->hevent = NULL ; /* Just in case */
111}
112
113DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
114{
115 /* Assume that the thread waits successfully */
116 DWORD ret ;
117
118 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
119 if (!wait)
120 {
121 if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1)
122 return WAIT_TIMEOUT ;
123 ret = WAIT_OBJECT_0 ;
124 }
125 else
126 ret = InterlockedIncrement(&mutex->owned) ?
127 /* Some thread owns the mutex, let's wait... */
128 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
129
130 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
131 return ret ;
132}
133
134BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
135{
136 /* We don't own the mutex */
137 mutex->thread_id = 0 ;
138 return
139 InterlockedDecrement(&mutex->owned) < 0 ||
140 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
141}
142
143PNRMUTEX AllocNonRecursiveMutex()
144{
145 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
146 if (mutex && !InitializeNonRecursiveMutex(mutex))
147 {
148 free(mutex) ;
149 mutex = NULL ;
150 }
151 return mutex ;
152}
153
154void FreeNonRecursiveMutex(PNRMUTEX mutex)
155{
156 if (mutex)
157 {
158 DeleteNonRecursiveMutex(mutex) ;
159 free(mutex) ;
160 }
161}
162
Guido van Rossum65d5b571998-12-21 19:32:43 +0000163long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000164
165/*
166 * Change all headers to pure ANSI as no one will use K&R style on an
167 * NT
168 */
169
170/*
171 * Initialization of the C package, should not be needed.
172 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000173static void PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000174{
175}
176
177/*
178 * Thread support.
179 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000180int PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000181{
Guido van Rossum49b12261997-08-14 20:12:58 +0000182 long rv;
183 int success = 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000184
Guido van Rossum65d5b571998-12-21 19:32:43 +0000185 dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000186 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000187 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000188
Guido van Rossum49b12261997-08-14 20:12:58 +0000189 rv = _beginthread(func, 0, arg); /* use default stack size */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000190
Guido van Rossum49b12261997-08-14 20:12:58 +0000191 if (rv != -1) {
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000192 success = 1;
Guido van Rossum4cea6052000-05-05 14:29:59 +0000193 dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), rv));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000194 }
195
196 return success;
197}
198
199/*
200 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
201 * thread in the system
202 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000203long PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000204{
205 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000206 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000207
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000208 return GetCurrentThreadId();
209}
210
Guido van Rossum65d5b571998-12-21 19:32:43 +0000211static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000212{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000213 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000214 if (!initialized)
215 if (no_cleanup)
216 _exit(0);
217 else
218 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000219 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000220}
221
Guido van Rossum65d5b571998-12-21 19:32:43 +0000222void PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000224 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000225}
226
Guido van Rossum65d5b571998-12-21 19:32:43 +0000227void PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000228{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000229 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000230}
231
232#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000233static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000234{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000235 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000236 if (!initialized)
237 if (no_cleanup)
238 _exit(status);
239 else
240 exit(status);
241}
242
Guido van Rossum65d5b571998-12-21 19:32:43 +0000243void PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000244{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000245 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000246}
247
Guido van Rossum65d5b571998-12-21 19:32:43 +0000248void PyThread__exit_prog _P1(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000249{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000250 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000251}
252#endif /* NO_EXIT_PROG */
253
254/*
255 * Lock support. It has too be implemented as semaphores.
256 * I [Dag] tried to implement it with mutex but I could find a way to
257 * tell whether a thread already own the lock or not.
258 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000259PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000260{
Guido van Rossum706262b2000-05-04 18:47:15 +0000261 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000262
Guido van Rossum65d5b571998-12-21 19:32:43 +0000263 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000264 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000265 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000266
Guido van Rossum706262b2000-05-04 18:47:15 +0000267 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000268
Guido van Rossum65d5b571998-12-21 19:32:43 +0000269 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000270
Guido van Rossum65d5b571998-12-21 19:32:43 +0000271 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000272}
273
Guido van Rossum65d5b571998-12-21 19:32:43 +0000274void PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000275{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000276 dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000277
Guido van Rossum706262b2000-05-04 18:47:15 +0000278 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000279}
280
281/*
282 * Return 1 on success if the lock was acquired
283 *
284 * and 0 if the lock was not acquired. This means a 0 is returned
285 * if the lock has already been acquired by this thread!
286 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000287int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000288{
Guido van Rossum706262b2000-05-04 18:47:15 +0000289 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000290
Guido van Rossum65d5b571998-12-21 19:32:43 +0000291 dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000292
Guido van Rossum706262b2000-05-04 18:47:15 +0000293 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000294
Guido van Rossum65d5b571998-12-21 19:32:43 +0000295 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 +0000296
297 return success;
298}
299
Guido van Rossum65d5b571998-12-21 19:32:43 +0000300void PyThread_release_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000301{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000302 dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000303
Guido van Rossum706262b2000-05-04 18:47:15 +0000304 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Guido van Rossum65d5b571998-12-21 19:32:43 +0000305 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 +0000306}
307
308/*
309 * Semaphore support.
310 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000311PyThread_type_sema PyThread_allocate_sema(int value)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000312{
313 HANDLE aSemaphore;
314
Guido van Rossum65d5b571998-12-21 19:32:43 +0000315 dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000316 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000317 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000318
319 aSemaphore = CreateSemaphore( NULL, /* Security attributes */
Guido van Rossum706262b2000-05-04 18:47:15 +0000320 value, /* Initial value */
321 INT_MAX, /* Maximum value */
322 NULL); /* Name of semaphore */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000323
Guido van Rossum65d5b571998-12-21 19:32:43 +0000324 dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000325
Guido van Rossum65d5b571998-12-21 19:32:43 +0000326 return (PyThread_type_sema) aSemaphore;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000327}
328
Guido van Rossum65d5b571998-12-21 19:32:43 +0000329void PyThread_free_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000330{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000331 dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000332
333 CloseHandle((HANDLE) aSemaphore);
334}
335
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000336/*
337 XXX must do something about waitflag
338 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000339int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000340{
341 DWORD waitResult;
342
Guido van Rossum65d5b571998-12-21 19:32:43 +0000343 dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000344
345 waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
346
Guido van Rossum65d5b571998-12-21 19:32:43 +0000347 dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000348 return 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000349}
350
Guido van Rossum65d5b571998-12-21 19:32:43 +0000351void PyThread_up_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000352{
353 ReleaseSemaphore(
354 (HANDLE) aSemaphore, /* Handle of semaphore */
355 1, /* increment count by one */
356 NULL); /* not interested in previous count */
357
Guido van Rossum65d5b571998-12-21 19:32:43 +0000358 dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000359}