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.
This commit is contained in:
Joris Vink 2019-05-29 15:25:31 +02:00
parent 5f0153ba0e
commit c2d9f1413c
1 changed files with 16 additions and 3 deletions

View File

@ -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);