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)
112 bootstrap(void *call
)
114 callobj
*obj
= (callobj
*)call
;
115 /* copy callobj since other thread might free it before we're done */
116 void (*func
)(void*) = obj
->func
;
117 void *arg
= obj
->arg
;
119 obj
->id
= PyThread_get_thread_ident();
120 ReleaseSemaphore(obj
->done
, 1, NULL
);
126 PyThread_start_new_thread(void (*func
)(void *), void *arg
)
131 dprintf(("%ld: PyThread_start_new_thread called\n",
132 PyThread_get_thread_ident()));
134 PyThread_init_thread();
136 obj
.id
= -1; /* guilty until proved innocent */
139 obj
.done
= CreateSemaphore(NULL
, 0, 1, NULL
);
140 if (obj
.done
== NULL
)
143 rv
= _beginthread(bootstrap
,
144 Py_SAFE_DOWNCAST(_pythread_stacksize
,
147 if (rv
== (Py_uintptr_t
)-1) {
148 /* I've seen errno == EAGAIN here, which means "there are
151 dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n",
152 PyThread_get_thread_ident(), (void*)rv
, errno
));
156 dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
157 PyThread_get_thread_ident(), (void*)rv
));
158 /* wait for thread to initialize, so we can get its id */
159 WaitForSingleObject(obj
.done
, INFINITE
);
160 assert(obj
.id
!= -1);
162 CloseHandle((HANDLE
)obj
.done
);
167 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
168 * thread in the system
171 PyThread_get_thread_ident(void)
174 PyThread_init_thread();
176 return GetCurrentThreadId();
180 do_PyThread_exit_thread(int no_cleanup
)
182 dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
192 PyThread_exit_thread(void)
194 do_PyThread_exit_thread(0);
198 PyThread__exit_thread(void)
200 do_PyThread_exit_thread(1);
205 do_PyThread_exit_prog(int status
, int no_cleanup
)
207 dprintf(("PyThread_exit_prog(%d) called\n", status
));
216 PyThread_exit_prog(int status
)
218 do_PyThread_exit_prog(status
, 0);
222 PyThread__exit_prog(int status
)
224 do_PyThread_exit_prog(status
, 1);
226 #endif /* NO_EXIT_PROG */
229 * Lock support. It has too be implemented as semaphores.
230 * I [Dag] tried to implement it with mutex but I could find a way to
231 * tell whether a thread already own the lock or not.
234 PyThread_allocate_lock(void)
238 dprintf(("PyThread_allocate_lock called\n"));
240 PyThread_init_thread();
242 aLock
= AllocNonRecursiveMutex() ;
244 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock
));
246 return (PyThread_type_lock
) aLock
;
250 PyThread_free_lock(PyThread_type_lock aLock
)
252 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock
));
254 FreeNonRecursiveMutex(aLock
) ;
258 * Return 1 on success if the lock was acquired
260 * and 0 if the lock was not acquired. This means a 0 is returned
261 * if the lock has already been acquired by this thread!
264 PyThread_acquire_lock(PyThread_type_lock aLock
, int waitflag
)
268 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock
, waitflag
));
270 success
= aLock
&& EnterNonRecursiveMutex((PNRMUTEX
) aLock
, (waitflag
? INFINITE
: 0)) == WAIT_OBJECT_0
;
272 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock
, waitflag
, success
));
278 PyThread_release_lock(PyThread_type_lock aLock
)
280 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock
));
282 if (!(aLock
&& LeaveNonRecursiveMutex((PNRMUTEX
) aLock
)))
283 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock
, GetLastError()));
286 /* minimum/maximum thread stack sizes supported */
287 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
288 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
290 /* set the thread stack size.
291 * Return 0 if size is valid, -1 otherwise.
294 _pythread_nt_set_stacksize(size_t size
)
298 _pythread_stacksize
= 0;
303 if (size
>= THREAD_MIN_STACKSIZE
&& size
< THREAD_MAX_STACKSIZE
) {
304 _pythread_stacksize
= size
;
311 #define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)