summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/threading.rst24
-rw-r--r--Doc/whatsnew/3.3.rst8
-rw-r--r--Include/pythread.h4
-rw-r--r--Lib/test/test_os.py15
-rw-r--r--Lib/test/test_threading.py13
-rw-r--r--Lib/test/test_threadsignals.py7
-rw-r--r--Lib/threading.py3
-rw-r--r--Misc/NEWS13
-rw-r--r--Modules/_threadmodule.c24
-rw-r--r--Python/thread.c57
10 files changed, 150 insertions, 18 deletions
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index df47045..dd2226d 100644
--- a/Doc/library/threading.rst
+++ b/Doc/library/threading.rst
@@ -175,6 +175,30 @@ 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 602b2b7..d3c9a97 100644
--- a/Doc/whatsnew/3.3.rst
+++ b/Doc/whatsnew/3.3.rst
@@ -112,6 +112,14 @@ connection when done::
(Contributed by Giampaolo RodolĂ  in :issue:`9795`)
+threading
+---------
+
+* The :mod:`threading` module has a new :func:`~threading._info` function which
+ provides informations about the thread implementation.
+
+ (:issue:`11223`)
+
Optimizations
=============
diff --git a/Include/pythread.h b/Include/pythread.h
index 9806c61..9a35e5d 100644
--- a/Include/pythread.h
+++ b/Include/pythread.h
@@ -32,7 +32,7 @@ PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int);
on a lock (see PyThread_acquire_lock_timed() below).
PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that
type, and depends on the system threading API.
-
+
NOTE: this isn't the same value as `_thread.TIMEOUT_MAX`. The _thread
module exposes a higher-level API, with timeouts expressed in seconds
and floating-point numbers allowed.
@@ -74,6 +74,8 @@ 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);
+
/* Thread Local Storage (TLS) API */
PyAPI_FUNC(int) PyThread_create_key(void);
PyAPI_FUNC(void) PyThread_delete_key(int);
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 35aa7fa..5432412 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -27,12 +27,15 @@ 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.
-if (hasattr(os, "confstr_names") and
- "CS_GNU_LIBPTHREAD_VERSION" in os.confstr_names):
- libpthread = os.confstr("CS_GNU_LIBPTHREAD_VERSION")
- USING_LINUXTHREADS= libpthread.startswith("linuxthreads")
-else:
- USING_LINUXTHREADS= False
+USING_LINUXTHREADS = False
+if threading:
+ info = threading._info()
+ try:
+ pthread_version = info['pthread_version']
+ except KeyError:
+ pass
+ else:
+ USING_LINUXTHREADS = pthread_version.startswith("linuxthreads")
# Tests creating TESTFN
class FileTests(unittest.TestCase):
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index c107652..fd63d39 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -718,6 +718,17 @@ class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests):
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,
@@ -725,7 +736,7 @@ def test_main():
ThreadTests,
ThreadJoinOnShutdown,
ThreadingExceptionTests,
- BarrierTests
+ BarrierTests, MiscTests,
)
if __name__ == "__main__":
diff --git a/Lib/test/test_threadsignals.py b/Lib/test/test_threadsignals.py
index 46e405a..b0bc607 100644
--- a/Lib/test/test_threadsignals.py
+++ b/Lib/test/test_threadsignals.py
@@ -14,6 +14,9 @@ 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')
def registerSignals(for_usr1, for_usr2, for_alrm):
usr1 = signal.signal(signal.SIGUSR1, for_usr1)
@@ -70,6 +73,8 @@ class ThreadSignals(unittest.TestCase):
def alarm_interrupt(self, sig, frame):
raise KeyboardInterrupt
+ @unittest.skipIf(USING_PTHREAD_COND,
+ 'POSIX condition variables cannot be interrupted')
def test_lock_acquire_interruption(self):
# Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
# in a deadlock.
@@ -91,6 +96,8 @@ class ThreadSignals(unittest.TestCase):
finally:
signal.signal(signal.SIGALRM, oldalrm)
+ @unittest.skipIf(USING_PTHREAD_COND,
+ 'POSIX condition variables cannot be interrupted')
def test_rlock_acquire_interruption(self):
# Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck
# in a deadlock.
diff --git a/Lib/threading.py b/Lib/threading.py
index cb09afa..eb3cb62 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']
+ 'Timer', 'setprofile', 'settrace', 'local', 'stack_size', '_info']
# Rename some stuff so "from threading import *" is safe
_start_new_thread = _thread.start_new_thread
@@ -31,6 +31,7 @@ try:
except AttributeError:
_CRLock = None
TIMEOUT_MAX = _thread.TIMEOUT_MAX
+_info = _thread.info
del _thread
diff --git a/Misc/NEWS b/Misc/NEWS
index 27be0cc..7cb812c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -110,6 +110,9 @@ Core and Builtins
Library
-------
+- Issue #11223: Add threading._info() function providing informations about
+ the thread implementation.
+
- Issue #11731: simplify/enhance email parser/generator API by introducing
policy objects.
@@ -463,9 +466,9 @@ Build
- Issue #11268: Prevent Mac OS X Installer failure if Documentation
package had previously been installed.
-
+
- Issue #11495: OSF support is eliminated. It was deprecated in Python 3.2.
-
+
IDLE
----
@@ -487,6 +490,12 @@ Extensions
Tests
-----
+- Issue #11223: Skip test_lock_acquire_interruption() and
+ test_rlock_acquire_interruption() of test_threadsignals if a thread lock is
+ implemented using a POSIX mutex and a POSIX condition variable. A POSIX
+ condition variable cannot be interrupted by a signal (e.g. on Linux, the
+ futex system call is restarted).
+
- Issue #11790: Fix sporadic failures in test_multiprocessing.WithProcessesTestCondition.
- Fix possible "file already exists" error when running the tests in parallel.
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index ef17b28..914d671 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -1221,13 +1221,22 @@ 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},
+ METH_VARARGS, start_new_doc},
{"start_new", (PyCFunction)thread_PyThread_start_new_thread,
- METH_VARARGS,
- start_new_doc},
+ METH_VARARGS, start_new_doc},
{"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
METH_NOARGS, allocate_doc},
{"allocate", (PyCFunction)thread_PyThread_allocate_lock,
@@ -1243,8 +1252,9 @@ static PyMethodDef thread_methods[] = {
{"_count", (PyCFunction)thread__count,
METH_NOARGS, _count_doc},
{"stack_size", (PyCFunction)thread_stack_size,
- METH_VARARGS,
- stack_size_doc},
+ METH_VARARGS, stack_size_doc},
+ {"info", (PyCFunction)thread_info,
+ METH_NOARGS, thread_info_doc},
{NULL, NULL} /* sentinel */
};
@@ -1310,7 +1320,7 @@ PyInit__thread(void)
d = PyModule_GetDict(m);
ThreadError = PyExc_RuntimeError;
Py_INCREF(ThreadError);
-
+
PyDict_SetItemString(d, "error", ThreadError);
Locktype.tp_doc = lock_doc;
Py_INCREF(&Locktype);
diff --git a/Python/thread.c b/Python/thread.c
index d224046..5213a72 100644
--- a/Python/thread.c
+++ b/Python/thread.c
@@ -100,6 +100,7 @@ static size_t _pythread_stacksize = 0;
#endif
#ifdef SOLARIS_THREADS
+#define PYTHREAD_NAME "solaris"
#include "thread_solaris.h"
#endif
@@ -115,6 +116,7 @@ static size_t _pythread_stacksize = 0;
#endif
#ifdef _POSIX_THREADS
+#define PYTHREAD_NAME "pthread"
#include "thread_pthread.h"
#endif
@@ -124,14 +126,17 @@ static size_t _pythread_stacksize = 0;
#endif
#ifdef NT_THREADS
+#define PYTHREAD_NAME "nt"
#include "thread_nt.h"
#endif
#ifdef OS2_THREADS
+#define PYTHREAD_NAME "os2"
#include "thread_os2.h"
#endif
#ifdef PLAN9_THREADS
+#define PYTHREAD_NAME "plan9"
#include "thread_plan9.h"
#endif
@@ -409,3 +414,55 @@ PyThread_ReInitTLS(void)
}
#endif /* Py_HAVE_NATIVE_TLS */
+
+PyObject*
+_PyThread_Info(void)
+{
+ PyObject *info, *value;
+ int ret;
+ char buffer[255];
+ int len;
+
+ info = PyDict_New();
+ if (info == NULL)
+ return NULL;
+
+ value = PyUnicode_FromString(PYTHREAD_NAME);
+ ret = PyDict_SetItemString(info, "name", value);
+ Py_DECREF(value);
+ if (ret)
+ goto error;
+
+#ifdef _POSIX_THREADS
+#ifdef USE_SEMAPHORES
+ value = PyUnicode_FromString("semaphore");
+#else
+ value = PyUnicode_FromString("mutex+cond");
+#endif
+ if (value == NULL)
+ return NULL;
+ ret = PyDict_SetItemString(info, "lock_implementation", value);
+ Py_DECREF(value);
+ if (ret)
+ goto error;
+
+#if defined(HAVE_CONFSTR) && defined(_CS_GNU_LIBPTHREAD_VERSION)
+ 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;
+ }
+#endif
+#endif
+
+ return info;
+
+error:
+ Py_DECREF(info);
+ return NULL;
+}