--- Doc/lib/libthread.tex.orig Sun Jan 29 23:08:34 2006 +++ Doc/lib/libthread.tex Mon Mar 20 20:57:42 2006 @@ -74,6 +74,16 @@ another thread is created. \end{funcdesc} +\begin{funcdesc}{stack_size}{\optional{size}} +Return the thread stack size used when creating new threads. The +optional \var{size} argument specifies the stack size to be used for +subsequently created threads, and must be 0 (use platform or +configured default) or a positive integer in a platform defined range. +If changing the thread stack size is unsupported, or the specified size +is invalid, a RuntimeWarning is issued and the stack size is unmodified. +\versionadded{2.5} +\end{funcdesc} + Lock objects have the following methods: --- Include/pythread.h.orig Sun Jan 29 22:27:24 2006 +++ Include/pythread.h Mon Mar 20 14:42:26 2006 @@ -25,6 +25,9 @@ #define NOWAIT_LOCK 0 PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock); +PyAPI_FUNC(size_t) PyThread_get_stacksize(void); +PyAPI_FUNC(int) PyThread_set_stacksize(size_t); + #ifndef NO_EXIT_PROG PyAPI_FUNC(void) PyThread_exit_prog(int); PyAPI_FUNC(void) PyThread__PyThread_exit_prog(int); --- Lib/dummy_thread.py.orig Mon Jan 30 00:01:30 2006 +++ Lib/dummy_thread.py Mon Mar 20 20:56:09 2006 @@ -20,6 +20,7 @@ 'interrupt_main', 'LockType'] import traceback as _traceback +import warnings class error(Exception): """Dummy implementation of thread.error.""" @@ -74,6 +75,13 @@ def allocate_lock(): """Dummy implementation of thread.allocate_lock().""" return LockType() + +def stack_size(size=None): + """Dummy implementation of thread.stack_size().""" + if size is not None: + msg = "setting thread stack size not supported on this platform" + warnings.warn(msg, RuntimeWarning) + return 0 class LockType(object): """Class implementing dummy implementation of thread.LockType. --- Modules/threadmodule.c.orig Sat Mar 11 05:27:43 2006 +++ Modules/threadmodule.c Mon Mar 20 20:58:23 2006 @@ -595,6 +595,42 @@ be relied upon, and the number should be seen purely as a magic cookie.\n\ A thread's identity may be reused for another thread after it exits."); +static PyObject * +thread_stack_size(PyObject *self, PyObject *args) +{ + size_t old_size, new_size; + PyObject *set_size = NULL; + + if (!PyArg_UnpackTuple(args, "stack_size", 0, 1, &set_size)) + return NULL; + + old_size = PyThread_get_stacksize(); + + if (set_size != NULL) { + if (PyInt_Check(set_size)) + new_size = (size_t) PyInt_AsLong(set_size); + else { + PyErr_SetString(PyExc_TypeError, + "size must be an integer"); + return NULL; + } + if (PyThread_set_stacksize(new_size)) + return NULL; + } + + return PyInt_FromLong((long) old_size); +} + +PyDoc_STRVAR(stack_size_doc, +"stack_size([size]) -> size\n\ +\n\ +Return the thread stack size used when creating new threads. The\n\ +optional size argument specifies the stack size to be used for\n\ +subsequently created threads, and must be 0 (use platform or\n\ +configured default) or a positive integer in a platform defined range.\n\ +If changing the thread stack size is unsupported, or the specified size\n\ +is invalid, a RuntimeWarning is issued and the stack size is unmodified."); + static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, @@ -614,6 +650,9 @@ METH_NOARGS, interrupt_doc}, {"get_ident", (PyCFunction)thread_get_ident, METH_NOARGS, get_ident_doc}, + {"stack_size", (PyCFunction)thread_stack_size, + METH_VARARGS, + stack_size_doc}, #ifndef NO_EXIT_PROG {"exit_prog", (PyCFunction)thread_PyThread_exit_prog, METH_VARARGS}, --- Python/thread.c.orig Sun Jan 29 22:25:22 2006 +++ Python/thread.c Mon Mar 20 20:35:45 2006 @@ -94,6 +94,29 @@ PyThread__init_thread(); } +/* Support for runtime thread stack size tuning. + A value of 0 means using the platform's default stack size + or the size specified by the THREAD_STACK_SIZE macro. */ +static size_t _pythread_stacksize = 0; + +size_t PyThread_get_stacksize(void) +{ + return _pythread_stacksize; +} + +static int _pythread_unsupported_set_stacksize(size_t size) +{ + return PyErr_Warn(PyExc_RuntimeWarning, + "setting thread stack size not supported on " + "this platform"); +} + +/* Only platforms with THREAD_SET_STACKSIZE() defined in + pthread_.h, overriding this default definition, + will support changing the stack size. + Return 1 if an exception is pending, 0 otherwise. */ +#define THREAD_SET_STACKSIZE(x) _pythread_unsupported_set_stacksize(x) + #ifdef SGI_THREADS #include "thread_sgi.h" #endif @@ -148,6 +171,13 @@ #include "thread_foobar.h" #endif */ + +/* use appropriate thread stack size setting routine. + Return 1 if an exception is pending, 0 otherwise. */ +int PyThread_set_stacksize(size_t size) +{ + return THREAD_SET_STACKSIZE(size); +} #ifndef Py_HAVE_NATIVE_TLS /* If the platform has not supplied a platform specific --- Python/thread_nt.h.orig Fri Feb 17 05:26:04 2006 +++ Python/thread_nt.h Mon Mar 20 18:59:35 2006 @@ -185,7 +185,7 @@ if (obj.done == NULL) return -1; - rv = _beginthread(bootstrap, 0, &obj); /* use default stack size */ + rv = _beginthread(bootstrap, _pythread_stacksize, &obj); if (rv == (uintptr_t)-1) { /* I've seen errno == EAGAIN here, which means "there are * too many threads". @@ -313,3 +313,39 @@ if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); } + +/* minimum/maximum thread stack sizes supported */ +#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ +#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ + +/* set the thread stack size. + * Return 1 if an exception is pending, 0 otherwise. + */ +static int _pythread_nt_set_stacksize(size_t size) +{ + /* set to default */ + if (size == 0) + { + _pythread_stacksize = 0; + return 0; + } + + /* valid range? */ + if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) + { + _pythread_stacksize = size; + return 0; + } + else + { + char warning[128]; + snprintf(warning, + 128, + "thread stack size of %#x bytes not supported on Win32", + size); + return PyErr_Warn(PyExc_RuntimeWarning, warning); + } +} + +#undef THREAD_SET_STACKSIZE +#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x) --- Python/thread_os2.h.orig Sun Jan 29 22:25:22 2006 +++ Python/thread_os2.h Mon Mar 20 19:32:31 2006 @@ -14,10 +14,13 @@ long PyThread_get_thread_ident(void); #endif +/* default thread stack size of 64kB */ #if !defined(THREAD_STACK_SIZE) #define THREAD_STACK_SIZE 0x10000 #endif +#define OS2_STACKSIZE(x) (x ? x : THREAD_STACK_SIZE) + /* * Initialization of the C package, should not be needed. */ @@ -35,7 +38,10 @@ int aThread; int success = 0; - aThread = _beginthread(func, NULL, THREAD_STACK_SIZE, arg); + aThread = _beginthread(func, + NULL, + OS2_STACKSIZE(_pythread_stacksize), + arg); if (aThread == -1) { success = -1; @@ -154,8 +160,8 @@ DosCreateEventSem(NULL, &lock->changed, 0, 0); dprintf(("%ld: PyThread_allocate_lock() -> %p\n", - PyThread_get_thread_ident(), - lock->changed)); + PyThread_get_thread_ident(), + lock->changed)); return (PyThread_type_lock)lock; #endif @@ -274,3 +280,36 @@ DosExitCritSec(); #endif } + +/* minimum/maximum thread stack sizes supported */ +#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ +#define THREAD_MAX_STACKSIZE 0x2000000 /* 32MB */ + +/* set the thread stack size. + * Return 1 if an exception is pending, 0 otherwise. + */ +static int _pythread_os2_set_stacksize(size_t size) +{ + /* set to default */ + if (size == 0) + return _pythread_stacksize = 0; + + /* valid range? */ + if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) + { + _pythread_stacksize = size; + return 0; + } + else + { + char warning[128]; + snprintf(warning, + 128, + "thread stack size of %#x bytes not supported on OS/2", + size); + return PyErr_Warn(PyExc_RuntimeWarning, warning); + } +} + +#undef THREAD_SET_STACKSIZE +#define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x) --- Python/thread_pthread.h.orig Sun Jan 29 22:25:22 2006 +++ Python/thread_pthread.h Mon Mar 20 19:28:10 2006 @@ -125,40 +125,38 @@ { pthread_t th; int status; -#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_t attrs; -#endif + dprintf(("PyThread_start_new_thread called\n")); if (!initialized) PyThread_init_thread(); -#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_init(&attrs); -#endif + #ifdef THREAD_STACK_SIZE - pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE); + if (_pythread_stacksize == 0) + pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE); + else +#else + if (_pythread_stacksize != 0) #endif + pthread_attr_setstacksize(&attrs, _pythread_stacksize); + #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !defined(__FreeBSD__) - pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif status = pthread_create(&th, -#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) &attrs, -#else - (pthread_attr_t*)NULL, -#endif (void* (*)(void *))func, (void *)arg ); -#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_destroy(&attrs); -#endif if (status != 0) - return -1; + return -1; - pthread_detach(th); + pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG return (long) th; @@ -450,3 +448,35 @@ } #endif /* USE_SEMAPHORES */ + +/* set the thread stack size. + * Return 1 if an exception is pending, 0 otherwise. + */ +static int _pythread_pthread_set_stacksize(size_t size) +{ + /* set to default */ + if (size == 0) + { + _pythread_stacksize = 0; + return 0; + } + + /* valid range? */ + if (size >= PTHREAD_STACK_MIN) + { + _pythread_stacksize = size; + return 0; + } + else + { + char warning[128]; + snprintf(warning, + 128, + "thread stack size of %#x bytes not supported", + size); + return PyErr_Warn(PyExc_RuntimeWarning, warning); + } +} + +#undef THREAD_SET_STACKSIZE +#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)