blob: 0c7ced4abbe1206ab7cd3b4da59053a914a850f8 [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 ;
53
54 /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */
55 while(InterlockedExchange(&spinlock, 1)) Sleep(0) ;
56 result = *dest ;
57 if (result == comperand)
58 *dest = exc ;
59 /* Release spinlock */
60 spinlock = 0 ;
61 return result ;
62} ;
63
64static interlocked_cmp_xchg_t *ixchg ;
65BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)
66{
67 if (!ixchg)
68 {
69 /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */
70 HANDLE kernel = GetModuleHandle("kernel32.dll") ;
71 if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL)
72 ixchg = interlocked_cmp_xchg ;
73 }
74
75 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
76 mutex->thread_id = 0 ;
77 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
78 return mutex->hevent != NULL ; /* TRUE if the mutex is created */
79}
80
81#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand)))
82
83VOID DeleteNonRecursiveMutex(PNRMUTEX mutex)
84{
85 /* No in-use check */
86 CloseHandle(mutex->hevent) ;
87 mutex->hevent = NULL ; /* Just in case */
88}
89
90DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
91{
92 /* Assume that the thread waits successfully */
93 DWORD ret ;
94
95 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
96 if (!wait)
97 {
98 if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1)
99 return WAIT_TIMEOUT ;
100 ret = WAIT_OBJECT_0 ;
101 }
102 else
103 ret = InterlockedIncrement(&mutex->owned) ?
104 /* Some thread owns the mutex, let's wait... */
105 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
106
107 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
108 return ret ;
109}
110
111BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
112{
113 /* We don't own the mutex */
114 mutex->thread_id = 0 ;
115 return
116 InterlockedDecrement(&mutex->owned) < 0 ||
117 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
118}
119
120PNRMUTEX AllocNonRecursiveMutex()
121{
122 PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
123 if (mutex && !InitializeNonRecursiveMutex(mutex))
124 {
125 free(mutex) ;
126 mutex = NULL ;
127 }
128 return mutex ;
129}
130
131void FreeNonRecursiveMutex(PNRMUTEX mutex)
132{
133 if (mutex)
134 {
135 DeleteNonRecursiveMutex(mutex) ;
136 free(mutex) ;
137 }
138}
139
Guido van Rossum65d5b571998-12-21 19:32:43 +0000140long PyThread_get_thread_ident(void);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000141
142/*
143 * Change all headers to pure ANSI as no one will use K&R style on an
144 * NT
145 */
146
147/*
148 * Initialization of the C package, should not be needed.
149 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000150static void PyThread__init_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000151{
152}
153
154/*
155 * Thread support.
156 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000157int PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000158{
Guido van Rossum49b12261997-08-14 20:12:58 +0000159 long rv;
160 int success = 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000161
Guido van Rossum65d5b571998-12-21 19:32:43 +0000162 dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000163 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000164 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000165
Guido van Rossum49b12261997-08-14 20:12:58 +0000166 rv = _beginthread(func, 0, arg); /* use default stack size */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000167
Guido van Rossum49b12261997-08-14 20:12:58 +0000168 if (rv != -1) {
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000169 success = 1;
Guido van Rossum4cea6052000-05-05 14:29:59 +0000170 dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), rv));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000171 }
172
173 return success;
174}
175
176/*
177 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
178 * thread in the system
179 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000180long PyThread_get_thread_ident(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000181{
182 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000183 PyThread_init_thread();
Guido van Rossum706262b2000-05-04 18:47:15 +0000184
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000185 return GetCurrentThreadId();
186}
187
Guido van Rossum65d5b571998-12-21 19:32:43 +0000188static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000189{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000190 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000191 if (!initialized)
192 if (no_cleanup)
193 _exit(0);
194 else
195 exit(0);
Guido van Rossum49b12261997-08-14 20:12:58 +0000196 _endthread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000197}
198
Guido van Rossum65d5b571998-12-21 19:32:43 +0000199void PyThread_exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000200{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000201 do_PyThread_exit_thread(0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000202}
203
Guido van Rossum65d5b571998-12-21 19:32:43 +0000204void PyThread__exit_thread(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000205{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000206 do_PyThread_exit_thread(1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000207}
208
209#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000210static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000211{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000212 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000213 if (!initialized)
214 if (no_cleanup)
215 _exit(status);
216 else
217 exit(status);
218}
219
Guido van Rossum65d5b571998-12-21 19:32:43 +0000220void PyThread_exit_prog(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000221{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000222 do_PyThread_exit_prog(status, 0);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000223}
224
Guido van Rossum65d5b571998-12-21 19:32:43 +0000225void PyThread__exit_prog _P1(int status)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000226{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000227 do_PyThread_exit_prog(status, 1);
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000228}
229#endif /* NO_EXIT_PROG */
230
231/*
232 * Lock support. It has too be implemented as semaphores.
233 * I [Dag] tried to implement it with mutex but I could find a way to
234 * tell whether a thread already own the lock or not.
235 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000236PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000237{
Guido van Rossum706262b2000-05-04 18:47:15 +0000238 PNRMUTEX aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000239
Guido van Rossum65d5b571998-12-21 19:32:43 +0000240 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000241 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000242 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000243
Guido van Rossum706262b2000-05-04 18:47:15 +0000244 aLock = AllocNonRecursiveMutex() ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000245
Guido van Rossum65d5b571998-12-21 19:32:43 +0000246 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000247
Guido van Rossum65d5b571998-12-21 19:32:43 +0000248 return (PyThread_type_lock) aLock;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000249}
250
Guido van Rossum65d5b571998-12-21 19:32:43 +0000251void PyThread_free_lock(PyThread_type_lock aLock)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000252{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000253 dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000254
Guido van Rossum706262b2000-05-04 18:47:15 +0000255 FreeNonRecursiveMutex(aLock) ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000256}
257
258/*
259 * Return 1 on success if the lock was acquired
260 *
261 * and 0 if the lock was not acquired. This means a 0 is returned
262 * if the lock has already been acquired by this thread!
263 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000264int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000265{
Guido van Rossum706262b2000-05-04 18:47:15 +0000266 int success ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000267
Guido van Rossum65d5b571998-12-21 19:32:43 +0000268 dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000269
Guido van Rossum706262b2000-05-04 18:47:15 +0000270 success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000271
Guido van Rossum65d5b571998-12-21 19:32:43 +0000272 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 +0000273
274 return success;
275}
276
Guido van Rossum65d5b571998-12-21 19:32:43 +0000277void PyThread_release_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_release_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 if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
Guido van Rossum65d5b571998-12-21 19:32:43 +0000282 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 +0000283}
284
285/*
286 * Semaphore support.
287 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000288PyThread_type_sema PyThread_allocate_sema(int value)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000289{
290 HANDLE aSemaphore;
291
Guido van Rossum65d5b571998-12-21 19:32:43 +0000292 dprintf(("%ld: PyThread_allocate_sema called\n", PyThread_get_thread_ident()));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000293 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000294 PyThread_init_thread();
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000295
296 aSemaphore = CreateSemaphore( NULL, /* Security attributes */
Guido van Rossum706262b2000-05-04 18:47:15 +0000297 value, /* Initial value */
298 INT_MAX, /* Maximum value */
299 NULL); /* Name of semaphore */
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000300
Guido van Rossum65d5b571998-12-21 19:32:43 +0000301 dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000302
Guido van Rossum65d5b571998-12-21 19:32:43 +0000303 return (PyThread_type_sema) aSemaphore;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000304}
305
Guido van Rossum65d5b571998-12-21 19:32:43 +0000306void PyThread_free_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000307{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000308 dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000309
310 CloseHandle((HANDLE) aSemaphore);
311}
312
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000313/*
314 XXX must do something about waitflag
315 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000316int PyThread_down_sema(PyThread_type_sema aSemaphore, int waitflag)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000317{
318 DWORD waitResult;
319
Guido van Rossum65d5b571998-12-21 19:32:43 +0000320 dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000321
322 waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE);
323
Guido van Rossum65d5b571998-12-21 19:32:43 +0000324 dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000325 return 0;
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000326}
327
Guido van Rossum65d5b571998-12-21 19:32:43 +0000328void PyThread_up_sema(PyThread_type_sema aSemaphore)
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000329{
330 ReleaseSemaphore(
331 (HANDLE) aSemaphore, /* Handle of semaphore */
332 1, /* increment count by one */
333 NULL); /* not interested in previous count */
334
Guido van Rossum65d5b571998-12-21 19:32:43 +0000335 dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore));
Guido van Rossumc3f82b61995-01-17 16:29:31 +0000336}