[Python-checkins] cpython: faulthandler: dump_tracebacks_later() displays also the timeout

victor.stinner python-checkins at python.org
Fri Apr 8 13:40:17 CEST 2011


http://hg.python.org/cpython/rev/7af470b0fa5e
changeset:   69208:7af470b0fa5e
user:        Victor Stinner <victor.stinner at haypocalc.com>
date:        Fri Apr 08 13:39:59 2011 +0200
summary:
  faulthandler: dump_tracebacks_later() displays also the timeout

files:
  Lib/test/test_faulthandler.py |   4 +-
  Modules/faulthandler.c        |  52 +++++++++++++++++++++-
  2 files changed, 52 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -1,4 +1,5 @@
 from contextlib import contextmanager
+import datetime
 import faulthandler
 import re
 import signal
@@ -360,6 +361,7 @@
 
         Raise an error if the output doesn't match the expect format.
         """
+        timeout_str = str(datetime.timedelta(seconds=TIMEOUT))
         code = """
 import faulthandler
 import time
@@ -399,7 +401,7 @@
             count = loops
             if repeat:
                 count *= 2
-            header = 'Thread 0x[0-9a-f]+:\n'
+            header = r'Timeout \(%s\)!\nThread 0x[0-9a-f]+:\n' % timeout_str
             regex = expected_traceback(9, 20, header, count=count)
             self.assertRegex(trace, regex)
         else:
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -50,6 +50,8 @@
     int repeat;
     PyInterpreterState *interp;
     int exit;
+    char *header;
+    size_t header_len;
     /* The main thread always hold this lock. It is only released when
        faulthandler_thread() is interrupted until this thread exits, or at
        Python exit. */
@@ -424,6 +426,8 @@
         /* get the thread holding the GIL, NULL if no thread hold the GIL */
         current = _Py_atomic_load_relaxed(&_PyThreadState_Current);
 
+        write(thread.fd, thread.header, thread.header_len);
+
         errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current);
         ok = (errmsg == NULL);
 
@@ -449,6 +453,37 @@
     PyThread_acquire_lock(thread.cancel_event, 1);
 
     Py_CLEAR(thread.file);
+    if (thread.header) {
+        free(thread.header);
+        thread.header = NULL;
+    }
+}
+
+static char*
+format_timeout(double timeout)
+{
+    unsigned long us, sec, min, hour;
+    double intpart, fracpart;
+    char buffer[100];
+
+    fracpart = modf(timeout, &intpart);
+    sec = (unsigned long)intpart;
+    us = (unsigned long)(fracpart * 1e6);
+    min = sec / 60;
+    sec %= 60;
+    hour = min / 60;
+    min %= 60;
+
+    if (us != 0)
+        PyOS_snprintf(buffer, sizeof(buffer),
+                      "Timeout (%lu:%02lu:%02lu.%06lu)!\n",
+                      hour, min, sec, us);
+    else
+        PyOS_snprintf(buffer, sizeof(buffer),
+                      "Timeout (%lu:%02lu:%02lu)!\n",
+                      hour, min, sec);
+
+    return strdup(buffer);
 }
 
 static PyObject*
@@ -463,17 +498,18 @@
     int fd;
     int exit = 0;
     PyThreadState *tstate;
+    char *header;
+    size_t header_len;
 
     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
         "d|iOi:dump_tracebacks_later", kwlist,
         &timeout, &repeat, &file, &exit))
         return NULL;
-    timeout *= 1e6;
-    if (timeout >= (double) PY_TIMEOUT_MAX) {
+    if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) {
         PyErr_SetString(PyExc_OverflowError,  "timeout value is too large");
         return NULL;
     }
-    timeout_us = (PY_TIMEOUT_T)timeout;
+    timeout_us = (PY_TIMEOUT_T)(timeout * 1e6);
     if (timeout_us <= 0) {
         PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
         return NULL;
@@ -490,6 +526,12 @@
     if (file == NULL)
         return NULL;
 
+    /* format the timeout */
+    header = format_timeout(timeout);
+    if (header == NULL)
+        return PyErr_NoMemory();
+    header_len = strlen(header);
+
     /* Cancel previous thread, if running */
     cancel_dump_tracebacks_later();
 
@@ -501,6 +543,8 @@
     thread.repeat = repeat;
     thread.interp = tstate->interp;
     thread.exit = exit;
+    thread.header = header;
+    thread.header_len = header_len;
 
     /* Arm these locks to serve as events when released */
     PyThread_acquire_lock(thread.running, 1);
@@ -508,6 +552,8 @@
     if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) {
         PyThread_release_lock(thread.running);
         Py_CLEAR(thread.file);
+        free(header);
+        thread.header = NULL;
         PyErr_SetString(PyExc_RuntimeError,
                         "unable to start watchdog thread");
         return NULL;

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list