From 19c6f1ee92cf6514e885def44f7deb9d225de4dc Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 7 Oct 2008 02:57:59 -0700 Subject: directory: serialize song deletes from playlist during update This makes the update code thread-safe and doesn't penalize the playlist code by complicating it with complicated and error-prone locks (and the associated overhead, not everybody has a thread-implementation as good as NPTL). The update task blocks during the delete; but the update task is a slow task anyways so we can block w/o people caring too much. This was also our only freeSong call site, so remove that function. Note that deleting entire directories is not fully thread-safe, yet; as their traversals are not yet locked. --- src/directory.c | 30 +++++++++++++++++++++++++++--- src/song.c | 6 ------ src/song.h | 2 -- 3 files changed, 27 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/directory.c b/src/directory.c index a11d01d25..9613bbfbd 100644 --- a/src/directory.c +++ b/src/directory.c @@ -63,8 +63,13 @@ static time_t directory_dbModTime; static pthread_t update_thr; static const int update_task_id_max = 1 << 15; + static int update_task_id; +static Song *delete; + +static struct condition delete_cond; + static int addToDirectory(Directory * directory, const char *name); static void freeDirectory(Directory * directory); @@ -144,6 +149,16 @@ void reap_update_task(void) assert(pthread_equal(pthread_self(), main_task)); + cond_enter(&delete_cond); + if (delete) { + char tmp[MPD_PATH_MAX]; + LOG("removing: %s\n", get_song_url(tmp, delete)); + deleteASongFromPlaylist(delete); + delete = NULL; + cond_signal(&delete_cond); + } + cond_leave(&delete_cond); + if (progress != UPDATE_PROGRESS_DONE) return; if (pthread_join(update_thr, (void **)&ret)) @@ -215,10 +230,19 @@ static void freeDirectory(Directory * directory) static void delete_song(Directory *dir, Song *del) { - char path_max_tmp[MPD_PATH_MAX]; /* wasteful */ - LOG("removing: %s\n", get_song_url(path_max_tmp, del)); + /* first, prevent traversers in main task from getting this */ songvec_delete(&dir->songs, del); - freeSong(del); /* FIXME racy */ + + /* now take it out of the playlist (in the main_task) */ + cond_enter(&delete_cond); + assert(!delete); + delete = del; + wakeup_main_task(); + do { cond_wait(&delete_cond); } while (delete); + cond_leave(&delete_cond); + + /* finally, all possible references gone, free it */ + freeJustSong(del); } static void deleteEmptyDirectoriesInDirectory(Directory * directory) diff --git a/src/song.c b/src/song.c index f967e3e17..c9301386d 100644 --- a/src/song.c +++ b/src/song.c @@ -79,12 +79,6 @@ Song *newSong(const char *url, Directory * parentDir) return song; } -void freeSong(Song * song) -{ - deleteASongFromPlaylist(song); - freeJustSong(song); -} - void freeJustSong(Song * song) { if (song->tag) diff --git a/src/song.h b/src/song.h index d8189d42c..9aa9efa94 100644 --- a/src/song.h +++ b/src/song.h @@ -42,8 +42,6 @@ typedef struct _Song { Song *newSong(const char *url, struct _Directory *parentDir); -void freeSong(Song *); - void freeJustSong(Song *); ssize_t song_print_info(Song * song, int fd); -- cgit v1.2.3