dispatch: fix broken locking

mp_dispatch_queue_process() releases the queue->lock mutex while
processing a dispatch callback. But this allowed mp_dispatch_lock() to
grab the "logical" lock represented by queue->locked. Grabbing the
logical lock is not a problem in itself, but it can't be allowed to
happen while the callback is still running.

Fix this by claiming the logical lock while the dispatch callback is
processed. Also make sure that the thread calling mp_dispatch_lock() is
woken up properly.

Fortunately, this didn't matter, because the locking function is unused.
This commit is contained in:
wm4 2014-04-23 20:40:20 +02:00
parent ff4028f3bf
commit ed7e7e2eb4
1 changed files with 7 additions and 0 deletions

View File

@ -28,6 +28,7 @@ struct mp_dispatch_queue {
pthread_mutex_t lock;
pthread_cond_t cond;
int suspend_requested;
int lock_requested;
bool suspended;
bool locked;
void (*wakeup_fn)(void *wakeup_ctx);
@ -173,9 +174,11 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout)
item->next = NULL;
// Unlock, because we want to allow other threads to queue items
// while the dispatch item is processed.
queue->locked = true;
pthread_mutex_unlock(&queue->lock);
item->fn(item->fn_data);
pthread_mutex_lock(&queue->lock);
queue->locked = false;
if (item->asynchronous) {
talloc_free(item);
} else {
@ -184,6 +187,8 @@ void mp_dispatch_queue_process(struct mp_dispatch_queue *queue, double timeout)
pthread_cond_broadcast(&queue->cond);
}
} else {
if (!queue->locked && queue->lock_requested)
pthread_cond_broadcast(&queue->cond);
pthread_cond_wait(&queue->cond, &queue->lock);
}
}
@ -235,6 +240,7 @@ void mp_dispatch_lock(struct mp_dispatch_queue *queue)
// dispatch items to guarantee minimum fairness.
pthread_mutex_lock(&queue->lock);
queue->suspend_requested++;
queue->lock_requested++;
while (1) {
if (queue->suspended && !queue->locked) {
queue->locked = true;
@ -250,6 +256,7 @@ void mp_dispatch_lock(struct mp_dispatch_queue *queue)
}
pthread_cond_wait(&queue->cond, &queue->lock);
}
queue->lock_requested--;
pthread_mutex_unlock(&queue->lock);
}