Skip to content

Commit 07f41ed

Browse files
author
gvanrossum
committed
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.) git-svn-id: http://svn.python.org/projects/python/trunk@23732 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 9e1581c commit 07f41ed

16 files changed

Lines changed: 97 additions & 42 deletions

Doc/lib/libthread.tex

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,10 @@ \section{\module{thread} ---
3232
\end{datadesc}
3333

3434
\begin{funcdesc}{start_new_thread}{function, args\optional{, kwargs}}
35-
Start a new thread. The thread executes the function \var{function}
36-
with the argument list \var{args} (which must be a tuple). The
37-
optional \var{kwargs} argument specifies a dictionary of keyword
38-
arguments. When the
39-
function returns, the thread silently exits. When the function
35+
Start a new thread and return its identifier. The thread executes the function
36+
\var{function} with the argument list \var{args} (which must be a tuple). The
37+
optional \var{kwargs} argument specifies a dictionary of keyword arguments.
38+
When the function returns, the thread silently exits. When the function
4039
terminates with an unhandled exception, a stack trace is printed and
4140
then the thread exits (but other threads continue to run).
4241
\end{funcdesc}

Include/pythread.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extern "C" {
1313
#endif
1414

1515
DL_IMPORT(void) PyThread_init_thread(void);
16-
DL_IMPORT(int) PyThread_start_new_thread(void (*)(void *), void *);
16+
DL_IMPORT(long) PyThread_start_new_thread(void (*)(void *), void *);
1717
DL_IMPORT(void) PyThread_exit_thread(void);
1818
DL_IMPORT(void) PyThread__PyThread_exit_thread(void);
1919
DL_IMPORT(long) PyThread_get_thread_ident(void);

Misc/NEWS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Core
3939

4040
Library
4141

42+
- thread.start_new_thread() now returns the thread ID (previously None).
43+
4244
- doctest now excludes functions and classes not defined by the module
4345
being tested, thanks to Tim Hochberg.
4446

@@ -91,6 +93,13 @@ C API
9193
Consequently, PyArg_ParseTuple's 'L' code also accepts int (as well
9294
as long) arguments.
9395

96+
- PyThread_start_new_thread() now returns a long int giving the thread
97+
ID, if one can be calculated; it returns -1 for error, 0 if no
98+
thread ID is calculated (this is an incompatible change, but only
99+
the thread module used this API). This code has only really been
100+
tested on Linux and Windows; other platforms please beware (and
101+
report any bugs or strange behavior).
102+
94103
New platforms
95104

96105
Tests

Modules/threadmodule.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
213213
{
214214
PyObject *func, *args, *keyw = NULL;
215215
struct bootstate *boot;
216+
long ident;
216217

217218
if (!PyArg_ParseTuple(fargs, "OO|O:start_new_thread", &func, &args, &keyw))
218219
return NULL;
@@ -242,28 +243,28 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
242243
Py_INCREF(args);
243244
Py_XINCREF(keyw);
244245
PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
245-
if (!PyThread_start_new_thread(t_bootstrap, (void*) boot)) {
246+
ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
247+
if (ident == -1) {
246248
PyErr_SetString(ThreadError, "can't start new thread\n");
247249
Py_DECREF(func);
248250
Py_DECREF(args);
249251
Py_XDECREF(keyw);
250252
PyMem_DEL(boot);
251253
return NULL;
252254
}
253-
Py_INCREF(Py_None);
254-
return Py_None;
255+
return PyInt_FromLong(ident);
255256
}
256257

257258
static char start_new_doc[] =
258259
"start_new_thread(function, args[, kwargs])\n\
259260
(start_new() is an obsolete synonym)\n\
260261
\n\
261-
Start a new thread. The thread will call the function with positional\n\
262-
arguments from the tuple args and keyword arguments taken from the optional\n\
263-
dictionary kwargs. The thread exits when the function returns; the return\n\
264-
value is ignored. The thread will also exit when the function raises an\n\
265-
unhandled exception; a stack trace will be printed unless the exception is\n\
266-
SystemExit.";
262+
Start a new thread and return its identifier. The thread will call the\n\
263+
function with positional arguments from the tuple args and keyword arguments\n\
264+
taken from the optional dictionary kwargs. The thread exits when the\n\
265+
function returns; the return value is ignored. The thread will also exit\n\
266+
when the function raises an unhandled exception; a stack trace will be\n\
267+
printed unless the exception is SystemExit.\n";
267268

268269
static PyObject *
269270
thread_PyThread_exit_thread(PyObject *self, PyObject *args)

Python/thread.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ void PyThread_init_thread(void)
111111

112112
#ifdef HAVE_PTH
113113
#include "thread_pth.h"
114-
#undef _POSIX_THREADS
115114
#endif
116115

117116
#ifdef _POSIX_THREADS

Python/thread_beos.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static void PyThread__init_thread( void )
112112

113113
static int32 thread_count = 0;
114114

115-
int PyThread_start_new_thread( void (*func)(void *), void *arg )
115+
long PyThread_start_new_thread( void (*func)(void *), void *arg )
116116
{
117117
status_t success = 0;
118118
thread_id tid;
@@ -131,7 +131,7 @@ int PyThread_start_new_thread( void (*func)(void *), void *arg )
131131
success = resume_thread( tid );
132132
}
133133

134-
return ( success == B_NO_ERROR ? 1 : 0 );
134+
return ( success == B_NO_ERROR ? tid : -1 );
135135
}
136136

137137
long PyThread_get_thread_ident( void )

Python/thread_cthread.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ PyThread__init_thread(void)
1414
/*
1515
* Thread support.
1616
*/
17-
int
17+
long
1818
PyThread_start_new_thread(void (*func)(void *), void *arg)
1919
{
2020
int success = 0; /* init not needed when SOLARIS_THREADS and */
@@ -27,7 +27,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
2727
* so well do it here
2828
*/
2929
cthread_detach(cthread_fork((cthread_fn_t) func, arg));
30-
return success < 0 ? 0 : 1;
30+
return success < 0 ? -1 : 0;
3131
}
3232

3333
long

Python/thread_foobar.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ PyThread__init_thread(void)
1010
/*
1111
* Thread support.
1212
*/
13-
int
13+
long
1414
PyThread_start_new_thread(void (*func)(void *), void *arg)
1515
{
1616
int success = 0; /* init not needed when SOLARIS_THREADS and */
@@ -19,7 +19,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
1919
dprintf(("PyThread_start_new_thread called\n"));
2020
if (!initialized)
2121
PyThread_init_thread();
22-
return success < 0 ? 0 : 1;
22+
return success < 0 ? -1 : 0;
2323
}
2424

2525
long

Python/thread_lwp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ static void PyThread__init_thread(void)
2626
*/
2727

2828

29-
int PyThread_start_new_thread(void (*func)(void *), void *arg)
29+
long PyThread_start_new_thread(void (*func)(void *), void *arg)
3030
{
3131
thread_t tid;
3232
int success;
3333
dprintf(("PyThread_start_new_thread called\n"));
3434
if (!initialized)
3535
PyThread_init_thread();
3636
success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
37-
return success < 0 ? 0 : 1;
37+
return success < 0 ? -1 : 0;
3838
}
3939

4040
long PyThread_get_thread_ident(void)

Python/thread_nt.h

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
#include <windows.h>
66
#include <limits.h>
77
#include <process.h>
8+
#include <Python.h>
89

910
typedef struct NRMUTEX {
1011
LONG owned ;
1112
DWORD thread_id ;
1213
HANDLE hevent ;
1314
} NRMUTEX, *PNRMUTEX ;
1415

16+
/* dictionary to correlate thread ids with the handle needed to terminate them*/
17+
static PyObject *threads = NULL;
1518

1619
typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ;
1720

@@ -145,28 +148,67 @@ long PyThread_get_thread_ident(void);
145148
*/
146149
static void PyThread__init_thread(void)
147150
{
151+
threads = PyDict_New();
148152
}
149153

150154
/*
151155
* Thread support.
152156
*/
153-
int PyThread_start_new_thread(void (*func)(void *), void *arg)
157+
158+
typedef struct {
159+
void (*func)(void*);
160+
void *arg;
161+
long id;
162+
HANDLE done;
163+
} callobj;
164+
165+
static int
166+
bootstrap(void *call)
167+
{
168+
callobj *obj = (callobj*)call;
169+
/* copy callobj since other thread might free it before we're done */
170+
void (*func)(void*) = obj->func;
171+
void *arg = obj->arg;
172+
173+
obj->id = PyThread_get_thread_ident();
174+
ReleaseSemaphore(obj->done, 1, NULL);
175+
func(arg);
176+
return 0;
177+
}
178+
179+
long PyThread_start_new_thread(void (*func)(void *), void *arg)
154180
{
155181
unsigned long rv;
156182
int success = 0;
183+
callobj *obj;
184+
int id;
185+
PyObject *key, *val;
157186

158187
dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident()));
159188
if (!initialized)
160189
PyThread_init_thread();
161190

162-
rv = _beginthread(func, 0, arg); /* use default stack size */
191+
obj = malloc(sizeof(callobj));
192+
obj->func = func;
193+
obj->arg = arg;
194+
obj->done = CreateSemaphore(NULL, 0, 1, NULL);
195+
196+
rv = _beginthread(func, 0, obj); /* use default stack size */
163197

164198
if (rv != (unsigned long)-1) {
165199
success = 1;
166200
dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", PyThread_get_thread_ident(), rv));
167201
}
168202

169-
return success;
203+
/* wait for thread to initialize and retrieve id */
204+
WaitForSingleObject(obj->done, 5000); /* maybe INFINITE instead of 5000? */
205+
CloseHandle((HANDLE)obj->done);
206+
key = PyLong_FromLong(obj->id);
207+
val = PyLong_FromLong((long)rv);
208+
PyDict_SetItem(threads, key, val);
209+
id = obj->id;
210+
free(obj);
211+
return id;
170212
}
171213

172214
/*

0 commit comments

Comments
 (0)