Commit 3c28863e authored by Guido van Rossum's avatar Guido van Rossum

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.)
parent 6f543b60
......@@ -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()));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment