]> granicus.if.org Git - python/commitdiff
Issue 3582. Improved thread support and TLS for Windows
authorKristján Valur Jónsson <kristjan@ccpgames.com>
Fri, 9 Jan 2009 20:03:27 +0000 (20:03 +0000)
committerKristján Valur Jónsson <kristjan@ccpgames.com>
Fri, 9 Jan 2009 20:03:27 +0000 (20:03 +0000)
Python/thread_nt.h

index 944552992f4f442d8d445a5f953b9bb96ff3b6c9..5ec15f6a931957348060ca0e6ef1183ecc4c3e6f 100644 (file)
@@ -104,20 +104,16 @@ PyThread__init_thread(void)
 typedef struct {
        void (*func)(void*);
        void *arg;
-       long id;
-       HANDLE done;
 } callobj;
 
-static int
+/* thunker to call a __cdecl function instead of a __stdcall */
+static unsigned __stdcall
 bootstrap(void *call)
 {
        callobj *obj = (callobj*)call;
-       /* copy callobj since other thread might free it before we're done */
        void (*func)(void*) = obj->func;
        void *arg = obj->arg;
-
-       obj->id = PyThread_get_thread_ident();
-       ReleaseSemaphore(obj->done, 1, NULL);
+       HeapFree(GetProcessHeap(), 0, obj);
        func(arg);
        return 0;
 }
@@ -125,42 +121,41 @@ bootstrap(void *call)
 long
 PyThread_start_new_thread(void (*func)(void *), void *arg)
 {
-       Py_uintptr_t rv;
-       callobj obj;
-
+       HANDLE hThread;
+       unsigned threadID;
+       callobj *obj;
+       
        dprintf(("%ld: PyThread_start_new_thread called\n",
                 PyThread_get_thread_ident()));
        if (!initialized)
                PyThread_init_thread();
 
-       obj.id = -1;    /* guilty until proved innocent */
-       obj.func = func;
-       obj.arg = arg;
-       obj.done = CreateSemaphore(NULL, 0, 1, NULL);
-       if (obj.done == NULL)
+       obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
+       if (!obj)
                return -1;
-
-       rv = _beginthread(bootstrap,
+       obj->func = func;
+       obj->arg = arg;
+       hThread = (HANDLE)_beginthreadex(0,
                          Py_SAFE_DOWNCAST(_pythread_stacksize,
-                                          Py_ssize_t, int),
-                         &obj);
-       if (rv == (Py_uintptr_t)-1) {
+                                          Py_ssize_t, unsigned int),
+                         bootstrap, obj,
+                         0, &threadID);
+       if (hThread == 0) {
                /* I've seen errno == EAGAIN here, which means "there are
                 * too many threads".
                 */
-               dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n",
-                        PyThread_get_thread_ident(), (void*)rv, errno));
-               obj.id = -1;
+               dprintf(("%ld: PyThread_start_new_thread failed, errno %d\n",
+                        PyThread_get_thread_ident(), errno));
+               threadID = (unsigned)-1;
+               HeapFree(GetProcessHeap(), 0, obj);
        }
        else {
                dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n",
-                        PyThread_get_thread_ident(), (void*)rv));
+                        PyThread_get_thread_ident(), (void*)hThread));
                /* wait for thread to initialize, so we can get its id */
-               WaitForSingleObject(obj.done, INFINITE);
-               assert(obj.id != -1);
+               CloseHandle(hThread);
        }
-       CloseHandle((HANDLE)obj.done);
-       return obj.id;
+       return (long) threadID;
 }
 
 /*
@@ -176,52 +171,22 @@ PyThread_get_thread_ident(void)
        return GetCurrentThreadId();
 }
 
-static void
-do_PyThread_exit_thread(int no_cleanup)
-{
-       dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
-       if (!initialized)
-               if (no_cleanup)
-                       _exit(0);
-               else
-                       exit(0);
-       _endthread();
-}
-
 void
 PyThread_exit_thread(void)
 {
-       do_PyThread_exit_thread(0);
-}
-
-void
-PyThread__exit_thread(void)
-{
-       do_PyThread_exit_thread(1);
-}
-
-#ifndef NO_EXIT_PROG
-static void
-do_PyThread_exit_prog(int status, int no_cleanup)
-{
-       dprintf(("PyThread_exit_prog(%d) called\n", status));
+       dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident()));
        if (!initialized)
-               if (no_cleanup)
-                       _exit(status);
-               else
-                       exit(status);
+               exit(0);
+       _endthreadex(0);
 }
 
+#ifndef NO_EXIT_PROG
 void
 PyThread_exit_prog(int status)
 {
-       do_PyThread_exit_prog(status, 0);
-}
-
-void
-PyThread__exit_prog(int status)
-{
-       do_PyThread_exit_prog(status, 1);
+       dprintf(("PyThread_exit_prog(%d) called\n", status));
+       if (!initialized)
+               exit(status);
 }
 #endif /* NO_EXIT_PROG */
 
@@ -309,3 +274,64 @@ _pythread_nt_set_stacksize(size_t size)
 }
 
 #define THREAD_SET_STACKSIZE(x)        _pythread_nt_set_stacksize(x)
+
+
+/* use native Windows TLS functions */
+#define Py_HAVE_NATIVE_TLS
+
+#ifdef Py_HAVE_NATIVE_TLS
+int
+PyThread_create_key(void)
+{
+       return (int) TlsAlloc();
+}
+
+void
+PyThread_delete_key(int key)
+{
+       TlsFree(key);
+}
+
+/* We must be careful to emulate the strange semantics implemented in thread.c,
+ * where the value is only set if it hasn't been set before.
+ */
+int
+PyThread_set_key_value(int key, void *value)
+{
+       BOOL ok;
+       void *oldvalue;
+
+       assert(value != NULL);
+       oldvalue = TlsGetValue(key);
+       if (oldvalue != NULL)
+               /* ignore value if already set */
+               return 0;
+       ok = TlsSetValue(key, value);
+       if (!ok)
+               return -1;
+       return 0;
+}
+
+void *
+PyThread_get_key_value(int key)
+{
+       return TlsGetValue(key);
+}
+
+void
+PyThread_delete_key_value(int key)
+{
+       /* NULL is used as "key missing", and it is also the default
+        * given by TlsGetValue() if nothing has been set yet.
+        */
+       TlsSetValue(key, NULL);
+}
+
+/* reinitialization of TLS is not necessary after fork when using
+ * the native TLS functions.  And forking isn't supported on Windows either.
+ */
+void
+PyThread_ReInitTLS(void)
+{}
+
+#endif