summaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-04-23 20:40:20 +0200
committerwm4 <wm4@nowhere>2014-04-23 21:16:52 +0200
commited7e7e2eb407031b3ba79bf485c1cdd34b7a2baf (patch)
tree22175f4cda6e4a5e5a7d18d2b15588fda71f5ee1 /misc
parentff4028f3bf0c241c835d527ddc7cb8aa779f849c (diff)
downloadmpv-ed7e7e2eb407031b3ba79bf485c1cdd34b7a2baf.tar.bz2
mpv-ed7e7e2eb407031b3ba79bf485c1cdd34b7a2baf.tar.xz
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.
Diffstat (limited to 'misc')
-rw-r--r--misc/dispatch.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/misc/dispatch.c b/misc/dispatch.c
index 07f8995628..e64dc425cd 100644
--- a/misc/dispatch.c
+++ b/misc/dispatch.c
@@ -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);
}