X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=plm_dbtool.c;h=3b551fcd5e36ab68e227a0364e1fa6e9b3fc877c;hp=fd18f254ac03c5c711642f26e75e5d225e2119d8;hb=7533926d69875da66c5dc45940f67cb5d659738e;hpb=8db6cb34ef06dff8aaf6f4fa4189151216354c9a diff --git a/plm_dbtool.c b/plm_dbtool.c index fd18f254..3b551fcd 100644 --- a/plm_dbtool.c +++ b/plm_dbtool.c @@ -16,21 +16,50 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ -/** \file plm_dbtool.c Simple playlist manager for paraslash */ +/** \file plm_dbtool.c Playlist manager for paraslash */ -#include /* gettimeofday */ -#include "server.cmdline.h" #include "server.h" #include "db.h" #include "error.h" #include "net.h" #include "string.h" +#include "ipc.h" -#define MAX_PLAYLIST_LEN 10000 +/** + * structure used for transmission of the playlist + * + * There's one such struct which gets initialized during startup. It lives in + * shared memory and is used by com_lpl(). + */ +struct plm_client_data { +/** allocated and set by com_lpl() (child) */ + int shm_id; +/** the size of the shared memory area identified by \a shm_id */ + size_t size; +/** initially locked, gets unlocked by parent when it is done */ + int mutex; +/** return value, set by parent */ + int retval; +}; + +/** data specific to the plm database tool */ +struct private_plm_data { +/** guards against concurrent client access */ + int client_mutex; +/** guards against concurrent parent-child access */ + int server_mutex; +/** pointer to the client data */ + struct plm_client_data *client_data; +/** id of the shm corresponding to \a client_data */ + int client_data_shm_id; +}; + +/** we refuse to load playlists bigger than that */ #define MAX_PLAYLIST_BYTES (1024 * 1024) static unsigned playlist_len, playlist_size, current_playlist_entry; static char **playlist; +static struct dbtool *self; static int com_ppl(int, int, char **); static int com_lpl(int, int, char **); @@ -53,8 +82,8 @@ static struct server_command cmds[] = { .description = "load playlist", .synopsis = "lpl", .help = -"Read a new playlist from stdin" - +"Read a new playlist from stdin. Example:\n" +"\tfind /audio -name '*.mp3' | para_client lpl" }, { .name = NULL, } @@ -63,54 +92,95 @@ static struct server_command cmds[] = { static void playlist_add(char *path) { if (playlist_len >= playlist_size) { - if (playlist_size >= MAX_PLAYLIST_LEN) - return; - playlist_size *= 2; + playlist_size = 2 * playlist_size + 1; playlist = para_realloc(playlist, playlist_size * sizeof(char *)); } - PARA_DEBUG_LOG("adding #%d: %s\n", playlist_len, path); - playlist[playlist_len] = para_strdup(path); - playlist_len++; + PARA_DEBUG_LOG("adding #%d/%d: %s\n", playlist_len, playlist_size, path); + playlist[playlist_len++] = para_strdup(path); +} + +static int send_playlist_to_server(const char *buf, size_t size) +{ + struct private_plm_data *ppd = self->private_data; + int ret, shm_mutex = -1, shm_id = -1; + void *shm = NULL; + + PARA_DEBUG_LOG("new playlist (%d bytes)\n", size); + + ret = mutex_new(); + if (ret < 0) + return ret; + shm_mutex = ret; + + ret = shm_new(size); + if (ret < 0) + goto out; + shm_id = ret; + + ret = shm_attach(shm_id, ATTACH_RW, &shm); + if (ret < 0) + goto out; + mutex_lock(shm_mutex); + memcpy(shm, buf, size); + mutex_lock(ppd->client_mutex); + mutex_lock(ppd->server_mutex); + ppd->client_data->size = size; + ppd->client_data->shm_id = shm_id; + ppd->client_data->mutex = shm_mutex; + kill(getppid(), SIGUSR1); /* wake up the server */ + mutex_unlock(ppd->server_mutex); + mutex_lock(shm_mutex); /* wait until server is done */ + mutex_unlock(shm_mutex); + ret = ppd->client_data->retval; + mutex_unlock(ppd->client_mutex); + shm_detach(shm); +out: + if (shm_id >= 0) + shm_destroy(shm_id); + mutex_destroy(shm_mutex); + PARA_DEBUG_LOG("returning %d\n", ret); + return ret; } static int com_lpl(int fd, __unused int argc, __unused char *argv[]) { - unsigned i, loaded = 0; - char buf[_POSIX_PATH_MAX]; + unsigned loaded = 0; + size_t bufsize = 4096; /* guess that's enough */ + char *buf = para_malloc(bufsize); ssize_t ret; - - PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len); - for (i = 0; i < playlist_len; i++) - free(playlist[i]); - current_playlist_entry = 0; - playlist_len = 0; ret = send_buffer(fd, AWAITING_DATA_MSG); if (ret < 0) - return ret; + goto out; again: - ret = recv_bin_buffer(fd, buf + loaded, sizeof(buf) - loaded); + ret = recv_bin_buffer(fd, buf + loaded, bufsize - loaded); if (ret < 0) - goto err_out; + goto out; if (!ret) { - PARA_DEBUG_LOG("loaded playlist (%d entries)\n", playlist_len); - return playlist_len; + ret = send_playlist_to_server(buf, loaded); + goto out; } loaded += ret; - loaded = for_each_line(buf, loaded, &playlist_add, 0); - if (loaded >= sizeof(buf)) - goto err_out; + ret = -E_LOAD_PLAYLIST; + if (loaded >= MAX_PLAYLIST_BYTES) + goto out; + if (loaded >= bufsize) { + bufsize *= 2; + buf = para_realloc(buf, bufsize); + } goto again; -err_out: - return -E_LOAD_PLAYLIST; +out: + free(buf); + return ret; } static int com_ppl(int fd, __unused int argc, __unused char *argv[]) { unsigned i; - PARA_DEBUG_LOG("sending playlist (%d entries)\n", playlist_len); + PARA_DEBUG_LOG("sending playlist to client (%d entries)\n", playlist_len); for (i = 0; i < playlist_len; i++) { - int ret = send_buffer(fd, playlist[i]); + int ret = send_va_buffer(fd, "%s\n", playlist[ + (i + current_playlist_entry) % playlist_len]); if (ret < 0) return ret; } @@ -122,7 +192,6 @@ static char **plm_get_audio_file_list(unsigned int num) char **file_list; unsigned i; - return NULL; num = MIN(num, playlist_len); if (!num) return NULL; @@ -135,13 +204,74 @@ static char **plm_get_audio_file_list(unsigned int num) return file_list; } +static void free_playlist_contents(void) +{ + int i; + + PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len); + for (i = 0; i < playlist_len; i++) + free(playlist[i]); + current_playlist_entry = 0; + playlist_len = 0; +} + static void plm_shutdown(void) { - /* free the playlist */ + struct private_plm_data *ppd = self->private_data; + + shm_detach(ppd->client_data); + shm_destroy(ppd->client_data_shm_id); + mutex_destroy(ppd->server_mutex); + mutex_destroy(ppd->client_mutex); + free(ppd); + free_playlist_contents(); + free(playlist); + playlist = NULL; + playlist_len = 0; + playlist_size = 0; +} + +static void plm_post_select(__unused fd_set *rfds, __unused fd_set *wfds) +{ + struct private_plm_data *ppd = self->private_data; + struct plm_client_data *pcd = ppd->client_data; + int ret; + void *shm; + + mutex_lock(ppd->server_mutex); + if (!pcd->size) + goto out; + free_playlist_contents(); + ret = shm_attach(pcd->shm_id, ATTACH_RW, &shm); + if (ret < 0) { + PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); + goto out; + } + PARA_DEBUG_LOG("loading new playlist (%d bytes)\n", pcd->size); + ret = for_each_line((char *)shm, pcd->size, &playlist_add, 0); + shm_detach(shm); + PARA_NOTICE_LOG("new playlist (%d entries)\n", playlist_len); + pcd->retval = 1; + pcd->size = 0; + mutex_unlock(pcd->mutex); +out: + mutex_unlock(ppd->server_mutex); +} + +void plm_update_audio_file(char *audio_file) +{ + unsigned i; + + for (i = 0; i < playlist_len; i++) { + unsigned j = (current_playlist_entry + i) % playlist_len; + if (strcmp(playlist[j], audio_file)) + continue; + current_playlist_entry = (j + 1) % playlist_len; + } } /** - * the init function for the plm database tool + * the init function for the plm database tool * * Init all function pointers of \a db * @@ -149,11 +279,53 @@ static void plm_shutdown(void) */ int plm_dbtool_init(struct dbtool *db) { - playlist = para_calloc(100 * sizeof(char *)); /* guess 100 is enough */ - playlist_size = 100; - sprintf(mmd->dbinfo, "plm initialized"); + int ret; + struct private_plm_data *ppd = NULL; + void *shm = NULL; + + self = db; db->cmd_list = cmds; db->get_audio_file_list = plm_get_audio_file_list; db->shutdown = plm_shutdown; + db->post_select = plm_post_select; + db->update_audio_file = plm_update_audio_file; + ppd = para_calloc(sizeof(struct private_plm_data)); + db->private_data = ppd; + + ppd->client_mutex = -1; + ppd->server_mutex = -1; + ppd->client_data_shm_id = -1; + ppd->client_data = NULL; + + ret = mutex_new(); + if (ret < 0) + goto err_out; + ppd->client_mutex = ret; + + ret = mutex_new(); + if (ret < 0) + goto err_out; + ppd->server_mutex = ret; + + ret = shm_new(sizeof(struct plm_client_data)); + if (ret < 0) + goto err_out; + ppd->client_data_shm_id = ret; + + ret = shm_attach(ppd->client_data_shm_id, ATTACH_RW, &shm); + if (ret < 0) + goto err_out; + ppd->client_data = shm; + ppd->client_data->size = 0; + sprintf(mmd->dbinfo, "plm initialized"); return 1; +err_out: + if (ppd->client_data_shm_id >= 0) + shm_destroy(ppd->client_data_shm_id); + if (ppd->client_mutex >= 0) + mutex_destroy(ppd->client_mutex); + if (ppd->server_mutex >= 0) + mutex_destroy(ppd->server_mutex); + free(ppd); + return ret; }