diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index ba781b3a6d0..a34c4977c92 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -961,6 +961,35 @@ always available. to a console and Python apps started with :program:`pythonw`. +.. data:: thread_info + + A :term:`struct sequence` holding information about the thread + implementation. + + +------------------+---------------------------------------------------------+ + | Attribute | Explanation | + +==================+=========================================================+ + | :const:`name` | Name of the thread implementation: | + | | | + | | * ``'nt'``: Windows threads | + | | * ``'os2'``: OS/2 threads | + | | * ``'pthread'``: POSIX threads | + | | * ``'solaris'``: Solaris threads | + +------------------+---------------------------------------------------------+ + | :const:`lock` | Name of the lock implementation: | + | | | + | | * ``'semaphore'``: a lock uses a semaphore | + | | * ``'mutex+cond'``: a lock uses a mutex | + | | and a condition variable | + | | * ``None`` if this information is unknown | + +------------------+---------------------------------------------------------+ + | :const:`version` | Name and version of the thread library. It is a string, | + | | or ``None`` if these informations are unknown. | + +------------------+---------------------------------------------------------+ + + .. 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 index dd2226d67f5..df47045ffb5 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -175,30 +175,6 @@ This module defines the following functions and objects: 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/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index a26fe7587f5..93da9d8555a 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -112,11 +112,11 @@ connection when done:: (Contributed by Giampaolo RodolĂ  in :issue:`9795`) -threading ---------- +sys +--- -* The :mod:`threading` module has a new :func:`~threading._info` function which - provides informations about the thread implementation. +* The :mod:`sys` module has a new :func:`~sys.thread_info` :term:`struct + sequence` holding informations about the thread implementation. (:issue:`11223`) diff --git a/Include/pythread.h b/Include/pythread.h index 9a35e5d01c4..6e9f30337fb 100644 --- a/Include/pythread.h +++ b/Include/pythread.h @@ -74,7 +74,7 @@ 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); -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 index f2465a9c99d..13b1f26965a 100644 --- 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 index 543241294c6..aa9ff5dfe9e 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -27,15 +27,10 @@ except ImportError: # and unmaintained) linuxthreads threading library. There's an issue # when combining linuxthreads with a failed execv call: see # 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") +if hasattr(sys, 'thread_info') and sys.thread_info.version: + USING_LINUXTHREADS = sys.thread_info.version.startswith("linuxthreads") +else: + USING_LINUXTHREADS = False # Tests creating TESTFN class FileTests(unittest.TestCase): diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index e18019c15cc..61b2676c449 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -474,6 +474,14 @@ class SysModuleTest(unittest.TestCase): if not sys.platform.startswith('win'): self.assertIsInstance(sys.abiflags, str) + @unittest.skipUnless(hasattr(sys, 'thread_info'), + 'Threading required for this test.') + 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 index fd63d39367d..66a04c83f3b 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -719,16 +719,6 @@ class BarrierTests(lock_tests.BarrierTests): 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 index b0bc6072851..f975a75e85d 100644 --- a/Lib/test/test_threadsignals.py +++ b/Lib/test/test_threadsignals.py @@ -14,9 +14,8 @@ if sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos': 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 index 28c21466714..fafe7792f56 100644 --- 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/Modules/_threadmodule.c b/Modules/_threadmodule.c index 1aee77b5f72..8881427269c 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1227,17 +1227,6 @@ requiring allocation in multiples of the system memory page size\n\ (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}, @@ -1259,8 +1248,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 index fdf361fa8b4..b5492035365 100644 --- 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 @@ -1611,6 +1613,10 @@ _PySys_Init(void) PyUnicode_FromString("legacy")); #endif +#ifdef WITH_THREAD + SET_SYS_FROM_STRING("thread_info", PyThread_GetInfo()); +#endif + #undef SET_SYS_FROM_STRING if (PyErr_Occurred()) return NULL; diff --git a/Python/thread.c b/Python/thread.c index 1f15a22e2fc..c7d17d60e98 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -7,7 +7,6 @@ #include "Python.h" - #ifndef _POSIX_THREADS /* This means pthreads are not implemented in libc headers, hence the macro not present in unistd.h. But they still can be implemented as an external @@ -415,26 +414,51 @@ PyThread_ReInitTLS(void) #endif /* Py_HAVE_NATIVE_TLS */ +PyDoc_STRVAR(threadinfo__doc__, +"sys.thread_info\n\ +\n\ +A struct sequence holding information about the thread implementation."); + +static PyStructSequence_Field threadinfo_fields[] = { + {"name", "name of the thread implementation"}, + {"lock", "name of the lock implementation"}, + {"version", "name and version of the thread library"}, + {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, *value; + int pos = 0; #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ && defined(_CS_GNU_LIBPTHREAD_VERSION)) char buffer[255]; int len; #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; 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 +466,31 @@ _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)) { + if (1 < 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 -#endif - - return info; - -error: - Py_DECREF(info); - return NULL; + { + Py_INCREF(Py_None); + value = Py_None; + } + PyStructSequence_SET_ITEM(threadinfo, pos++, value); + return threadinfo; }