Issue #11223: Add threading._info() function providing informations about the

thread implementation.

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).
This commit is contained in:
Victor Stinner 2011-04-19 23:58:51 +02:00
parent cf2a807831
commit 754851f456
10 changed files with 150 additions and 18 deletions

View File

@ -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

View File

@ -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
=============

View File

@ -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);

View File

@ -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
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):

View File

@ -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__":

View File

@ -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.

View File

@ -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

View File

@ -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.
@ -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.

View File

@ -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 */
};

View File

@ -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;
}