aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2008-10-12 00:23:38 -0700
committerEric Wong <normalperson@yhbt.net>2008-10-12 05:27:33 -0700
commit6ad5891f2c57bca861d51160cbfa54f172fa1ea5 (patch)
tree7090ab8d6d46f7f5636b344adb07b9806bb1c0a6
parentf58827951ff79539125dcb4b1bd08e549e347a62 (diff)
downloadmpd-6ad5891f2c57bca861d51160cbfa54f172fa1ea5.tar.gz
mpd-6ad5891f2c57bca861d51160cbfa54f172fa1ea5.tar.xz
mpd-6ad5891f2c57bca861d51160cbfa54f172fa1ea5.zip
update: serialize directory deletions
We only delete directory object in the main thread to prevent access to individual elements (mainly path).
-rw-r--r--src/update.c39
1 files changed, 28 insertions, 11 deletions
diff --git a/src/update.c b/src/update.c
index c3e5b9a7c..b244c3a3b 100644
--- a/src/update.c
+++ b/src/update.c
@@ -46,7 +46,11 @@ static const unsigned update_task_id_max = 1 << 15;
static unsigned update_task_id;
-static struct mpd_song *delete;
+enum update_type { UPDATE_TYPE_SONG, UPDATE_TYPE_DIR };
+
+static enum update_type delete_type;
+
+static void *delete;
static struct condition delete_cond;
@@ -62,20 +66,26 @@ static void directory_set_stat(struct directory *dir, const struct stat *st)
dir->stat = 1;
}
-static void delete_song(struct directory *dir, struct mpd_song *del)
+static void serialized_delete(void *del, enum update_type type)
{
- /* first, prevent traversers in main task from getting this */
- songvec_delete(&dir->songs, del);
-
- /* now take it out of the playlist (in the main_task) */
cond_enter(&delete_cond);
assert(!delete);
+ delete_type = type;
delete = del;
wakeup_main_task();
do { cond_wait(&delete_cond); } while (delete);
cond_leave(&delete_cond);
}
+static void delete_song(struct directory *dir, struct mpd_song *del)
+{
+ /* first, prevent traversers in main task from getting this */
+ songvec_delete(&dir->songs, del);
+
+ /* now take it out of the playlist (in the main_task) and free */
+ serialized_delete(del, UPDATE_TYPE_SONG);
+}
+
static int delete_each_song(struct mpd_song *song, mpd_unused void *data)
{
struct directory *dir = data;
@@ -105,7 +115,7 @@ static void delete_directory(struct directory *dir)
clear_directory(dir, NULL);
dirvec_delete(&dir->parent->children, dir);
- directory_free(dir);
+ serialized_delete(dir, UPDATE_TYPE_DIR);
}
struct delete_data {
@@ -417,10 +427,17 @@ void reap_update_task(void)
cond_enter(&delete_cond);
if (delete) {
- char tmp[MPD_PATH_MAX];
- LOG("removing: %s\n", song_get_url(delete, tmp));
- deleteASongFromPlaylist(delete);
- song_free(delete);
+ switch (delete_type) {
+ case UPDATE_TYPE_SONG: {
+ char tmp[MPD_PATH_MAX];
+ LOG("removing: %s\n", song_get_url(delete, tmp));
+ deleteASongFromPlaylist(delete);
+ song_free(delete);
+ }
+ break;
+ case UPDATE_TYPE_DIR:
+ directory_free(delete);
+ }
delete = NULL;
cond_signal(&delete_cond);
}