2 /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
4 /* Eliminated some memory leaks, gsw@agere.com */
12 typedef struct NRMUTEX
{
16 } NRMUTEX
, *PNRMUTEX
;
20 InitializeNonRecursiveMutex(PNRMUTEX mutex
)
22 mutex
->owned
= -1 ; /* No threads have entered NonRecursiveMutex */
23 mutex
->thread_id
= 0 ;
24 mutex
->hevent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
) ;
25 return mutex
->hevent
!= NULL
; /* TRUE if the mutex is created */
29 DeleteNonRecursiveMutex(PNRMUTEX mutex
)
32 CloseHandle(mutex
->hevent
) ;
33 mutex
->hevent
= NULL
; /* Just in case */
37 EnterNonRecursiveMutex(PNRMUTEX mutex
, BOOL wait
)
39 /* Assume that the thread waits successfully */
42 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
45 if (InterlockedCompareExchange(&mutex
->owned
, 0, -1) != -1)
50 ret
= InterlockedIncrement(&mutex
->owned
) ?
51 /* Some thread owns the mutex, let's wait... */
52 WaitForSingleObject(mutex
->hevent
, INFINITE
) : WAIT_OBJECT_0
;
54 mutex
->thread_id
= GetCurrentThreadId() ; /* We own it */
59 LeaveNonRecursiveMutex(PNRMUTEX mutex
)
61 /* We don't own the mutex */
62 mutex
->thread_id
= 0 ;
64 InterlockedDecrement(&mutex
->owned
) < 0 ||
65 SetEvent(mutex
->hevent
) ; /* Other threads are waiting, wake one on them up */
69 AllocNonRecursiveMutex(void)
71 PNRMUTEX mutex
= (PNRMUTEX
)malloc(sizeof(NRMUTEX
)) ;
72 if (mutex
&& !InitializeNonRecursiveMutex(mutex
))
81 FreeNonRecursiveMutex(PNRMUTEX mutex
)
85 DeleteNonRecursiveMutex(mutex
) ;
90 long PyThread_get_thread_ident(void);
93 * Initialization of the C package, should not be needed.
96 PyThread__init_thread(void)
109 /* thunker to call adapt between the function type used by the system's
110 thread start function and the internally used one. */
111 #if defined(MS_WINCE)
114 static unsigned __stdcall
116 bootstrap(void *call
)
118 callobj
*obj
= (callobj
*)call
;
119 void (*func
)(void*) = obj
->func
;
120 void *arg
= obj
->arg
;
121 HeapFree(GetProcessHeap(), 0, obj
);
127 PyThread_start_new_thread(void (*func
)(void *), void *arg
)
133 dprintf(("%ld: PyThread_start_new_thread called\n",
134 PyThread_get_thread_ident()));
136 PyThread_init_thread();
138 obj
= (callobj
*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj
));
143 #if defined(MS_WINCE)
144 hThread
= CreateThread(NULL
,
145 Py_SAFE_DOWNCAST(_pythread_stacksize
, Py_ssize_t
, SIZE_T
),
146 bootstrap
, obj
, 0, &threadID
);
148 hThread
= (HANDLE
)_beginthreadex(0,
149 Py_SAFE_DOWNCAST(_pythread_stacksize
,
150 Py_ssize_t
, unsigned int),
155 #if defined(MS_WINCE)
156 /* Save error in variable, to prevent PyThread_get_thread_ident
157 from clobbering it. */
158 unsigned e
= GetLastError();
159 dprintf(("%ld: PyThread_start_new_thread failed, win32 error code %u\n",
160 PyThread_get_thread_ident(), e
));
162 /* I've seen errno == EAGAIN here, which means "there are
166 dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",
167 PyThread_get_thread_ident(), e
));
169 threadID
= (unsigned)-1;
170 HeapFree(GetProcessHeap(), 0, obj
);
173 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
174 PyThread_get_thread_ident(), (void*)hThread
));
175 CloseHandle(hThread
);
177 return (long) threadID
;
181 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
182 * thread in the system
185 PyThread_get_thread_ident(void)
188 PyThread_init_thread();
190 return GetCurrentThreadId();
194 PyThread_exit_thread(void)
196 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
199 #if defined(MS_WINCE)
208 PyThread_exit_prog(int status
)
210 dprintf(("PyThread_exit_prog(%d) called\n", status
));
214 #endif /* NO_EXIT_PROG */
217 * Lock support. It has too be implemented as semaphores.
218 * I [Dag] tried to implement it with mutex but I could find a way to
219 * tell whether a thread already own the lock or not.
222 PyThread_allocate_lock(void)
226 dprintf(("PyThread_allocate_lock called\n"));
228 PyThread_init_thread();
230 aLock
= AllocNonRecursiveMutex() ;
232 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock
));
234 return (PyThread_type_lock
) aLock
;
238 PyThread_free_lock(PyThread_type_lock aLock
)
240 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock
));
242 FreeNonRecursiveMutex(aLock
) ;
246 * Return 1 on success if the lock was acquired
248 * and 0 if the lock was not acquired. This means a 0 is returned
249 * if the lock has already been acquired by this thread!
252 PyThread_acquire_lock(PyThread_type_lock aLock
, int waitflag
)
256 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock
, waitflag
));
258 success
= aLock
&& EnterNonRecursiveMutex((PNRMUTEX
) aLock
, (waitflag
? INFINITE
: 0)) == WAIT_OBJECT_0
;
260 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock
, waitflag
, success
));
266 PyThread_release_lock(PyThread_type_lock aLock
)
268 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock
));
270 if (!(aLock
&& LeaveNonRecursiveMutex((PNRMUTEX
) aLock
)))
271 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock
, GetLastError()));
274 /* minimum/maximum thread stack sizes supported */
275 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
276 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
278 /* set the thread stack size.
279 * Return 0 if size is valid, -1 otherwise.
282 _pythread_nt_set_stacksize(size_t size
)
286 _pythread_stacksize
= 0;
291 if (size
>= THREAD_MIN_STACKSIZE
&& size
< THREAD_MAX_STACKSIZE
) {
292 _pythread_stacksize
= size
;
299 #define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)
302 /* use native Windows TLS functions */
303 #define Py_HAVE_NATIVE_TLS
305 #ifdef Py_HAVE_NATIVE_TLS
307 PyThread_create_key(void)
309 return (int) TlsAlloc();
313 PyThread_delete_key(int key
)
318 /* We must be careful to emulate the strange semantics implemented in thread.c,
319 * where the value is only set if it hasn't been set before.
322 PyThread_set_key_value(int key
, void *value
)
327 assert(value
!= NULL
);
328 oldvalue
= TlsGetValue(key
);
329 if (oldvalue
!= NULL
)
330 /* ignore value if already set */
332 ok
= TlsSetValue(key
, value
);
339 PyThread_get_key_value(int key
)
341 /* because TLS is used in the Py_END_ALLOW_THREAD macro,
342 * it is necessary to preserve the windows error state, because
343 * it is assumed to be preserved across the call to the macro.
344 * Ideally, the macro should be fixed, but it is simpler to
347 DWORD error
= GetLastError();
348 void *result
= TlsGetValue(key
);
354 PyThread_delete_key_value(int key
)
356 /* NULL is used as "key missing", and it is also the default
357 * given by TlsGetValue() if nothing has been set yet.
359 TlsSetValue(key
, NULL
);
362 /* reinitialization of TLS is not necessary after fork when using
363 * the native TLS functions. And forking isn't supported on Windows either.
366 PyThread_ReInitTLS(void)