From 3c28863e081986a232d4d2bba3cd9b63e14263c0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 16 Oct 2001 21:13:49 +0000 Subject: [PATCH] Partial patch from SF #452266, by Jason Petrone. This changes Pythread_start_thread() to return the thread ID, or -1 for an error. (It's technically an incompatible API change, but I doubt anyone calls it.) --- Doc/lib/libthread.tex | 9 ++++---- Include/pythread.h | 2 +- Misc/NEWS | 9 ++++++++ Modules/threadmodule.c | 19 ++++++++-------- Python/thread.c | 1 - Python/thread_beos.h | 4 ++-- Python/thread_cthread.h | 4 ++-- Python/thread_foobar.h | 4 ++-- Python/thread_lwp.h | 4 ++-- Python/thread_nt.h | 48 ++++++++++++++++++++++++++++++++++++++--- Python/thread_os2.h | 6 +++--- Python/thread_pth.h | 4 ++-- Python/thread_pthread.h | 8 +++++-- Python/thread_sgi.h | 4 ++-- Python/thread_solaris.h | 7 +++--- Python/thread_wince.h | 6 +++--- 16 files changed, 97 insertions(+), 42 deletions(-) diff --git a/Doc/lib/libthread.tex b/Doc/lib/libthread.tex index 652058da375..a2e5b7e4a0c 100644 --- a/Doc/lib/libthread.tex +++ b/Doc/lib/libthread.tex @@ -32,11 +32,10 @@ This is the type of lock objects. \end{datadesc} \begin{funcdesc}{start_new_thread}{function, args\optional{, kwargs}} -Start a new thread. The thread executes the function \var{function} -with the argument list \var{args} (which must be a tuple). The -optional \var{kwargs} argument specifies a dictionary of keyword -arguments. When the -function returns, the thread silently exits. When the function +Start a new thread and return its identifier. The thread executes the function +\var{function} with the argument list \var{args} (which must be a tuple). The +optional \var{kwargs} argument specifies a dictionary of keyword arguments. +When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run). \end{funcdesc} diff --git a/Include/pythread.h b/Include/pythread.h index c0a718e5ade..514cdeafe07 100644 --- a/Include/pythread.h +++ b/Include/pythread.h @@ -13,7 +13,7 @@ extern "C" { #endif DL_IMPORT(void) PyThread_init_thread(void); -DL_IMPORT(int) PyThread_start_new_thread(void (*)(void *), void *); +DL_IMPORT(long) PyThread_start_new_thread(void (*)(void *), void *); DL_IMPORT(void) PyThread_exit_thread(void); DL_IMPORT(void) PyThread__PyThread_exit_thread(void); DL_IMPORT(long) PyThread_get_thread_ident(void); diff --git a/Misc/NEWS b/Misc/NEWS index 690759b1709..1d86a4313ea 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -39,6 +39,8 @@ Core Library +- thread.start_new_thread() now returns the thread ID (previously None). + - doctest now excludes functions and classes not defined by the module being tested, thanks to Tim Hochberg. @@ -91,6 +93,13 @@ C API Consequently, PyArg_ParseTuple's 'L' code also accepts int (as well as long) arguments. +- PyThread_start_new_thread() now returns a long int giving the thread + ID, if one can be calculated; it returns -1 for error, 0 if no + thread ID is calculated (this is an incompatible change, but only + the thread module used this API). This code has only really been + tested on Linux and Windows; other platforms please beware (and + report any bugs or strange behavior). + New platforms Tests diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c index 7050914b067..bdc7932c6e0 100644 --- a/Modules/threadmodule.c +++ b/Modules/threadmodule.c @@ -213,6 +213,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) { PyObject *func, *args, *keyw = NULL; struct bootstate *boot; + long ident; if (!PyArg_ParseTuple(fargs, "OO|O:start_new_thread", &func, &args, &keyw)) return NULL; @@ -242,7 +243,8 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) Py_INCREF(args); Py_XINCREF(keyw); PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ - if (!PyThread_start_new_thread(t_bootstrap, (void*) boot)) { + ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); + if (ident == -1) { PyErr_SetString(ThreadError, "can't start new thread\n"); Py_DECREF(func); Py_DECREF(args); @@ -250,20 +252,19 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) PyMem_DEL(boot); return NULL; } - Py_INCREF(Py_None); - return Py_None; + return PyInt_FromLong(ident); } static char start_new_doc[] = "start_new_thread(function, args[, kwargs])\n\ (start_new() is an obsolete synonym)\n\ \n\ -Start a new thread. The thread will call the function with positional\n\ -arguments from the tuple args and keyword arguments taken from the optional\n\ -dictionary kwargs. The thread exits when the function returns; the return\n\ -value is ignored. The thread will also exit when the function raises an\n\ -unhandled exception; a stack trace will be printed unless the exception is\n\ -SystemExit."; +Start a new thread and return its identifier. The thread will call the\n\ +function with positional arguments from the tuple args and keyword arguments\n\ +taken from the optional dictionary kwargs. The thread exits when the\n\ +function returns; the return value is ignored. The thread will also exit\n\ +when the function raises an unhandled exception; a stack trace will be\n\ +printed unless the exception is SystemExit.\n"; static PyObject * thread_PyThread_exit_thread(PyObject *self, PyObject *args) diff --git a/Python/thread.c b/Python/thread.c index 3558af0afcd..df42f316be0 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -111,7 +111,6 @@ void PyThread_init_thread(void) #ifdef HAVE_PTH #include "thread_pth.h" -#undef _POSIX_THREADS #endif #ifdef _POSIX_THREADS diff --git a/Python/thread_beos.h b/Python/thread_beos.h index 046d37eea79..3f843474bff 100644 --- a/Python/thread_beos.h +++ b/Python/thread_beos.h @@ -112,7 +112,7 @@ static void PyThread__init_thread( void ) static int32 thread_count = 0; -int PyThread_start_new_thread( void (*func)(void *), void *arg ) +long PyThread_start_new_thread( void (*func)(void *), void *arg ) { status_t success = 0; thread_id tid; @@ -131,7 +131,7 @@ int PyThread_start_new_thread( void (*func)(void *), void *arg ) success = resume_thread( tid ); } - return ( success == B_NO_ERROR ? 1 : 0 ); + return ( success == B_NO_ERROR ? tid : -1 ); } long PyThread_get_thread_ident( void ) diff --git a/Python/thread_cthread.h b/Python/thread_cthread.h index 080505134dd..8487cc295f6 100644 --- a/Python/thread_cthread.h +++ b/Python/thread_cthread.h @@ -14,7 +14,7 @@ PyThread__init_thread(void) /* * Thread support. */ -int +long PyThread_start_new_thread(void (*func)(void *), void *arg) { int success = 0; /* init not needed when SOLARIS_THREADS and */ @@ -27,7 +27,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) * so well do it here */ cthread_detach(cthread_fork((cthread_fn_t) func, arg)); - return success < 0 ? 0 : 1; + return success < 0 ? -1 : 0; } long diff --git a/Python/thread_foobar.h b/Python/thread_foobar.h index 6edd0f93a50..4baf7e78463 100644 --- a/Python/thread_foobar.h +++ b/Python/thread_foobar.h @@ -10,7 +10,7 @@ PyThread__init_thread(void) /* * Thread support. */ -int +long PyThread_start_new_thread(void (*func)(void *), void *arg) { int success = 0; /* init not needed when SOLARIS_THREADS and */ @@ -19,7 +19,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) dprintf(("PyThread_start_new_thread called\n")); if (!initialized) PyThread_init_thread(); - return success < 0 ? 0 : 1; + return success < 0 ? -1 : 0; } long diff --git a/Python/thread_lwp.h b/Python/thread_lwp.h index bf44e0425cb..f6e688568b0 100644 --- a/Python/thread_lwp.h +++ b/Python/thread_lwp.h @@ -26,7 +26,7 @@ static void PyThread__init_thread(void) */ -int PyThread_start_new_thread(void (*func)(void *), void *arg) +long PyThread_start_new_thread(void (*func)(void *), void *arg) { thread_t tid; int success; @@ -34,7 +34,7 @@ int PyThread_start_new_thread(void (*func)(void *), void *arg) if (!initialized) PyThread_init_thread(); success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg); - return success < 0 ? 0 : 1; + return success < 0 ? -1 : 0; } long PyThread_get_thread_ident(void) diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 1d276274eb4..21aac29a496 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -5,6 +5,7 @@ #include #include #include +#include typedef struct NRMUTEX { LONG owned ; @@ -12,6 +13,8 @@ typedef struct NRMUTEX { HANDLE hevent ; } NRMUTEX, *PNRMUTEX ; +/* dictionary to correlate thread ids with the handle needed to terminate them*/ +static PyObject *threads = NULL; typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ; @@ -145,28 +148,67 @@ long PyThread_get_thread_ident(void); */ static void PyThread__init_thread(void) { + threads = PyDict_New(); } /* * Thread support. */ -int PyThread_start_new_thread(void (*func)(void *), void *arg) + +typedef struct { + void (*func)(void*); + void *arg; + long id; + HANDLE done; +} callobj; + +static int +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); + func(arg); + return 0; +} + +long PyThread_start_new_thread(void (*func)(void *), void *arg) { unsigned long rv; int success = 0; + callobj *obj; + int id; + PyObject *key, *val; dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); if (!initialized) PyThread_init_thread(); - rv = _beginthread(func, 0, arg); /* use default stack size */ + obj = malloc(sizeof(callobj)); + obj->func = func; + obj->arg = arg; + obj->done = CreateSemaphore(NULL, 0, 1, NULL); + + rv = _beginthread(func, 0, obj); /* use default stack size */ if (rv != (unsigned long)-1) { success = 1; dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", PyThread_get_thread_ident(), rv)); } - return success; + /* wait for thread to initialize and retrieve id */ + WaitForSingleObject(obj->done, 5000); /* maybe INFINITE instead of 5000? */ + CloseHandle((HANDLE)obj->done); + key = PyLong_FromLong(obj->id); + val = PyLong_FromLong((long)rv); + PyDict_SetItem(threads, key, val); + id = obj->id; + free(obj); + return id; } /* diff --git a/Python/thread_os2.h b/Python/thread_os2.h index 3f913c5dbef..31800d6c264 100644 --- a/Python/thread_os2.h +++ b/Python/thread_os2.h @@ -21,16 +21,16 @@ PyThread__init_thread(void) /* * Thread support. */ -int +long PyThread_start_new_thread(void (*func)(void *), void *arg) { int aThread; - int success = 1; + int success = 0; aThread = _beginthread(func,NULL,65536,arg); if( aThread == -1 ) { - success = 0; + success = -1; fprintf(stderr,"aThread failed == %d",aThread); dprintf(("_beginthread failed. return %ld\n", errno)); } diff --git a/Python/thread_pth.h b/Python/thread_pth.h index 6596b1a8c77..71e0d042cff 100644 --- a/Python/thread_pth.h +++ b/Python/thread_pth.h @@ -44,7 +44,7 @@ static void PyThread__init_thread(void) */ -int PyThread_start_new_thread(void (*func)(void *), void *arg) +long PyThread_start_new_thread(void (*func)(void *), void *arg) { pth_t th; dprintf(("PyThread_start_new_thread called\n")); @@ -56,7 +56,7 @@ int PyThread_start_new_thread(void (*func)(void *), void *arg) (void *)arg ); - return th == NULL ? 0 : 1; + return th; } long PyThread_get_thread_ident(void) diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 7170c8a8120..0fbafdafc70 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -143,7 +143,7 @@ PyThread__init_thread(void) */ -int +long PyThread_start_new_thread(void (*func)(void *), void *arg) { pthread_t th; @@ -210,7 +210,11 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) pthread_detach(th); #endif } - return success != 0 ? 0 : 1; +#if SIZEOF_PTHREAD_T <= SIZEOF_LONG + return (long) th; +#else + return (long) *(long *) &th; +#endif } /* XXX This implementation is considered (to quote Tim Peters) "inherently diff --git a/Python/thread_sgi.h b/Python/thread_sgi.h index 863284e412a..eda79726f72 100644 --- a/Python/thread_sgi.h +++ b/Python/thread_sgi.h @@ -168,7 +168,7 @@ static void clean_threads(void) } } -int PyThread_start_new_thread(void (*func)(void *), void *arg) +long PyThread_start_new_thread(void (*func)(void *), void *arg) { #ifdef USE_DL long addr, size; @@ -223,7 +223,7 @@ int PyThread_start_new_thread(void (*func)(void *), void *arg) } if (usunsetlock(count_lock) < 0) perror("usunsetlock (count_lock)"); - return success < 0 ? 0 : 1; + return success; } long PyThread_get_thread_ident(void) diff --git a/Python/thread_solaris.h b/Python/thread_solaris.h index 66bdfa25a34..4c958b915e2 100644 --- a/Python/thread_solaris.h +++ b/Python/thread_solaris.h @@ -36,9 +36,10 @@ new_func(void *funcarg) } -int +long PyThread_start_new_thread(void (*func)(void *), void *arg) { + thread_t tid; struct func_arg *funcarg; int success = 0; /* init not needed when SOLARIS_THREADS and */ /* C_THREADS implemented properly */ @@ -50,12 +51,12 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) funcarg->func = func; funcarg->arg = arg; if (thr_create(0, 0, new_func, funcarg, - THR_DETACHED | THR_NEW_LWP, 0)) { + THR_DETACHED | THR_NEW_LWP, &tid)) { perror("thr_create"); free((void *) funcarg); success = -1; } - return success < 0 ? 0 : 1; + return tid; } long diff --git a/Python/thread_wince.h b/Python/thread_wince.h index 3790bdab7d0..b5129b2149d 100644 --- a/Python/thread_wince.h +++ b/Python/thread_wince.h @@ -22,10 +22,10 @@ static void PyThread__init_thread(void) /* * Thread support. */ -int PyThread_start_new_thread(void (*func)(void *), void *arg) +long PyThread_start_new_thread(void (*func)(void *), void *arg) { long rv; - int success = 0; + int success = -1; dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); if (!initialized) @@ -34,7 +34,7 @@ int PyThread_start_new_thread(void (*func)(void *), void *arg) rv = _beginthread(func, 0, arg); /* use default stack size */ if (rv != -1) { - success = 1; + success = 0; dprintf(("%ld: PyThread_start_new_thread succeeded:\n", PyThread_get_thread_ident())); }