diff options
author | Eric Wong <normalperson@yhbt.net> | 2008-10-12 05:28:25 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2008-10-12 05:29:27 -0700 |
commit | 7278e3b2ee49a853b01dc6532bd7067a264f235d (patch) | |
tree | 28e83de310f0c58df226e253a82b0d43ff784497 /src/update.c | |
parent | c87ce02575e0a9d5ac3e50938688187ea28ad400 (diff) | |
parent | c7579ca2d8422f0172537e1ca7d1bd46edfc4f9d (diff) | |
download | mpd-7278e3b2ee49a853b01dc6532bd7067a264f235d.tar.gz mpd-7278e3b2ee49a853b01dc6532bd7067a264f235d.tar.xz mpd-7278e3b2ee49a853b01dc6532bd7067a264f235d.zip |
Merge branch 'ew/directory'
* ew/directory: (21 commits)
update: fix multiple deletes from *vec iterators
directory: children leave parents before being free()ed
directory: always maintain sorted properties vectors
update: simplify the serialized_delete usage a bit
update: remove delete_each_song and clear_directory
directory: directory_free kills all that it contains
update: serialize directory deletions
update: serialize song_free in main thread
dirvec: introduce locking for all iterators
dirvec: use dirvec_for_each where it makes sense
dirvec: add dirvec_for_each iterator
songvec: avoid holding nr_lock during free(3)
update: allow music_root updates to be queued
update: validate in command.c and fix small memory leak
directory: rename isRootDirectory => path_is_music_root
Avoid calling isRootDirectory when we have a directory object
directory: make music_root global and avoid runtime initialization
directory: use mpd_sizeof_str_flex_array for path, too
tag_item: avoid wasting space when struct is unpackable
song: use mpd_sizeof_str_flex_array for song.url
...
[ew: fixed up merge errors with myself when isRootDirectory
went away]
Diffstat (limited to 'src/update.c')
-rw-r--r-- | src/update.c | 107 |
1 files changed, 52 insertions, 55 deletions
diff --git a/src/update.c b/src/update.c index ca3640b73..9ede72759 100644 --- a/src/update.c +++ b/src/update.c @@ -46,7 +46,9 @@ static const unsigned update_task_id_max = 1 << 15; static unsigned update_task_id; -static struct mpd_song *delete; +static void (*delete_fn)(void *); + +static void *delete; static struct condition delete_cond; @@ -62,44 +64,33 @@ 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 (*fn)(void *), void *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) */ cond_enter(&delete_cond); assert(!delete); + assert(!delete_fn); + delete_fn = fn; delete = del; wakeup_main_task(); do { cond_wait(&delete_cond); } while (delete); cond_leave(&delete_cond); - - /* finally, all possible references gone, free it */ - song_free(del); } -static int delete_each_song(struct mpd_song *song, mpd_unused void *data) +static void delete_song_safely(struct mpd_song *song) { - struct directory *dir = data; - assert(song->parent == dir); - delete_song(dir, song); - return 0; + char tmp[MPD_PATH_MAX]; + LOG("removing: %s\n", song_get_url(song, tmp)); + deleteASongFromPlaylist(song); + song_free(song); } -/** - * Recursively remove all sub directories and songs from a directory, - * leaving an empty directory. - */ -static void clear_directory(struct directory *dir) +static void delete_song(struct directory *dir, struct mpd_song *del) { - int i; - - for (i = dir->children.nr; --i >= 0;) - clear_directory(dir->children.base[i]); - dirvec_clear(&dir->children); + /* first, prevent traversers in main task from getting this */ + songvec_delete(&dir->songs, del); - songvec_for_each(&dir->songs, delete_each_song, dir); + /* now take it out of the playlist (in the main_task) and free */ + serialized_delete((void (*)(void *))delete_song_safely, del); } /** @@ -109,9 +100,11 @@ static void delete_directory(struct directory *dir) { assert(dir->parent != NULL); - clear_directory(dir); + /* first, prevent traversers in main task from getting this */ dirvec_delete(&dir->parent->children, dir); - directory_free(dir); + + /* now we let the main task recursively delete everything under us */ + serialized_delete((void (*)(void *))directory_free, dir); } struct delete_data { @@ -149,23 +142,27 @@ static void delete_path(const char *path) } } -static void -removeDeletedFromDirectory(char *path_max_tmp, struct directory *dir) +/* passed to dirvec_for_each */ +static int delete_directory_if_removed(struct directory *dir, void *_data) { - int i; - struct dirvec *dv = &dir->children; - struct delete_data data; + if (!isDir(dir->path)) { + struct delete_data *data = _data; - for (i = dv->nr; --i >= 0; ) { - if (isDir(dv->base[i]->path)) - continue; - LOG("removing directory: %s\n", dv->base[i]->path); - dirvec_delete(dv, dv->base[i]); + LOG("removing directory: %s\n", directory_get_path(dir)); + dirvec_delete(&data->dir->children, dir); modified = 1; } + return 0; +} + +static void +removeDeletedFromDirectory(char *path_max_tmp, struct directory *dir) +{ + struct delete_data data; data.dir = dir; data.tmp = path_max_tmp; + dirvec_for_each(&dir->children, delete_directory_if_removed, &data); songvec_for_each(&dir->songs, delete_song_if_removed, &data); } @@ -278,7 +275,7 @@ static int updateDirectory(struct directory *dir, const struct stat *st) if (!utf8) continue; - if (!isRootDirectory(dir->path)) + if (dir != &music_root) utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8), dirname, strlen(dirname)); @@ -317,10 +314,9 @@ directory_make_child_checked(struct directory *parent, const char *path) return dir; } -static struct directory * -addParentPathToDB(const char *utf8path) +static struct directory * addParentPathToDB(const char *utf8path) { - struct directory *dir = db_get_root(); + struct directory *dir = &music_root; char *duplicated = xstrdup(utf8path); char *slash = duplicated; @@ -350,15 +346,17 @@ static void updatePath(const char *utf8path) static void * update_task(void *_path) { - if (_path != NULL && !isRootDirectory(_path)) { - updatePath((char *)_path); - free(_path); + char *utf8path = _path; + + if (utf8path) { + assert(*utf8path); + updatePath(utf8path); + free(utf8path); } else { - struct directory *dir = db_get_root(); struct stat st; - if (myStat(directory_get_path(dir), &st) == 0) - updateDirectory(dir, &st); + if (myStat(directory_get_path(&music_root), &st) == 0) + updateDirectory(&music_root, &st); } if (modified) @@ -388,13 +386,14 @@ unsigned directory_update_init(char *path) { assert(pthread_equal(pthread_self(), main_task)); + assert(!path || (path && *path)); + if (progress != UPDATE_PROGRESS_IDLE) { unsigned next_task_id; - if (!path) - return 0; if (update_paths_nr == ARRAY_SIZE(update_paths)) { - free(path); + if (path) + free(path); return 0; } @@ -416,11 +415,9 @@ void reap_update_task(void) return; cond_enter(&delete_cond); - if (delete) { - char tmp[MPD_PATH_MAX]; - LOG("removing: %s\n", song_get_url(delete, tmp)); - deleteASongFromPlaylist(delete); - delete = NULL; + if (delete && delete_fn) { + delete_fn(delete); + delete = delete_fn = NULL; cond_signal(&delete_cond); } cond_leave(&delete_cond); |