diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -934,6 +934,32 @@ always available. to a console and Python apps started with :program:`pythonw`. +.. data:: thread_info + + A structseq holding information about the thread implementation. + + +------------------+-------------------------------------------------------------------+ + | attribute | explanation | + +==================+===================================================================+ + | :const:`name` | Name of the thread implementation (string, optional): | + | | | + | | * ``'nt'``: Windows threads | + | | * ``'os2'``: OS/2 threads | + | | * ``'pthread'``: POSIX threads | + | | * ``'solaris'``: Solaris threads | + | | * ``None``: Python compiled without threads | + +------------------+-------------------------------------------------------------------+ + | :const:`lock` | Name of the lock implementation (string, optional): | + | | | + | | * ``'semaphore'``: a lock uses a semaphore | + | | * ``'mutex+cond'``: a lock uses a mutex and a condition variable | + +------------------+-------------------------------------------------------------------+ + | :const:`version` | Name and version of the thread library (string, optional) | + +------------------+-------------------------------------------------------------------+ + + .. versionadded:: 3.3 + + .. data:: tracebacklimit When this variable is set to an integer value, it determines the maximum number diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -175,30 +175,6 @@ This module defines the following functi Availability: Windows, systems with POSIX threads. -.. function:: _info() - - Return a dictionary with informations about the thread implementation. - The ``'name'`` key gives the name of the thread implementation (string): - - * ``'nt'``: Windows threads - * ``'os2'``: OS/2 threads - * ``'pthread'``: POSIX threads - * ``'solaris'``: Solaris threads - - POSIX threads have two more keys: - - * ``'lock_implementation'`` (string): name of the lock - implementation - - * ``'semaphore'``: a lock uses a semaphore - * ``'mutex+cond'``: a lock uses a mutex and a condition variable - - * ``'pthread_version'`` (string, optional): name and version of the pthread - library - - .. versionadded:: 3.3 - - This module also defines the following constant: .. data:: TIMEOUT_MAX diff --git a/Include/pythread.h b/Include/pythread.h --- a/Include/pythread.h +++ b/Include/pythread.h @@ -74,7 +74,7 @@ PyAPI_FUNC(void) PyThread_release_lock(P PyAPI_FUNC(size_t) PyThread_get_stacksize(void); PyAPI_FUNC(int) PyThread_set_stacksize(size_t); -PyAPI_FUNC(PyObject*) _PyThread_Info(void); +PyAPI_FUNC(PyObject*) PyThread_GetInfo(void); /* Thread Local Storage (TLS) API */ PyAPI_FUNC(int) PyThread_create_key(void); diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py --- a/Lib/_dummy_thread.py +++ b/Lib/_dummy_thread.py @@ -149,6 +149,3 @@ def interrupt_main(): else: global _interrupt _interrupt = True - -def info(): - return {'name': 'dummy'} diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -29,13 +29,7 @@ except ImportError: # http://bugs.python.org/issue4970. USING_LINUXTHREADS = False if threading: - info = threading._info() - try: - pthread_version = info['pthread_version'] - except KeyError: - pass - else: - USING_LINUXTHREADS = pthread_version.startswith("linuxthreads") + USING_LINUXTHREADS = sys.thread_info['version'].startswith("linuxthreads") # Tests creating TESTFN class FileTests(unittest.TestCase): diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -474,6 +474,12 @@ class SysModuleTest(unittest.TestCase): if not sys.platform.startswith('win'): self.assertIsInstance(sys.abiflags, str) + def test_thread_info(self): + info = sys.thread_info + self.assertTrue(len(info), 3) + self.assertIn(info.name, ('nt', 'os2', 'pthread', 'solaris', None)) + self.assertIn(info.lock, ('semaphore', 'mutex+cond', None)) + def test_43581(self): # Can't use sys.stdout, as this is a StringIO object when # the test runs under regrtest. diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -719,16 +719,6 @@ class BarrierTests(lock_tests.BarrierTes barriertype = staticmethod(threading.Barrier) -class MiscTests(unittest.TestCase): - def test_info(self): - info = threading._info() - self.assertIn(info['name'], - 'nt os2 pthread solaris'.split()) - if info['name'] == 'pthread': - self.assertIn(info['lock_implementation'], - ('semaphore', 'mutex+cond')) - - def test_main(): test.support.run_unittest(LockTests, PyRLockTests, CRLockTests, EventTests, ConditionAsRLockTests, ConditionTests, @@ -736,7 +726,7 @@ def test_main(): ThreadTests, ThreadJoinOnShutdown, ThreadingExceptionTests, - BarrierTests, MiscTests, + BarrierTests, ) if __name__ == "__main__": diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -14,9 +14,8 @@ if sys.platform[:3] in ('win', 'os2') or process_pid = os.getpid() signalled_all=thread.allocate_lock() -info = thread.info() -USING_PTHREAD_COND = (info['name'] == 'pthread' - and info['lock_implementation'] == 'mutex+cond') +USING_PTHREAD_COND = (sys.thread_info.name == 'pthread' + and sys.thread_info.lock == 'mutex+cond') def registerSignals(for_usr1, for_usr2, for_alrm): usr1 = signal.signal(signal.SIGUSR1, for_usr1) diff --git a/Lib/threading.py b/Lib/threading.py --- a/Lib/threading.py +++ b/Lib/threading.py @@ -19,7 +19,7 @@ from collections import deque __all__ = ['active_count', 'Condition', 'current_thread', 'enumerate', 'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread', 'Barrier', - 'Timer', 'setprofile', 'settrace', 'local', 'stack_size', '_info'] + 'Timer', 'setprofile', 'settrace', 'local', 'stack_size'] # Rename some stuff so "from threading import *" is safe _start_new_thread = _thread.start_new_thread @@ -31,7 +31,6 @@ try: except AttributeError: _CRLock = None TIMEOUT_MAX = _thread.TIMEOUT_MAX -_info = _thread.info del _thread diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -180,7 +180,6 @@ LIBC= @LIBC@ SYSLIBS= $(LIBM) $(LIBC) SHLIBS= @SHLIBS@ -THREADOBJ= @THREADOBJ@ DLINCLDIR= @DLINCLDIR@ DYNLOADFILE= @DYNLOADFILE@ MACHDEP_OBJS= @MACHDEP_OBJS@ @@ -324,6 +323,7 @@ PYTHON_OBJS= \ Python/structmember.o \ Python/symtable.o \ Python/sysmodule.o \ + Python/thread.o \ Python/traceback.o \ Python/getopt.o \ Python/pystrcmp.o \ @@ -333,8 +333,7 @@ PYTHON_OBJS= \ Python/fileutils.o \ Python/$(DYNLOADFILE) \ $(LIBOBJS) \ - $(MACHDEP_OBJS) \ - $(THREADOBJ) + $(MACHDEP_OBJS) ########################################################################## diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1221,17 +1221,6 @@ requiring allocation in multiples of the (4kB pages are common; using multiples of 4096 for the stack size is\n\ the suggested approach in the absence of more specific information)."); -static PyObject * -thread_info(PyObject *self) -{ - return _PyThread_Info(); -} - -PyDoc_STRVAR(thread_info_doc, -"info() -> dict\n\ -\n\ -Informations about the thread implementation."); - static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, @@ -1253,8 +1242,6 @@ static PyMethodDef thread_methods[] = { METH_NOARGS, _count_doc}, {"stack_size", (PyCFunction)thread_stack_size, METH_VARARGS, stack_size_doc}, - {"info", (PyCFunction)thread_info, - METH_NOARGS, thread_info_doc}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -17,6 +17,7 @@ Data members: #include "Python.h" #include "code.h" #include "frameobject.h" +#include "pythread.h" #include "osdefs.h" @@ -1251,20 +1252,21 @@ PyDoc_STR( "\n\ Static objects:\n\ \n\ -float_info -- a dict with information about the float implementation.\n\ +builtin_module_names -- tuple of module names built into this interpreter\n\ +copyright -- copyright notice pertaining to this interpreter\n\ +exec_prefix -- prefix used to find the machine-specific Python library\n\ +executable -- pathname of this Python interpreter\n\ +float_info -- a struct sequence with information about the float implementation.\n\ +float_repr_style -- string indicating the style of repr() output for floats\n\ +hexversion -- version information encoded as a single integer\n\ int_info -- a struct sequence with information about the int implementation.\n\ maxsize -- the largest supported length of containers.\n\ maxunicode -- the largest supported character\n\ -builtin_module_names -- tuple of module names built into this interpreter\n\ +platform -- platform identifier\n\ +prefix -- prefix used to find the Python library\n\ +thread_info -- a struct sequence with information about the thread implementation.\n\ version -- the version of this interpreter as a string\n\ version_info -- version information as a named tuple\n\ -hexversion -- version information encoded as a single integer\n\ -copyright -- copyright notice pertaining to this interpreter\n\ -platform -- platform identifier\n\ -executable -- pathname of this Python interpreter\n\ -prefix -- prefix used to find the Python library\n\ -exec_prefix -- prefix used to find the machine-specific Python library\n\ -float_repr_style -- string indicating the style of repr() output for floats\n\ " ) #ifdef MS_WINDOWS @@ -1526,6 +1528,8 @@ _PySys_Init(void) PyLong_FromSsize_t(PY_SSIZE_T_MAX)); SET_SYS_FROM_STRING("float_info", PyFloat_GetInfo()); + SET_SYS_FROM_STRING("thread_info", + PyThread_GetInfo()); SET_SYS_FROM_STRING("int_info", PyLong_GetInfo()); /* initialize hash_info */ diff --git a/Python/thread.c b/Python/thread.c --- a/Python/thread.c +++ b/Python/thread.c @@ -7,6 +7,7 @@ #include "Python.h" +#ifdef WITH_THREAD #ifndef _POSIX_THREADS /* This means pthreads are not implemented in libc headers, hence the macro @@ -415,26 +416,57 @@ PyThread_ReInitTLS(void) #endif /* Py_HAVE_NATIVE_TLS */ +#endif /* WITH_THREAD */ + +PyDoc_STRVAR(threadinfo__doc__, +"sys.thread_info\n\ +\n\ +A structseq holding information about the thread implementation."); + +static PyStructSequence_Field threadinfo_fields[] = { + {"name", "name of the thread implementation (string)"}, + {"lock", "name of the lock implementation (string, optional)"}, + {"version", "name and version of the thread library (string, optional)"}, + {0} +}; + +static PyStructSequence_Desc threadinfo_desc = { + "sys.thread_info", /* name */ + threadinfo__doc__, /* doc */ + threadinfo_fields, /* fields */ + 3 +}; + +static PyTypeObject ThreadInfoType; + PyObject* -_PyThread_Info(void) +PyThread_GetInfo(void) { - PyObject *info, *value; - int ret; + PyObject *threadinfo; +#ifdef WITH_THREAD + PyObject *value; #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ && defined(_CS_GNU_LIBPTHREAD_VERSION)) char buffer[255]; int len; #endif + int pos = 0; +#endif - info = PyDict_New(); - if (info == NULL) + if (ThreadInfoType.tp_name == 0) + PyStructSequence_InitType(&ThreadInfoType, &threadinfo_desc); + + threadinfo = PyStructSequence_New(&ThreadInfoType); + if (threadinfo == NULL) return NULL; +#ifdef WITH_THREAD value = PyUnicode_FromString(PYTHREAD_NAME); - ret = PyDict_SetItemString(info, "name", value); - Py_DECREF(value); - if (ret) - goto error; + if (value == NULL) { + Py_DECREF(threadinfo); + return NULL; + } + PyStructSequence_SET_ITEM(threadinfo, pos++, value); #ifdef _POSIX_THREADS #ifdef USE_SEMAPHORES @@ -442,30 +474,39 @@ _PyThread_Info(void) #else value = PyUnicode_FromString("mutex+cond"); #endif - if (value == NULL) + if (value == NULL) { + Py_DECREF(threadinfo); return NULL; - ret = PyDict_SetItemString(info, "lock_implementation", value); - Py_DECREF(value); - if (ret) - goto error; + } +#else + Py_INCREF(Py_None); + value = Py_None; +#endif + PyStructSequence_SET_ITEM(threadinfo, pos++, value); -#if defined(HAVE_CONFSTR) && defined(_CS_GNU_LIBPTHREAD_VERSION) +#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ + && defined(_CS_GNU_LIBPTHREAD_VERSION)) + value = NULL; len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); if (0 < len && len < sizeof(buffer)) { value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); if (value == NULL) - goto error; - ret = PyDict_SetItemString(info, "pthread_version", value); - Py_DECREF(value); - if (ret) - goto error; + PyErr_Clear(); } + if (value == NULL) #endif + { + Py_INCREF(Py_None); + value = Py_None; + } + PyStructSequence_SET_ITEM(threadinfo, pos++, value); +#else + Py_INCREF(Py_None); + PyStructSequence_SET_ITEM(threadinfo, 0, Py_None); + Py_INCREF(Py_None); + PyStructSequence_SET_ITEM(threadinfo, 1, Py_None); + Py_INCREF(Py_None); + PyStructSequence_SET_ITEM(threadinfo, 2, Py_None); #endif - - return info; - -error: - Py_DECREF(info); - return NULL; + return threadinfo; } diff --git a/configure.in b/configure.in --- a/configure.in +++ b/configure.in @@ -2022,7 +2022,6 @@ then with_threads="yes" fi AC_MSG_RESULT($with_threads) -AC_SUBST(THREADOBJ) if test "$with_threads" = "no" then USE_THREAD_MODULE="#" @@ -2032,7 +2031,6 @@ then # Defining _REENTRANT on system with POSIX threads should not hurt. AC_DEFINE(_REENTRANT) posix_threads=yes - THREADOBJ="Python/thread.o" elif test "$ac_cv_kpthread" = "yes" then CC="$CC -Kpthread" @@ -2041,7 +2039,6 @@ then fi AC_DEFINE(WITH_THREAD) posix_threads=yes - THREADOBJ="Python/thread.o" elif test "$ac_cv_kthread" = "yes" then CC="$CC -Kthread" @@ -2050,7 +2047,6 @@ then fi AC_DEFINE(WITH_THREAD) posix_threads=yes - THREADOBJ="Python/thread.o" elif test "$ac_cv_pthread" = "yes" then CC="$CC -pthread" @@ -2059,7 +2055,6 @@ then fi AC_DEFINE(WITH_THREAD) posix_threads=yes - THREADOBJ="Python/thread.o" else if test ! -z "$with_threads" -a -d "$with_threads" then LDFLAGS="$LDFLAGS -L$with_threads" @@ -2086,13 +2081,11 @@ yes AC_DEFINE(C_THREADS) AC_DEFINE(HURD_C_THREADS, 1, [Define if you are using Mach cthreads directly under /include]) - LIBS="$LIBS -lthreads" - THREADOBJ="Python/thread.o"],[ + LIBS="$LIBS -lthreads"],[ AC_CHECK_HEADER(mach/cthreads.h, [AC_DEFINE(WITH_THREAD) AC_DEFINE(C_THREADS) AC_DEFINE(MACH_C_THREADS, 1, - [Define if you are using Mach cthreads under mach /]) - THREADOBJ="Python/thread.o"],[ + [Define if you are using Mach cthreads under mach /])],[ # Just looking for pthread_create in libpthread is not enough: # on HP/UX, pthread.h renames pthread_create to a different symbol name. # So we really have to include pthread.h, and then link. @@ -2105,40 +2098,32 @@ void * start_routine (void *arg) { exit pthread_create (NULL, NULL, start_routine, NULL)]])],[ AC_MSG_RESULT(yes) AC_DEFINE(WITH_THREAD) - posix_threads=yes - THREADOBJ="Python/thread.o"],[ + posix_threads=yes],[ LIBS=$_libs AC_CHECK_FUNC(pthread_detach, [AC_DEFINE(WITH_THREAD) - posix_threads=yes - THREADOBJ="Python/thread.o"],[ + posix_threads=yes],[ AC_CHECK_LIB(pthreads, pthread_create, [AC_DEFINE(WITH_THREAD) posix_threads=yes - LIBS="$LIBS -lpthreads" - THREADOBJ="Python/thread.o"], [ + LIBS="$LIBS -lpthreads"], [ AC_CHECK_LIB(c_r, pthread_create, [AC_DEFINE(WITH_THREAD) posix_threads=yes - LIBS="$LIBS -lc_r" - THREADOBJ="Python/thread.o"], [ + LIBS="$LIBS -lc_r"], [ AC_CHECK_LIB(pthread, __pthread_create_system, [AC_DEFINE(WITH_THREAD) posix_threads=yes - LIBS="$LIBS -lpthread" - THREADOBJ="Python/thread.o"], [ + LIBS="$LIBS -lpthread"], [ AC_CHECK_LIB(cma, pthread_create, [AC_DEFINE(WITH_THREAD) posix_threads=yes - LIBS="$LIBS -lcma" - THREADOBJ="Python/thread.o"],[ + LIBS="$LIBS -lcma"],[ USE_THREAD_MODULE="#"]) ])])])])])])]) AC_CHECK_LIB(mpc, usconfig, [AC_DEFINE(WITH_THREAD) LIBS="$LIBS -lmpc" - THREADOBJ="Python/thread.o" USE_THREAD_MODULE=""]) if test "$posix_threads" != "yes"; then AC_CHECK_LIB(thread, thr_create, [AC_DEFINE(WITH_THREAD) LIBS="$LIBS -lthread" - THREADOBJ="Python/thread.o" USE_THREAD_MODULE=""]) fi fi