1. Armin Rigo
  2. cpython-withatomic

Commits

Armin Rigo  committed 1be8e4b

Use the same solution as pypy-stm to handle atomic blocks that try to
acquire already-locked locks: just raise a _thread.error (in this case a
RuntimeError because it's Python 3). Must be added on a case-by-case
basis before PyThread_acquire_lock() when we still have the GIL.

  • Participants
  • Parent commits cd177e2
  • Branches stm-thread

Comments (0)

Files changed (4)

File Include/pythread.h

View file
 #define WAIT_LOCK	1
 #define NOWAIT_LOCK	0
 
+/* implemented in ceval_gil.h: raise an exception and returns -1 if
+   acquiring the lock would deadlock because we are in a "with atomic"
+   section. */
+PyAPI_FUNC(int) PyThread_check_lock_with_atomic(PyThread_type_lock);
+
 /* PY_TIMEOUT_T is the integral type used to specify timeouts when waiting
    on a lock (see PyThread_acquire_lock_timed() below).
    PY_TIMEOUT_MAX is the highest usable value (in microseconds) of that

File Modules/_io/bufferedio.c

View file
                      "reentrant call inside %R", self);
         return 0;
     }
+    if (PyThread_check_lock_with_atomic(self->lock))
+        return 0;
     Py_BEGIN_ALLOW_THREADS
     PyThread_acquire_lock(self->lock, 1);
     Py_END_ALLOW_THREADS

File Modules/_threadmodule.c

View file
     _PyTime_timeval endtime;
 
 
-    if (microseconds > 0) {
+    if (microseconds == -1) {
+        if (PyThread_check_lock_with_atomic(lock))
+            return PY_LOCK_INTR;
+    }
+    else if (microseconds > 0) {
         _PyTime_gettimeofday(&endtime);
         endtime.tv_sec += microseconds / (1000 * 1000);
         endtime.tv_usec += microseconds % (1000 * 1000);

File Python/ceval_gil.h

View file
 {
     return ts_withatomic;
 }
+
+int PyThread_check_lock_with_atomic(PyThread_type_lock lock)
+{
+    if (ts_withatomic == NULL)
+        return 0;
+    else {
+        PyLockStatus success = PyThread_acquire_lock(lock, NOWAIT_LOCK);
+        if (success == PY_LOCK_ACQUIRED) {
+            PyThread_release_lock(lock);
+            return 0;
+        }
+        else {
+            PyErr_SetString(PyExc_RuntimeError,
+                "deadlock: an atomic transaction tries to acquire "
+                "a lock that is already acquired");
+            return -1;
+        }
+    }
+}