[SCM] libgroove/upstream: playlist: fix race condition which can cause decoder to hang

andrewrk-guest at users.alioth.debian.org andrewrk-guest at users.alioth.debian.org
Fri Jun 20 21:56:18 UTC 2014


The following commit has been merged in the upstream branch:
commit 7c29310c51829be94f54c8d6de51fa390ab075db
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Mon Jun 16 14:56:09 2014 -0700

    playlist: fix race condition which can cause decoder to hang

diff --git a/groove/playlist.c b/groove/playlist.c
index ec07b1c..0230d03 100644
--- a/groove/playlist.c
+++ b/groove/playlist.c
@@ -61,16 +61,19 @@ struct GroovePlaylistPrivate {
     AVFilter *aformat_filter;
     AVFilter *abuffersink_filter;
 
+    pthread_mutex_t drain_cond_mutex;
+    int drain_cond_mutex_inited;
+
     // this mutex applies to the variables in this block
     pthread_mutex_t decode_head_mutex;
-    char decode_head_mutex_inited;
+    int decode_head_mutex_inited;
     // decode_thread waits on this cond when the decode_head is NULL
     pthread_cond_t decode_head_cond;
-    char decode_head_cond_inited;
+    int decode_head_cond_inited;
     // decode_thread waits on this cond when every sink is full
     // should also signal when the first sink is attached.
     pthread_cond_t sink_drain_cond;
-    char sink_drain_cond_inited;
+    int sink_drain_cond_inited;
     // pointer to current playlist item being decoded
     struct GroovePlaylistItem *decode_head;
     // desired volume for the volume filter
@@ -618,8 +621,11 @@ static void audioq_get(struct GrooveQueue *queue, void *obj) {
 
     struct GroovePlaylist *playlist = sink->playlist;
     struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist;
-    if (s->audioq_size < s->min_audioq_size)
+    if (s->audioq_size < s->min_audioq_size) {
+        pthread_mutex_lock(&p->drain_cond_mutex);
         pthread_cond_signal(&p->sink_drain_cond);
+        pthread_mutex_unlock(&p->drain_cond_mutex);
+    }
 }
 
 static void audioq_cleanup(struct GrooveQueue *queue, void *obj) {
@@ -675,15 +681,18 @@ static void *decode_thread(void *arg) {
         struct GrooveFile *file = p->decode_head->file;
         struct GrooveFilePrivate *f = (struct GrooveFilePrivate *) file;
 
+        pthread_mutex_lock(&p->drain_cond_mutex);
         if (p->detect_full_sinks(playlist) && (f->seek_pos < 0 || !f->seek_flush)) {
             if (!f->paused) {
                 av_read_pause(f->ic);
                 f->paused = 1;
             }
-            pthread_cond_wait(&p->sink_drain_cond, &p->decode_head_mutex);
             pthread_mutex_unlock(&p->decode_head_mutex);
+            pthread_cond_wait(&p->sink_drain_cond, &p->drain_cond_mutex);
+            pthread_mutex_unlock(&p->drain_cond_mutex);
             continue;
         }
+        pthread_mutex_unlock(&p->drain_cond_mutex);
         if (f->paused) {
             av_read_play(f->ic);
             f->paused = 0;
@@ -879,7 +888,9 @@ int groove_sink_attach(struct GrooveSink *sink, struct GroovePlaylist *playlist)
 
     pthread_mutex_lock(&p->decode_head_mutex);
     int err = add_sink_to_map(playlist, sink);
+    pthread_mutex_lock(&p->drain_cond_mutex);
     pthread_cond_signal(&p->sink_drain_cond);
+    pthread_mutex_unlock(&p->drain_cond_mutex);
     pthread_mutex_unlock(&p->decode_head_mutex);
 
     if (err < 0) {
@@ -936,11 +947,18 @@ struct GroovePlaylist * groove_playlist_create(void) {
 
     if (pthread_mutex_init(&p->decode_head_mutex, NULL) != 0) {
         groove_playlist_destroy(playlist);
-        av_log(NULL, AV_LOG_ERROR, "unable to allocate mutex\n");
+        av_log(NULL, AV_LOG_ERROR, "unable to allocate decode head mutex\n");
         return NULL;
     }
     p->decode_head_mutex_inited = 1;
 
+    if (pthread_mutex_init(&p->drain_cond_mutex, NULL) != 0) {
+        groove_playlist_destroy(playlist);
+        av_log(NULL, AV_LOG_ERROR, "unable to allocate drain cond mutex\n");
+        return NULL;
+    }
+    p->drain_cond_mutex_inited = 1;
+
     if (pthread_cond_init(&p->decode_head_cond, NULL) != 0) {
         groove_playlist_destroy(playlist);
         av_log(NULL, AV_LOG_ERROR, "unable to allocate decode head mutex condition\n");
@@ -1033,6 +1051,9 @@ void groove_playlist_destroy(struct GroovePlaylist *playlist) {
     if (p->decode_head_mutex_inited)
         pthread_mutex_destroy(&p->decode_head_mutex);
 
+    if (p->drain_cond_mutex_inited)
+        pthread_mutex_destroy(&p->drain_cond_mutex);
+
     if (p->decode_head_cond_inited)
         pthread_cond_destroy(&p->decode_head_cond);
 
@@ -1174,7 +1195,9 @@ void groove_playlist_remove(struct GroovePlaylist *playlist, struct GroovePlayli
     every_sink(playlist, purge_sink, 0);
     p->purge_item = NULL;
 
+    pthread_mutex_lock(&p->drain_cond_mutex);
     pthread_cond_signal(&p->sink_drain_cond);
+    pthread_mutex_unlock(&p->drain_cond_mutex);
     pthread_mutex_unlock(&p->decode_head_mutex);
 
     av_free(item);

-- 
libgroove packaging



More information about the pkg-multimedia-commits mailing list