Blame SOURCES/00370-GIL-monotonic-clock.patch

9b3a7c
diff --git a/Makefile.pre.in b/Makefile.pre.in
9b3a7c
index 8da1965..9864fe2 100644
9b3a7c
--- a/Makefile.pre.in
9b3a7c
+++ b/Makefile.pre.in
9b3a7c
@@ -884,7 +884,8 @@ regen-opcode-targets:
9b3a7c
 		$(srcdir)/Python/opcode_targets.h.new
9b3a7c
 	$(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new
9b3a7c
 
9b3a7c
-Python/ceval.o: $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/ceval_gil.h
9b3a7c
+Python/ceval.o: $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/ceval_gil.h \
9b3a7c
+		$(srcdir)/Python/condvar.h
9b3a7c
 
9b3a7c
 Python/frozen.o: $(srcdir)/Python/importlib.h $(srcdir)/Python/importlib_external.h
9b3a7c
 
9b3a7c
@@ -1706,7 +1707,7 @@ patchcheck: @DEF_MAKE_RULE@
9b3a7c
 
9b3a7c
 # Dependencies
9b3a7c
 
9b3a7c
-Python/thread.o: @THREADHEADERS@
9b3a7c
+Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h
9b3a7c
 
9b3a7c
 # Declare targets that aren't real files
9b3a7c
 .PHONY: all build_all sharedmods check-clean-src oldsharedmods test quicktest
9b3a7c
diff --git a/Python/ceval.c b/Python/ceval.c
9b3a7c
index 0b30cc1..3f1300c 100644
9b3a7c
--- a/Python/ceval.c
9b3a7c
+++ b/Python/ceval.c
9b3a7c
@@ -232,6 +232,7 @@ PyEval_InitThreads(void)
9b3a7c
 {
9b3a7c
     if (gil_created())
9b3a7c
         return;
9b3a7c
+    PyThread_init_thread();
9b3a7c
     create_gil();
9b3a7c
     take_gil(PyThreadState_GET());
9b3a7c
     main_thread = PyThread_get_thread_ident();
9b3a7c
diff --git a/Python/condvar.h b/Python/condvar.h
9b3a7c
index 9a71b17..39a420f 100644
9b3a7c
--- a/Python/condvar.h
9b3a7c
+++ b/Python/condvar.h
9b3a7c
@@ -59,20 +59,6 @@
9b3a7c
 
9b3a7c
 #include <pthread.h>
9b3a7c
 
9b3a7c
-#define PyCOND_ADD_MICROSECONDS(tv, interval) \
9b3a7c
-do { /* TODO: add overflow and truncation checks */ \
9b3a7c
-    tv.tv_usec += (long) interval; \
9b3a7c
-    tv.tv_sec += tv.tv_usec / 1000000; \
9b3a7c
-    tv.tv_usec %= 1000000; \
9b3a7c
-} while (0)
9b3a7c
-
9b3a7c
-/* We assume all modern POSIX systems have gettimeofday() */
9b3a7c
-#ifdef GETTIMEOFDAY_NO_TZ
9b3a7c
-#define PyCOND_GETTIMEOFDAY(ptv) gettimeofday(ptv)
9b3a7c
-#else
9b3a7c
-#define PyCOND_GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL)
9b3a7c
-#endif
9b3a7c
-
9b3a7c
 /* The following functions return 0 on success, nonzero on error */
9b3a7c
 #define PyMUTEX_T pthread_mutex_t
9b3a7c
 #define PyMUTEX_INIT(mut)       pthread_mutex_init((mut), NULL)
9b3a7c
@@ -81,32 +67,30 @@ do { /* TODO: add overflow and truncation checks */ \
9b3a7c
 #define PyMUTEX_UNLOCK(mut)     pthread_mutex_unlock(mut)
9b3a7c
 
9b3a7c
 #define PyCOND_T pthread_cond_t
9b3a7c
-#define PyCOND_INIT(cond)       pthread_cond_init((cond), NULL)
9b3a7c
+#define PyCOND_INIT(cond)       _PyThread_cond_init(cond)
9b3a7c
 #define PyCOND_FINI(cond)       pthread_cond_destroy(cond)
9b3a7c
 #define PyCOND_SIGNAL(cond)     pthread_cond_signal(cond)
9b3a7c
 #define PyCOND_BROADCAST(cond)  pthread_cond_broadcast(cond)
9b3a7c
 #define PyCOND_WAIT(cond, mut)  pthread_cond_wait((cond), (mut))
9b3a7c
 
9b3a7c
+/* These private functions are implemented in Python/thread_pthread.h */
9b3a7c
+int _PyThread_cond_init(PyCOND_T *cond);
9b3a7c
+void _PyThread_cond_after(long long us, struct timespec *abs);
9b3a7c
+
9b3a7c
 /* return 0 for success, 1 on timeout, -1 on error */
9b3a7c
 Py_LOCAL_INLINE(int)
9b3a7c
 PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us)
9b3a7c
 {
9b3a7c
-    int r;
9b3a7c
-    struct timespec ts;
9b3a7c
-    struct timeval deadline;
9b3a7c
-
9b3a7c
-    PyCOND_GETTIMEOFDAY(&deadline);
9b3a7c
-    PyCOND_ADD_MICROSECONDS(deadline, us);
9b3a7c
-    ts.tv_sec = deadline.tv_sec;
9b3a7c
-    ts.tv_nsec = deadline.tv_usec * 1000;
9b3a7c
-
9b3a7c
-    r = pthread_cond_timedwait((cond), (mut), &ts);
9b3a7c
-    if (r == ETIMEDOUT)
9b3a7c
+    struct timespec abs;
9b3a7c
+    _PyThread_cond_after(us, &abs;;
9b3a7c
+    int ret = pthread_cond_timedwait(cond, mut, &abs;;
9b3a7c
+    if (ret == ETIMEDOUT) {
9b3a7c
         return 1;
9b3a7c
-    else if (r)
9b3a7c
+    }
9b3a7c
+    if (ret) {
9b3a7c
         return -1;
9b3a7c
-    else
9b3a7c
-        return 0;
9b3a7c
+    }
9b3a7c
+    return 0;
9b3a7c
 }
9b3a7c
 
9b3a7c
 #elif defined(NT_THREADS)
9b3a7c
diff --git a/Python/thread.c b/Python/thread.c
9b3a7c
index 63eeb1e..c5d0e59 100644
9b3a7c
--- a/Python/thread.c
9b3a7c
+++ b/Python/thread.c
9b3a7c
@@ -6,6 +6,7 @@
9b3a7c
    Stuff shared by all thread_*.h files is collected here. */
9b3a7c
 
9b3a7c
 #include "Python.h"
9b3a7c
+#include "condvar.h"
9b3a7c
 
9b3a7c
 #ifndef _POSIX_THREADS
9b3a7c
 /* This means pthreads are not implemented in libc headers, hence the macro
9b3a7c
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
9b3a7c
index baea71f..7dc295e 100644
9b3a7c
--- a/Python/thread_pthread.h
9b3a7c
+++ b/Python/thread_pthread.h
9b3a7c
@@ -66,16 +66,6 @@
9b3a7c
 #endif
9b3a7c
 #endif
9b3a7c
 
9b3a7c
-#if !defined(pthread_attr_default)
9b3a7c
-#  define pthread_attr_default ((pthread_attr_t *)NULL)
9b3a7c
-#endif
9b3a7c
-#if !defined(pthread_mutexattr_default)
9b3a7c
-#  define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
9b3a7c
-#endif
9b3a7c
-#if !defined(pthread_condattr_default)
9b3a7c
-#  define pthread_condattr_default ((pthread_condattr_t *)NULL)
9b3a7c
-#endif
9b3a7c
-
9b3a7c
 
9b3a7c
 /* Whether or not to use semaphores directly rather than emulating them with
9b3a7c
  * mutexes and condition variables:
9b3a7c
@@ -120,6 +110,56 @@ do { \
9b3a7c
 } while(0)
9b3a7c
 
9b3a7c
 
9b3a7c
+/*
9b3a7c
+ * pthread_cond support
9b3a7c
+ */
9b3a7c
+
9b3a7c
+#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
9b3a7c
+// monotonic is supported statically.  It doesn't mean it works on runtime.
9b3a7c
+#define CONDATTR_MONOTONIC
9b3a7c
+#endif
9b3a7c
+
9b3a7c
+// NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported.
9b3a7c
+static pthread_condattr_t *condattr_monotonic = NULL;
9b3a7c
+
9b3a7c
+static void
9b3a7c
+init_condattr()
9b3a7c
+{
9b3a7c
+#ifdef CONDATTR_MONOTONIC
9b3a7c
+    static pthread_condattr_t ca;
9b3a7c
+    pthread_condattr_init(&ca);
9b3a7c
+    if (pthread_condattr_setclock(&ca, CLOCK_MONOTONIC) == 0) {
9b3a7c
+        condattr_monotonic = &ca;  // Use monotonic clock
9b3a7c
+    }
9b3a7c
+#endif
9b3a7c
+}
9b3a7c
+
9b3a7c
+int
9b3a7c
+_PyThread_cond_init(PyCOND_T *cond)
9b3a7c
+{
9b3a7c
+    return pthread_cond_init(cond, condattr_monotonic);
9b3a7c
+}
9b3a7c
+
9b3a7c
+void
9b3a7c
+_PyThread_cond_after(long long us, struct timespec *abs)
9b3a7c
+{
9b3a7c
+#ifdef CONDATTR_MONOTONIC
9b3a7c
+    if (condattr_monotonic) {
9b3a7c
+        clock_gettime(CLOCK_MONOTONIC, abs);
9b3a7c
+        abs->tv_sec  += us / 1000000;
9b3a7c
+        abs->tv_nsec += (us % 1000000) * 1000;
9b3a7c
+        abs->tv_sec  += abs->tv_nsec / 1000000000;
9b3a7c
+        abs->tv_nsec %= 1000000000;
9b3a7c
+        return;
9b3a7c
+    }
9b3a7c
+#endif
9b3a7c
+
9b3a7c
+    struct timespec ts;
9b3a7c
+    MICROSECONDS_TO_TIMESPEC(us, ts);
9b3a7c
+    *abs = ts;
9b3a7c
+}
9b3a7c
+
9b3a7c
+
9b3a7c
 /* A pthread mutex isn't sufficient to model the Python lock type
9b3a7c
  * because, according to Draft 5 of the docs (P1003.4a/D5), both of the
9b3a7c
  * following are undefined:
9b3a7c
@@ -175,6 +215,7 @@ PyThread__init_thread(void)
9b3a7c
     extern void pthread_init(void);
9b3a7c
     pthread_init();
9b3a7c
 #endif
9b3a7c
+    init_condattr();
9b3a7c
 }
9b3a7c
 
9b3a7c
 #endif /* !_HAVE_BSDI */
9b3a7c
@@ -449,8 +490,7 @@ PyThread_allocate_lock(void)
9b3a7c
         memset((void *)lock, '\0', sizeof(pthread_lock));
9b3a7c
         lock->locked = 0;
9b3a7c
 
9b3a7c
-        status = pthread_mutex_init(&lock->mut,
9b3a7c
-                                    pthread_mutexattr_default);
9b3a7c
+        status = pthread_mutex_init(&lock->mut, NULL);
9b3a7c
         CHECK_STATUS_PTHREAD("pthread_mutex_init");
9b3a7c
         /* Mark the pthread mutex underlying a Python mutex as
9b3a7c
            pure happens-before.  We can't simply mark the
9b3a7c
@@ -459,8 +499,7 @@ PyThread_allocate_lock(void)
9b3a7c
            will cause errors. */
9b3a7c
         _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut);
9b3a7c
 
9b3a7c
-        status = pthread_cond_init(&lock->lock_released,
9b3a7c
-                                   pthread_condattr_default);
9b3a7c
+        status = _PyThread_cond_init(&lock->lock_released);
9b3a7c
         CHECK_STATUS_PTHREAD("pthread_cond_init");
9b3a7c
 
9b3a7c
         if (error) {
9b3a7c
@@ -519,9 +558,10 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
9b3a7c
             success = PY_LOCK_ACQUIRED;
9b3a7c
         }
9b3a7c
         else if (microseconds != 0) {
9b3a7c
-            struct timespec ts;
9b3a7c
-            if (microseconds > 0)
9b3a7c
-                MICROSECONDS_TO_TIMESPEC(microseconds, ts);
9b3a7c
+            struct timespec abs;
9b3a7c
+            if (microseconds > 0) {
9b3a7c
+                _PyThread_cond_after(microseconds, &abs;;
9b3a7c
+            }
9b3a7c
             /* continue trying until we get the lock */
9b3a7c
 
9b3a7c
             /* mut must be locked by me -- part of the condition
9b3a7c
@@ -530,10 +570,13 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
9b3a7c
                 if (microseconds > 0) {
9b3a7c
                     status = pthread_cond_timedwait(
9b3a7c
                         &thelock->lock_released,
9b3a7c
-                        &thelock->mut, &ts);
9b3a7c
+                        &thelock->mut, &abs;;
9b3a7c
+                    if (status == 1) {
9b3a7c
+                        break;
9b3a7c
+                    }
9b3a7c
                     if (status == ETIMEDOUT)
9b3a7c
                         break;
9b3a7c
-                    CHECK_STATUS_PTHREAD("pthread_cond_timed_wait");
9b3a7c
+                    CHECK_STATUS_PTHREAD("pthread_cond_timedwait");
9b3a7c
                 }
9b3a7c
                 else {
9b3a7c
                     status = pthread_cond_wait(
9b3a7c
diff --git a/configure.ac b/configure.ac
9b3a7c
index a0e3613..8a17559 100644
9b3a7c
--- a/configure.ac
9b3a7c
+++ b/configure.ac
9b3a7c
@@ -3582,7 +3582,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
9b3a7c
  memrchr mbrtowc mkdirat mkfifo \
9b3a7c
  mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \
9b3a7c
  posix_fallocate posix_fadvise pread \
9b3a7c
- pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \
9b3a7c
+ pthread_condattr_setclock pthread_init pthread_kill putenv pwrite readlink readlinkat readv realpath renameat \
9b3a7c
  select sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \
9b3a7c
  setgid sethostname \
9b3a7c
  setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setpriority setuid setvbuf \