commit c2d9f1413c7a5888f320954c4fbcbb093275a9ca
parent 5f0153ba0ec083176aa5ec77da407a643f57d77a
Author: Joris Vink <joris@coders.se>
Date: Wed, 29 May 2019 15:25:31 +0200
Fix two concurrency issues with kore.lock().
1) If a coroutine was waken up by another releasing a lock it was waiting
on we would incorrectly remove the pylock_op when the newly awoken coroutine
hits the iternext for pylock.
2) If a coroutine attempts to grab a lock it was woken up for only to fail
we did not properly rearm the coroutine to be woken up later to try again.
Diffstat:
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/python.c b/src/python.c
@@ -2682,6 +2682,7 @@ pylock_do_release(struct pylock *lock)
if (op->locking == 0)
continue;
+ op->active = 0;
TAILQ_REMOVE(&op->lock->ops, op, list);
if (op->coro->request != NULL)
@@ -2689,7 +2690,6 @@ pylock_do_release(struct pylock *lock)
else
python_coro_wakeup(op->coro);
- op->active = 0;
Py_DECREF((PyObject *)op);
break;
}
@@ -2733,14 +2733,27 @@ pylock_op_iternext(struct pylock_op *op)
pylock_do_release(op->lock);
} else {
if (op->lock->owner != NULL) {
+ /*
+ * We could be beat by another coroutine that grabbed
+ * the lock even if we were the one woken up for it.
+ */
+ if (op->active == 0) {
+ op->active = 1;
+ TAILQ_INSERT_HEAD(&op->lock->ops, op, list);
+ Py_INCREF((PyObject *)op);
+ }
Py_RETURN_NONE;
}
op->lock->owner = coro_running;
}
- op->active = 0;
- TAILQ_REMOVE(&op->lock->ops, op, list);
+ if (op->active) {
+ op->active = 0;
+ TAILQ_REMOVE(&op->lock->ops, op, list);
+ Py_DECREF((PyObject *)op);
+ }
+
PyErr_SetNone(PyExc_StopIteration);
return (NULL);