]> granicus.if.org Git - python/commitdiff
Issue #11223: Add threading._info() function providing informations about the
authorVictor Stinner <victor.stinner@haypocalc.com>
Tue, 19 Apr 2011 21:58:51 +0000 (23:58 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Tue, 19 Apr 2011 21:58:51 +0000 (23:58 +0200)
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).

Doc/library/threading.rst
Doc/whatsnew/3.3.rst
Include/pythread.h
Lib/test/test_os.py
Lib/test/test_threading.py
Lib/test/test_threadsignals.py
Lib/threading.py
Misc/NEWS
Modules/_threadmodule.c
Python/thread.c

index df47045ffb5d334ebdab847dbcb04696744288ed..dd2226d67f59b267f484db3a5ba869aaf5c234e9 100644 (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
index 602b2b70e3bbd8320d9572ed5ca40c5b189effb8..d3c9a97fc1ff0ffd13ef3bd3ac936d53239d0e03 100644 (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
 =============
 
index 9806c61159ba42ddbee565920e302347a93e2c65..9a35e5d01c4d610bf3595ee789bd63b768b468c6 100644 (file)
@@ -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);
index 35aa7fa75edd879bb0a2f20e644bb273e80466b0..543241294c669b94856e41626e2e6f04da466866 100644 (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
+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):
index c107652d268f4293642f213389bdcabe1d3ab14b..fd63d39367d014b238a0cfb5a0dc183e2a72f217 100644 (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__":
index 46e405ab818dbd7932be6e8579c7b12fd3d3af97..b0bc6072851177aa852bdf5991489aa2f9559ded 100644 (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.
index cb09afaa6635d81d1ecb2ba718104eb418f8701e..eb3cb626c37ce969fabeb44983375ab93896149d 100644 (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
 
 
index 27be0ccdf4b78fc373325611b428371bb734fced..7cb812cf79da86043c7f1042d18cb9507d6139e5 100644 (file)
--- 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.
index ef17b2845c3d04d9b881171b628773df67e41eae..914d671d6a2c5c1ba744441167272296358ae972 100644 (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 */
 };
 
@@ -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);
index d224046e6471d1ab58f12b24626b2171726e8537..5213a725aed97289b8c7267ce4efbcc07aa7d337 100644 (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;
+}