+++ /dev/null
-\r
-/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */\r
-/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */\r
-/* Eliminated some memory leaks, gsw@agere.com */\r
-\r
-#include <windows.h>\r
-#include <limits.h>\r
-#ifdef HAVE_PROCESS_H\r
-#include <process.h>\r
-#endif\r
-\r
-typedef struct NRMUTEX {\r
- LONG owned ;\r
- DWORD thread_id ;\r
- HANDLE hevent ;\r
-} NRMUTEX, *PNRMUTEX ;\r
-\r
-\r
-BOOL\r
-InitializeNonRecursiveMutex(PNRMUTEX mutex)\r
-{\r
- mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */\r
- mutex->thread_id = 0 ;\r
- mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;\r
- return mutex->hevent != NULL ; /* TRUE if the mutex is created */\r
-}\r
-\r
-VOID\r
-DeleteNonRecursiveMutex(PNRMUTEX mutex)\r
-{\r
- /* No in-use check */\r
- CloseHandle(mutex->hevent) ;\r
- mutex->hevent = NULL ; /* Just in case */\r
-}\r
-\r
-DWORD\r
-EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait)\r
-{\r
- /* Assume that the thread waits successfully */\r
- DWORD ret ;\r
-\r
- /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */\r
- if (!wait)\r
- {\r
- if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)\r
- return WAIT_TIMEOUT ;\r
- ret = WAIT_OBJECT_0 ;\r
- }\r
- else\r
- ret = InterlockedIncrement(&mutex->owned) ?\r
- /* Some thread owns the mutex, let's wait... */\r
- WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ;\r
-\r
- mutex->thread_id = GetCurrentThreadId() ; /* We own it */\r
- return ret ;\r
-}\r
-\r
-BOOL\r
-LeaveNonRecursiveMutex(PNRMUTEX mutex)\r
-{\r
- /* We don't own the mutex */\r
- mutex->thread_id = 0 ;\r
- return\r
- InterlockedDecrement(&mutex->owned) < 0 ||\r
- SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */\r
-}\r
-\r
-PNRMUTEX\r
-AllocNonRecursiveMutex(void)\r
-{\r
- PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;\r
- if (mutex && !InitializeNonRecursiveMutex(mutex))\r
- {\r
- free(mutex) ;\r
- mutex = NULL ;\r
- }\r
- return mutex ;\r
-}\r
-\r
-void\r
-FreeNonRecursiveMutex(PNRMUTEX mutex)\r
-{\r
- if (mutex)\r
- {\r
- DeleteNonRecursiveMutex(mutex) ;\r
- free(mutex) ;\r
- }\r
-}\r
-\r
-long PyThread_get_thread_ident(void);\r
-\r
-/*\r
- * Initialization of the C package, should not be needed.\r
- */\r
-static void\r
-PyThread__init_thread(void)\r
-{\r
-}\r
-\r
-/*\r
- * Thread support.\r
- */\r
-\r
-typedef struct {\r
- void (*func)(void*);\r
- void *arg;\r
-} callobj;\r
-\r
-/* thunker to call adapt between the function type used by the system's\r
-thread start function and the internally used one. */\r
-#if defined(MS_WINCE)\r
-static DWORD WINAPI\r
-#else\r
-static unsigned __stdcall\r
-#endif\r
-bootstrap(void *call)\r
-{\r
- callobj *obj = (callobj*)call;\r
- void (*func)(void*) = obj->func;\r
- void *arg = obj->arg;\r
- HeapFree(GetProcessHeap(), 0, obj);\r
- func(arg);\r
- return 0;\r
-}\r
-\r
-long\r
-PyThread_start_new_thread(void (*func)(void *), void *arg)\r
-{\r
- HANDLE hThread;\r
- unsigned threadID;\r
- callobj *obj;\r
-\r
- dprintf(("%ld: PyThread_start_new_thread called\n",\r
- PyThread_get_thread_ident()));\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
- obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));\r
- if (!obj)\r
- return -1;\r
- obj->func = func;\r
- obj->arg = arg;\r
-#if defined(MS_WINCE)\r
- hThread = CreateThread(NULL,\r
- Py_SAFE_DOWNCAST(_pythread_stacksize, Py_ssize_t, SIZE_T),\r
- bootstrap, obj, 0, &threadID);\r
-#else\r
- hThread = (HANDLE)_beginthreadex(0,\r
- Py_SAFE_DOWNCAST(_pythread_stacksize,\r
- Py_ssize_t, unsigned int),\r
- bootstrap, obj,\r
- 0, &threadID);\r
-#endif\r
- if (hThread == 0) {\r
-#if defined(MS_WINCE)\r
- /* Save error in variable, to prevent PyThread_get_thread_ident\r
- from clobbering it. */\r
- unsigned e = GetLastError();\r
- dprintf(("%ld: PyThread_start_new_thread failed, win32 error code %u\n",\r
- PyThread_get_thread_ident(), e));\r
-#else\r
- /* I've seen errno == EAGAIN here, which means "there are\r
- * too many threads".\r
- */\r
- int e = errno;\r
- dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",\r
- PyThread_get_thread_ident(), e));\r
-#endif\r
- threadID = (unsigned)-1;\r
- HeapFree(GetProcessHeap(), 0, obj);\r
- }\r
- else {\r
- dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",\r
- PyThread_get_thread_ident(), (void*)hThread));\r
- CloseHandle(hThread);\r
- }\r
- return (long) threadID;\r
-}\r
-\r
-/*\r
- * Return the thread Id instead of an handle. The Id is said to uniquely identify the\r
- * thread in the system\r
- */\r
-long\r
-PyThread_get_thread_ident(void)\r
-{\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
- return GetCurrentThreadId();\r
-}\r
-\r
-void\r
-PyThread_exit_thread(void)\r
-{\r
- dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));\r
- if (!initialized)\r
- exit(0);\r
-#if defined(MS_WINCE)\r
- ExitThread(0);\r
-#else\r
- _endthreadex(0);\r
-#endif\r
-}\r
-\r
-/*\r
- * Lock support. It has too be implemented as semaphores.\r
- * I [Dag] tried to implement it with mutex but I could find a way to\r
- * tell whether a thread already own the lock or not.\r
- */\r
-PyThread_type_lock\r
-PyThread_allocate_lock(void)\r
-{\r
- PNRMUTEX aLock;\r
-\r
- dprintf(("PyThread_allocate_lock called\n"));\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
- aLock = AllocNonRecursiveMutex() ;\r
-\r
- dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock));\r
-\r
- return (PyThread_type_lock) aLock;\r
-}\r
-\r
-void\r
-PyThread_free_lock(PyThread_type_lock aLock)\r
-{\r
- dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock));\r
-\r
- FreeNonRecursiveMutex(aLock) ;\r
-}\r
-\r
-/*\r
- * Return 1 on success if the lock was acquired\r
- *\r
- * and 0 if the lock was not acquired. This means a 0 is returned\r
- * if the lock has already been acquired by this thread!\r
- */\r
-int\r
-PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)\r
-{\r
- int success ;\r
-\r
- dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag));\r
-\r
- success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;\r
-\r
- dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success));\r
-\r
- return success;\r
-}\r
-\r
-void\r
-PyThread_release_lock(PyThread_type_lock aLock)\r
-{\r
- dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock));\r
-\r
- if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock)))\r
- dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n", PyThread_get_thread_ident(), aLock, GetLastError()));\r
-}\r
-\r
-/* minimum/maximum thread stack sizes supported */\r
-#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */\r
-#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */\r
-\r
-/* set the thread stack size.\r
- * Return 0 if size is valid, -1 otherwise.\r
- */\r
-static int\r
-_pythread_nt_set_stacksize(size_t size)\r
-{\r
- /* set to default */\r
- if (size == 0) {\r
- _pythread_stacksize = 0;\r
- return 0;\r
- }\r
-\r
- /* valid range? */\r
- if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {\r
- _pythread_stacksize = size;\r
- return 0;\r
- }\r
-\r
- return -1;\r
-}\r
-\r
-#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x)\r
-\r
-\r
-/* use native Windows TLS functions */\r
-#define Py_HAVE_NATIVE_TLS\r
-\r
-#ifdef Py_HAVE_NATIVE_TLS\r
-int\r
-PyThread_create_key(void)\r
-{\r
- return (int) TlsAlloc();\r
-}\r
-\r
-void\r
-PyThread_delete_key(int key)\r
-{\r
- TlsFree(key);\r
-}\r
-\r
-/* We must be careful to emulate the strange semantics implemented in thread.c,\r
- * where the value is only set if it hasn't been set before.\r
- */\r
-int\r
-PyThread_set_key_value(int key, void *value)\r
-{\r
- BOOL ok;\r
- void *oldvalue;\r
-\r
- assert(value != NULL);\r
- oldvalue = TlsGetValue(key);\r
- if (oldvalue != NULL)\r
- /* ignore value if already set */\r
- return 0;\r
- ok = TlsSetValue(key, value);\r
- if (!ok)\r
- return -1;\r
- return 0;\r
-}\r
-\r
-void *\r
-PyThread_get_key_value(int key)\r
-{\r
- /* because TLS is used in the Py_END_ALLOW_THREAD macro,\r
- * it is necessary to preserve the windows error state, because\r
- * it is assumed to be preserved across the call to the macro.\r
- * Ideally, the macro should be fixed, but it is simpler to\r
- * do it here.\r
- */\r
- DWORD error = GetLastError();\r
- void *result = TlsGetValue(key);\r
- SetLastError(error);\r
- return result;\r
-}\r
-\r
-void\r
-PyThread_delete_key_value(int key)\r
-{\r
- /* NULL is used as "key missing", and it is also the default\r
- * given by TlsGetValue() if nothing has been set yet.\r
- */\r
- TlsSetValue(key, NULL);\r
-}\r
-\r
-/* reinitialization of TLS is not necessary after fork when using\r
- * the native TLS functions. And forking isn't supported on Windows either.\r
- */\r
-void\r
-PyThread_ReInitTLS(void)\r
-{}\r
-\r
-#endif\r