kore

a fork of the worlds most advanced web framework
Log | Files | Refs | README | LICENSE

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:
Msrc/python.c | 19++++++++++++++++---
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);