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.)
This commit is contained in:
parent
6f543b606d
commit
3c28863e08
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -111,7 +111,6 @@ void PyThread_init_thread(void)
|
|||
|
||||
#ifdef HAVE_PTH
|
||||
#include "thread_pth.h"
|
||||
#undef _POSIX_THREADS
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_THREADS
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <windows.h>
|
||||
#include <limits.h>
|
||||
#include <process.h>
|
||||
#include <Python.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue