diff --git a/src/cache.c b/src/cache.c index be77ab7f..845d967f 100644 --- a/src/cache.c +++ b/src/cache.c @@ -72,8 +72,6 @@ static pthread_t tid_cache; // Event base, pipes and events struct event_base *evbase_cache; -static int g_exit_pipe[2]; -static struct event *g_exitev; static struct event *g_cacheev; static struct commands_base *cmdbase; @@ -123,18 +121,6 @@ remove_tag(char *in, const char *tag) } -static void -thread_exit(void) -{ - int dummy = 42; - - DPRINTF(E_DBG, L_CACHE, "Killing cache thread\n"); - - if (write(g_exit_pipe[1], &dummy, sizeof(dummy)) != sizeof(dummy)) - DPRINTF(E_LOG, L_CACHE, "Could not write to exit fd: %s\n", strerror(errno)); -} - - /* --------------------------------- MAIN --------------------------------- */ /* Thread: cache */ @@ -1316,23 +1302,6 @@ cache(void *arg) pthread_exit(NULL); } -static void -exit_cb(int fd, short what, void *arg) -{ - int dummy; - int ret; - - ret = read(g_exit_pipe[0], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - DPRINTF(E_LOG, L_CACHE, "Error reading from exit pipe\n"); - - event_base_loopbreak(evbase_cache); - - g_initialized = 0; - - event_add(g_exitev, NULL); -} - /* ---------------------------- DAAP cache API --------------------------- */ @@ -1637,17 +1606,6 @@ cache_init(void) return 0; } -#ifdef HAVE_PIPE2 - ret = pipe2(g_exit_pipe, O_CLOEXEC); -#else - ret = pipe(g_exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_LOG, L_CACHE, "Could not create exit pipe: %s\n", strerror(errno)); - goto exit_fail; - } - evbase_cache = event_base_new(); if (!evbase_cache) { @@ -1655,13 +1613,6 @@ cache_init(void) goto evbase_fail; } - g_exitev = event_new(evbase_cache, g_exit_pipe[0], EV_READ, exit_cb, NULL); - if (!g_exitev) - { - DPRINTF(E_LOG, L_CACHE, "Could not create exit event\n"); - goto evnew_fail; - } - g_cacheev = evtimer_new(evbase_cache, cache_daap_update_cb, NULL); if (!g_cacheev) { @@ -1669,9 +1620,7 @@ cache_init(void) goto evnew_fail; } - event_add(g_exitev, NULL); - - cmdbase = commands_base_new(evbase_cache); + cmdbase = commands_base_new(evbase_cache, NULL); DPRINTF(E_INFO, L_CACHE, "cache thread init\n"); @@ -1698,10 +1647,6 @@ cache_init(void) evbase_cache = NULL; evbase_fail: - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); - - exit_fail: return -1; } @@ -1713,7 +1658,8 @@ cache_deinit(void) if (!g_initialized) return; - thread_exit(); + g_initialized = 0; + commands_base_destroy(cmdbase); ret = pthread_join(tid_cache, NULL); if (ret != 0) @@ -1724,9 +1670,4 @@ cache_deinit(void) // Free event base (should free events too) event_base_free(evbase_cache); - - // Close pipes and free command base - commands_base_free(cmdbase); - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); } diff --git a/src/commands.c b/src/commands.c index e7ca47a1..9f510623 100644 --- a/src/commands.c +++ b/src/commands.c @@ -46,6 +46,8 @@ struct command struct commands_base { + struct event_base *evbase; + command_exit_cb exit_cb; int command_pipe[2]; struct event *command_event; struct command *current_cmd; @@ -166,10 +168,13 @@ send_command(struct commands_base *cmdbase, struct command *cmd) } /* - * Creates a new command base, needs to be freed by commands_base_free. + * Creates a new command base, needs to be freed by commands_base_destroy or commands_base_free. + * + * @param evbase The libevent base to use for command handling + * @param exit_cb Callback function to be called during commands_base_destroy */ struct commands_base * -commands_base_new(struct event_base *evbase) +commands_base_new(struct event_base *evbase, command_exit_cb exit_cb) { struct commands_base *cmdbase; int ret; @@ -213,6 +218,9 @@ commands_base_new(struct event_base *evbase) return NULL; } + cmdbase->evbase = evbase; + cmdbase->exit_cb = exit_cb; + return cmdbase; } @@ -359,3 +367,39 @@ commands_exec_async(struct commands_base *cmdbase, command_function func, void * return 0; } +/* + * Command to break the libevent loop + * + * If the command base was created with an exit_cb function, exit_cb is called before breaking the + * libevent loop. + * + * @param arg The command base + * @param retval Always set to COMMAND_END + */ +static enum command_state +cmdloop_exit(void *arg, int *retval) +{ + struct commands_base *cmdbase = arg; + *retval = 0; + + if (cmdbase->exit_cb) + cmdbase->exit_cb(); + + event_base_loopbreak(cmdbase->evbase); + + return COMMAND_END; +} + +/* + * Break the libevent loop for the given command base, closes the internally used pipes + * and frees the command base. + * + * @param cmdbase The command base + */ +void +commands_base_destroy(struct commands_base *cmdbase) +{ + commands_exec_sync(cmdbase, cmdloop_exit, NULL, cmdbase); + commands_base_free(cmdbase); +} + diff --git a/src/commands.h b/src/commands.h index 5d4df0e1..be1bba1a 100644 --- a/src/commands.h +++ b/src/commands.h @@ -39,11 +39,14 @@ enum command_state { */ typedef enum command_state (*command_function)(void *arg, int *ret); +typedef void (*command_exit_cb)(void); + + struct commands_base; struct commands_base * -commands_base_new(struct event_base *evbase); +commands_base_new(struct event_base *evbase, command_exit_cb exit_cb); int commands_base_free(struct commands_base *cmdbase); @@ -60,5 +63,7 @@ commands_exec_sync(struct commands_base *cmdbase, command_function func, command int commands_exec_async(struct commands_base *cmdbase, command_function func, void *arg); +void +commands_base_destroy(struct commands_base *cmdbase); #endif /* SRC_COMMANDS_H_ */ diff --git a/src/filescanner.c b/src/filescanner.c index 2b19ea1f..cb278f11 100644 --- a/src/filescanner.c +++ b/src/filescanner.c @@ -104,12 +104,10 @@ struct stacked_dir { struct stacked_dir *next; }; -static int exit_pipe[2]; static int scan_exit; static int inofd; static struct event_base *evbase_scan; static struct event *inoev; -static struct event *exitev; static pthread_t tid_scan; static struct deferred_pl *playlists; static struct stacked_dir *dirstack; @@ -1911,13 +1909,6 @@ inofd_event_unset(void) } /* Thread: scan */ -static void -exit_cb(int fd, short event, void *arg) -{ - event_base_loopbreak(evbase_scan); - - scan_exit = 1; -} static enum command_state filescanner_initscan(void *arg, int *retval) @@ -2002,32 +1993,13 @@ filescanner_init(void) return -1; } -#ifdef HAVE_PIPE2 - ret = pipe2(exit_pipe, O_CLOEXEC); -#else - ret = pipe(exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_FATAL, L_SCAN, "Could not create pipe: %s\n", strerror(errno)); - - goto pipe_fail; - } - - exitev = event_new(evbase_scan, exit_pipe[0], EV_READ, exit_cb, NULL); - if (!exitev || (event_add(exitev, NULL) < 0)) - { - DPRINTF(E_LOG, L_SCAN, "Could not create/add command event\n"); - goto exitev_fail; - } - ret = inofd_event_set(); if (ret < 0) { goto ino_fail; } - cmdbase = commands_base_new(evbase_scan); + cmdbase = commands_base_new(evbase_scan, NULL); ret = pthread_create(&tid_scan, NULL, filescanner, NULL); if (ret != 0) @@ -2048,11 +2020,7 @@ filescanner_init(void) thread_fail: commands_base_free(cmdbase); close(inofd); - exitev_fail: ino_fail: - close(exit_pipe[0]); - close(exit_pipe[1]); - pipe_fail: event_base_free(evbase_scan); return -1; @@ -2063,17 +2031,9 @@ void filescanner_deinit(void) { int ret; - int dummy = 42; - - ret = write(exit_pipe[1], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - { - DPRINTF(E_FATAL, L_SCAN, "Could not write to exit fd: %s\n", strerror(errno)); - - return; - } scan_exit = 1; + commands_base_destroy(cmdbase); ret = pthread_join(tid_scan, NULL); if (ret != 0) @@ -2086,7 +2046,4 @@ filescanner_deinit(void) inofd_event_unset(); event_base_free(evbase_scan); - commands_base_free(cmdbase); - close(exit_pipe[0]); - close(exit_pipe[1]); } diff --git a/src/mpd.c b/src/mpd.c index 846280c2..cf1b5866 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -68,8 +68,6 @@ static pthread_t tid_mpd; static struct event_base *evbase_mpd; -static int g_exit_pipe[2]; -static struct event *g_exitev; static struct commands_base *cmdbase; @@ -192,17 +190,6 @@ struct idle_client struct idle_client *idle_clients; -static void -thread_exit(void) -{ - int dummy = 42; - - DPRINTF(E_DBG, L_MPD, "Killing mpd thread\n"); - - if (write(g_exit_pipe[1], &dummy, sizeof(dummy)) != sizeof(dummy)) - DPRINTF(E_LOG, L_MPD, "Could not write to exit fd: %s\n", strerror(errno)); -} - /* Thread: mpd */ static void * @@ -225,21 +212,6 @@ mpd(void *arg) pthread_exit(NULL); } -static void -exit_cb(int fd, short what, void *arg) -{ - int dummy; - int ret; - - ret = read(g_exit_pipe[0], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - DPRINTF(E_LOG, L_MPD, "Error reading from exit pipe\n"); - - event_base_loopbreak(evbase_mpd); - - event_add(g_exitev, NULL); -} - static void mpd_time(char *buffer, size_t bufferlen, time_t t) { @@ -4670,17 +4642,6 @@ int mpd_init(void) v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6"); -#ifdef HAVE_PIPE2 - ret = pipe2(g_exit_pipe, O_CLOEXEC); -#else - ret = pipe(g_exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_LOG, L_MPD, "Could not create pipe: %s\n", strerror(errno)); - goto exit_fail; - } - evbase_mpd = event_base_new(); if (!evbase_mpd) { @@ -4688,16 +4649,7 @@ int mpd_init(void) goto evbase_fail; } - g_exitev = event_new(evbase_mpd, g_exit_pipe[0], EV_READ, exit_cb, NULL); - if (!g_exitev) - { - DPRINTF(E_LOG, L_MPD, "Could not create exit event\n"); - goto evnew_fail; - } - - event_add(g_exitev, NULL); - - cmdbase = commands_base_new(evbase_mpd); + cmdbase = commands_base_new(evbase_mpd, NULL); if (v6enabled) { @@ -4808,15 +4760,10 @@ int mpd_init(void) evconnlistener_free(listener); connew_fail: commands_base_free(cmdbase); - evnew_fail: event_base_free(evbase_mpd); evbase_mpd = NULL; evbase_fail: - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); - - exit_fail: return -1; } @@ -4835,7 +4782,7 @@ void mpd_deinit(void) return; } - thread_exit(); + commands_base_destroy(cmdbase); ret = pthread_join(tid_mpd, NULL); if (ret != 0) @@ -4861,9 +4808,4 @@ void mpd_deinit(void) // Free event base (should free events too) event_base_free(evbase_mpd); - - // Close pipes and free command base - commands_base_free(cmdbase); - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); } diff --git a/src/player.c b/src/player.c index 9321268b..cd9bbfdb 100644 --- a/src/player.c +++ b/src/player.c @@ -220,9 +220,7 @@ union player_arg struct event_base *evbase_player; -static int exit_pipe[2]; static int player_exit; -static struct event *exitev; static pthread_t tid_player; static struct commands_base *cmdbase; @@ -3952,14 +3950,6 @@ player(void *arg) pthread_exit(NULL); } -/* Thread: player */ -static void -exit_cb(int fd, short what, void *arg) -{ - event_base_loopbreak(evbase_player); - - player_exit = 1; -} /* Thread: main */ int @@ -4041,18 +4031,6 @@ player_init(void) goto audio_fail; } -#ifdef HAVE_PIPE2 - ret = pipe2(exit_pipe, O_CLOEXEC); -#else - ret = pipe(exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_LOG, L_PLAYER, "Could not create pipe: %s\n", strerror(errno)); - - goto exit_fail; - } - evbase_player = event_base_new(); if (!evbase_player) { @@ -4061,13 +4039,6 @@ player_init(void) goto evbase_fail; } - exitev = event_new(evbase_player, exit_pipe[0], EV_READ, exit_cb, NULL); - if (!exitev) - { - DPRINTF(E_LOG, L_PLAYER, "Could not create exit event\n"); - goto evnew_fail; - } - #if defined(__linux__) pb_timer_ev = event_new(evbase_player, pb_timer_fd, EV_READ | EV_PERSIST, player_playback_cb, NULL); #else @@ -4079,10 +4050,9 @@ player_init(void) goto evnew_fail; } - event_add(exitev, NULL); event_add(pb_timer_ev, NULL); - cmdbase = commands_base_new(evbase_player); + cmdbase = commands_base_new(evbase_player, NULL); ret = outputs_init(); if (ret < 0) @@ -4112,9 +4082,6 @@ player_init(void) evnew_fail: event_base_free(evbase_player); evbase_fail: - close(exit_pipe[0]); - close(exit_pipe[1]); - exit_fail: evbuffer_free(audio_buf); audio_fail: #if defined(__linux__) @@ -4131,20 +4098,14 @@ void player_deinit(void) { int ret; - int dummy = 42; - ret = write(exit_pipe[1], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - { - DPRINTF(E_LOG, L_PLAYER, "Could not write to exit pipe: %s\n", strerror(errno)); - - return; - } + player_exit = 1; + commands_base_destroy(cmdbase); ret = pthread_join(tid_player, NULL); if (ret != 0) { - DPRINTF(E_LOG, L_PLAYER, "Could not join HTTPd thread: %s\n", strerror(errno)); + DPRINTF(E_LOG, L_PLAYER, "Could not join player thread: %s\n", strerror(errno)); return; } @@ -4164,8 +4125,4 @@ player_deinit(void) outputs_deinit(); event_base_free(evbase_player); - - commands_base_free(cmdbase); - close(exit_pipe[0]); - close(exit_pipe[1]); } diff --git a/src/spotify.c b/src/spotify.c index 8bd3c3f9..8b2cedb6 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -114,9 +114,7 @@ static pthread_cond_t login_cond; // Event base, pipes and events struct event_base *evbase_spotify; -static int g_exit_pipe[2]; static int g_notify_pipe[2]; -static struct event *g_exitev; static struct event *g_notifyev; static struct commands_base *cmdbase; @@ -384,21 +382,6 @@ fptr_assign_all() // End of ugly part -/* ---------------------------- COMMAND EXECUTION -------------------------- */ - -/* Thread: main and filescanner */ -static void -thread_exit(void) -{ - int dummy = 42; - - DPRINTF(E_DBG, L_SPOTIFY, "Killing Spotify thread\n"); - - if (write(g_exit_pipe[1], &dummy, sizeof(dummy)) != sizeof(dummy)) - DPRINTF(E_LOG, L_SPOTIFY, "Could not write to exit fd: %s\n", strerror(errno)); -} - - /* -------------------------- PLAYLIST HELPERS ------------------------- */ /* Should only be called from within the spotify thread */ @@ -1619,23 +1602,11 @@ spotify(void *arg) } static void -exit_cb(int fd, short what, void *arg) +exit_cb() { - int dummy; - int ret; - - ret = read(g_exit_pipe[0], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - DPRINTF(E_LOG, L_SPOTIFY, "Error reading from exit pipe\n"); - fptr_sp_session_player_unload(g_sess); fptr_sp_session_logout(g_sess); - - event_base_loopbreak(evbase_spotify); - g_state = SPOTIFY_STATE_INACTIVE; - - event_add(g_exitev, NULL); } /* Process events when timeout expires or triggered by libspotify's notify_main_thread */ @@ -1976,17 +1947,6 @@ spotify_init(void) if (ret < 0) goto assign_fail; -#ifdef HAVE_PIPE2 - ret = pipe2(g_exit_pipe, O_CLOEXEC); -#else - ret = pipe(g_exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_LOG, L_SPOTIFY, "Could not create pipe: %s\n", strerror(errno)); - goto exit_fail; - } - #ifdef HAVE_PIPE2 ret = pipe2(g_notify_pipe, O_CLOEXEC); #else @@ -2005,13 +1965,6 @@ spotify_init(void) goto evbase_fail; } - g_exitev = event_new(evbase_spotify, g_exit_pipe[0], EV_READ, exit_cb, NULL); - if (!g_exitev) - { - DPRINTF(E_LOG, L_SPOTIFY, "Could not create exit event\n"); - goto evnew_fail; - } - g_notifyev = event_new(evbase_spotify, g_notify_pipe[0], EV_READ | EV_TIMEOUT, notify_cb, NULL); if (!g_notifyev) { @@ -2019,11 +1972,10 @@ spotify_init(void) goto evnew_fail; } - event_add(g_exitev, NULL); event_add(g_notifyev, NULL); - cmdbase = commands_base_new(evbase_spotify); + cmdbase = commands_base_new(evbase_spotify, exit_cb); if (!cmdbase) { DPRINTF(E_LOG, L_SPOTIFY, "Could not create command base\n"); @@ -2116,10 +2068,6 @@ spotify_init(void) close(g_notify_pipe[1]); notify_fail: - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); - - exit_fail: assign_fail: dlclose(g_libhandle); g_libhandle = NULL; @@ -2139,7 +2087,8 @@ spotify_deinit(void) /* Send exit signal to thread (if active) */ if (g_state != SPOTIFY_STATE_INACTIVE) { - thread_exit(); + commands_base_destroy(cmdbase); + g_state = SPOTIFY_STATE_INACTIVE; ret = pthread_join(tid_spotify, NULL); if (ret != 0) @@ -2155,12 +2104,9 @@ spotify_deinit(void) /* Free event base (should free events too) */ event_base_free(evbase_spotify); - /* Close pipes and free command base */ - commands_base_free(cmdbase); + /* Close pipes */ close(g_notify_pipe[0]); close(g_notify_pipe[1]); - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); /* Destroy locks */ pthread_cond_destroy(&login_cond); diff --git a/src/worker.c b/src/worker.c index 6bb90d73..a7cc9ee7 100644 --- a/src/worker.c +++ b/src/worker.c @@ -58,8 +58,6 @@ static pthread_t tid_worker; // Event base, pipes and events struct event_base *evbase_worker; static int g_initialized; -static int g_exit_pipe[2]; -static struct event *g_exitev; static struct commands_base *cmdbase; @@ -102,20 +100,6 @@ execute(void *arg, int *retval) } -/* Thread: main */ -static void -thread_exit(void) -{ - int dummy = 42; - - DPRINTF(E_DBG, L_MAIN, "Killing worker thread\n"); - - if (write(g_exit_pipe[1], &dummy, sizeof(dummy)) != sizeof(dummy)) - DPRINTF(E_LOG, L_MAIN, "Could not write to exit fd: %s\n", strerror(errno)); -} - - - /* --------------------------------- MAIN --------------------------------- */ /* Thread: worker */ @@ -146,23 +130,6 @@ worker(void *arg) pthread_exit(NULL); } -static void -exit_cb(int fd, short what, void *arg) -{ - int dummy; - int ret; - - ret = read(g_exit_pipe[0], &dummy, sizeof(dummy)); - if (ret != sizeof(dummy)) - DPRINTF(E_LOG, L_MAIN, "Error reading from exit pipe\n"); - - event_base_loopbreak(evbase_worker); - - g_initialized = 0; - - event_add(g_exitev, NULL); -} - /* ---------------------------- Our worker API --------------------------- */ @@ -205,17 +172,6 @@ worker_init(void) { int ret; -#ifdef HAVE_PIPE2 - ret = pipe2(g_exit_pipe, O_CLOEXEC); -#else - ret = pipe(g_exit_pipe); -#endif - if (ret < 0) - { - DPRINTF(E_LOG, L_MAIN, "Could not create pipe: %s\n", strerror(errno)); - goto exit_fail; - } - evbase_worker = event_base_new(); if (!evbase_worker) { @@ -223,16 +179,7 @@ worker_init(void) goto evbase_fail; } - g_exitev = event_new(evbase_worker, g_exit_pipe[0], EV_READ, exit_cb, NULL); - if (!g_exitev) - { - DPRINTF(E_LOG, L_MAIN, "Could not create exit event\n"); - goto evnew_fail; - } - - cmdbase = commands_base_new(evbase_worker); - - event_add(g_exitev, NULL); + cmdbase = commands_base_new(evbase_worker, NULL); ret = pthread_create(&tid_worker, NULL, worker, NULL); if (ret < 0) @@ -252,15 +199,10 @@ worker_init(void) thread_fail: commands_base_free(cmdbase); - evnew_fail: event_base_free(evbase_worker); evbase_worker = NULL; evbase_fail: - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); - - exit_fail: return -1; } @@ -269,7 +211,8 @@ worker_deinit(void) { int ret; - thread_exit(); + g_initialized = 0; + commands_base_destroy(cmdbase); ret = pthread_join(tid_worker, NULL); if (ret != 0) @@ -280,9 +223,4 @@ worker_deinit(void) // Free event base (should free events too) event_base_free(evbase_worker); - - // Close pipes and free command base - commands_base_free(cmdbase); - close(g_exit_pipe[0]); - close(g_exit_pipe[1]); }