diff options
author | Eric Wong <normalperson@yhbt.net> | 2008-10-07 22:11:16 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-10-07 22:11:16 +0200 |
commit | 7d8c9cc7e31e15b93af7c08f7d03ed8ca10f5454 (patch) | |
tree | d492791706dbf323eec84c2331308bf61566af82 /src/directory.c | |
parent | 2b965a5424b9e15f23794c0667c7eff95759dbb5 (diff) | |
download | mpd-7d8c9cc7e31e15b93af7c08f7d03ed8ca10f5454.tar.gz mpd-7d8c9cc7e31e15b93af7c08f7d03ed8ca10f5454.tar.xz mpd-7d8c9cc7e31e15b93af7c08f7d03ed8ca10f5454.zip |
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.
Diffstat (limited to '')
-rw-r--r-- | src/directory.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/src/directory.c b/src/directory.c index fb8c23e2f..949d249a4 100644 --- a/src/directory.c +++ b/src/directory.c @@ -31,6 +31,7 @@ #include "song_save.h" #include "main_notify.h" #include "dirvec.h" +#include "condition.h" #define DIRECTORY_DIR "directory: " #define DIRECTORY_MTIME "mtime: " /* DEPRECATED, noop-read-only */ @@ -64,8 +65,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 enum update_return addToDirectory(Directory * directory, const char *name); @@ -146,6 +152,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_async(&delete_cond); + } + cond_leave(&delete_cond); + if (progress != UPDATE_PROGRESS_DONE) return; if (pthread_join(update_thr, (void **)&ret)) @@ -217,10 +233,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) |