PageRenderTime 16ms CodeModel.GetById 2ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Python/thread_nt.h

http://unladen-swallow.googlecode.com/
C++ Header | 311 lines | 222 code | 49 blank | 40 comment | 28 complexity | 50d1b517ddc922ed5eb98740f7c878e9 MD5 | raw file
  1
  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 */
  5
  6#include <windows.h>
  7#include <limits.h>
  8#ifdef HAVE_PROCESS_H
  9#include <process.h>
 10#endif
 11
 12typedef struct NRMUTEX {
 13	LONG   owned ;
 14	DWORD  thread_id ;
 15	HANDLE hevent ;
 16} NRMUTEX, *PNRMUTEX ;
 17
 18
 19BOOL
 20InitializeNonRecursiveMutex(PNRMUTEX mutex)
 21{
 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 */
 26}
 27
 28VOID
 29DeleteNonRecursiveMutex(PNRMUTEX mutex)
 30{
 31	/* No in-use check */
 32	CloseHandle(mutex->hevent) ;
 33	mutex->hevent = NULL ; /* Just in case */
 34}
 35
 36DWORD
 37EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)
 38{
 39	/* Assume that the thread waits successfully */
 40	DWORD ret ;
 41
 42	/* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */
 43	if (!wait)
 44	{
 45		if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)
 46			return WAIT_TIMEOUT ;
 47		ret = WAIT_OBJECT_0 ;
 48	}
 49	else
 50		ret = InterlockedIncrement(&mutex->owned) ?
 51			/* Some thread owns the mutex, let's wait... */
 52			WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;
 53
 54	mutex->thread_id = GetCurrentThreadId() ; /* We own it */
 55	return ret ;
 56}
 57
 58BOOL
 59LeaveNonRecursiveMutex(PNRMUTEX mutex)
 60{
 61	/* We don't own the mutex */
 62	mutex->thread_id = 0 ;
 63	return
 64		InterlockedDecrement(&mutex->owned) < 0 ||
 65		SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
 66}
 67
 68PNRMUTEX
 69AllocNonRecursiveMutex(void)
 70{
 71	PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
 72	if (mutex && !InitializeNonRecursiveMutex(mutex))
 73	{
 74		free(mutex) ;
 75		mutex = NULL ;
 76	}
 77	return mutex ;
 78}
 79
 80void
 81FreeNonRecursiveMutex(PNRMUTEX mutex)
 82{
 83	if (mutex)
 84	{
 85		DeleteNonRecursiveMutex(mutex) ;
 86		free(mutex) ;
 87	}
 88}
 89
 90long PyThread_get_thread_ident(void);
 91
 92/*
 93 * Initialization of the C package, should not be needed.
 94 */
 95static void
 96PyThread__init_thread(void)
 97{
 98}
 99
100/*
101 * Thread support.
102 */
103
104typedef struct {
105	void (*func)(void*);
106	void *arg;
107	long id;
108	HANDLE done;
109} callobj;
110
111static int
112bootstrap(void *call)
113{
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;
118
119	obj->id = PyThread_get_thread_ident();
120	ReleaseSemaphore(obj->done, 1, NULL);
121	func(arg);
122	return 0;
123}
124
125long
126PyThread_start_new_thread(void (*func)(void *), void *arg)
127{
128	Py_uintptr_t rv;
129	callobj obj;
130
131	dprintf(("%ld: PyThread_start_new_thread called\n",
132		 PyThread_get_thread_ident()));
133	if (!initialized)
134		PyThread_init_thread();
135
136	obj.id = -1;	/* guilty until proved innocent */
137	obj.func = func;
138	obj.arg = arg;
139	obj.done = CreateSemaphore(NULL, 0, 1, NULL);
140	if (obj.done == NULL)
141		return -1;
142
143	rv = _beginthread(bootstrap,
144			  Py_SAFE_DOWNCAST(_pythread_stacksize,
145					   Py_ssize_t, int),
146			  &obj);
147	if (rv == (Py_uintptr_t)-1) {
148		/* I've seen errno == EAGAIN here, which means "there are
149		 * too many threads".
150		 */
151		dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n",
152		         PyThread_get_thread_ident(), (void*)rv, errno));
153		obj.id = -1;
154	}
155	else {
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);
161	}
162	CloseHandle((HANDLE)obj.done);
163	return obj.id;
164}
165
166/*
167 * Return the thread Id instead of an handle. The Id is said to uniquely identify the
168 * thread in the system
169 */
170long
171PyThread_get_thread_ident(void)
172{
173	if (!initialized)
174		PyThread_init_thread();
175
176	return GetCurrentThreadId();
177}
178
179static void
180do_PyThread_exit_thread(int no_cleanup)
181{
182	dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
183	if (!initialized)
184		if (no_cleanup)
185			_exit(0);
186		else
187			exit(0);
188	_endthread();
189}
190
191void
192PyThread_exit_thread(void)
193{
194	do_PyThread_exit_thread(0);
195}
196
197void
198PyThread__exit_thread(void)
199{
200	do_PyThread_exit_thread(1);
201}
202
203#ifndef NO_EXIT_PROG
204static void
205do_PyThread_exit_prog(int status, int no_cleanup)
206{
207	dprintf(("PyThread_exit_prog(%d) called\n", status));
208	if (!initialized)
209		if (no_cleanup)
210			_exit(status);
211		else
212			exit(status);
213}
214
215void
216PyThread_exit_prog(int status)
217{
218	do_PyThread_exit_prog(status, 0);
219}
220
221void
222PyThread__exit_prog(int status)
223{
224	do_PyThread_exit_prog(status, 1);
225}
226#endif /* NO_EXIT_PROG */
227
228/*
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.
232 */
233PyThread_type_lock
234PyThread_allocate_lock(void)
235{
236	PNRMUTEX aLock;
237
238	dprintf(("PyThread_allocate_lock called\n"));
239	if (!initialized)
240		PyThread_init_thread();
241
242	aLock = AllocNonRecursiveMutex() ;
243
244	dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));
245
246	return (PyThread_type_lock) aLock;
247}
248
249void
250PyThread_free_lock(PyThread_type_lock aLock)
251{
252	dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
253
254	FreeNonRecursiveMutex(aLock) ;
255}
256
257/*
258 * Return 1 on success if the lock was acquired
259 *
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!
262 */
263int
264PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
265{
266	int success ;
267
268	dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));
269
270	success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
271
272	dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));
273
274	return success;
275}
276
277void
278PyThread_release_lock(PyThread_type_lock aLock)
279{
280	dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));
281
282	if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))
283		dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock, GetLastError()));
284}
285
286/* minimum/maximum thread stack sizes supported */
287#define THREAD_MIN_STACKSIZE	0x8000		/* 32kB */
288#define THREAD_MAX_STACKSIZE	0x10000000	/* 256MB */
289
290/* set the thread stack size.
291 * Return 0 if size is valid, -1 otherwise.
292 */
293static int
294_pythread_nt_set_stacksize(size_t size)
295{
296	/* set to default */
297	if (size == 0) {
298		_pythread_stacksize = 0;
299		return 0;
300	}
301
302	/* valid range? */
303	if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
304		_pythread_stacksize = size;
305		return 0;
306	}
307
308	return -1;
309}
310
311#define THREAD_SET_STACKSIZE(x)	_pythread_nt_set_stacksize(x)