diff --git a/src/commands.c b/src/commands.c index 91752357..a799aa83 100644 --- a/src/commands.c +++ b/src/commands.c @@ -20,14 +20,13 @@ #include #include -#include #include #include #include #include #include "logger.h" - +#include "misc.h" struct command { @@ -79,7 +78,7 @@ command_cb_sync(struct commands_base *cmdbase, struct command *cmd) { enum command_state cmdstate; - pthread_mutex_lock(&cmd->lck); + CHECK_ERR(L_MAIN, pthread_mutex_lock(&cmd->lck)); cmdstate = cmd->func(cmd->arg, &cmd->ret); if (cmdstate == COMMAND_PENDING) @@ -95,8 +94,8 @@ command_cb_sync(struct commands_base *cmdbase, struct command *cmd) cmd->func_bh(cmd->arg, &cmd->ret); // Signal the calling thread that the command execution finished - pthread_cond_signal(&cmd->cond); - pthread_mutex_unlock(&cmd->lck); + CHECK_ERR(L_MAIN, pthread_cond_signal(&cmd->cond)); + CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmd->lck)); event_add(cmdbase->command_event, NULL); } @@ -284,8 +283,8 @@ commands_exec_end(struct commands_base *cmdbase, int retvalue) { cmdbase->current_cmd->func_bh(cmdbase->current_cmd->arg, &cmdbase->current_cmd->ret); } - pthread_cond_signal(&cmdbase->current_cmd->cond); - pthread_mutex_unlock(&cmdbase->current_cmd->lck); + CHECK_ERR(L_MAIN, pthread_cond_signal(&cmdbase->current_cmd->cond)); + CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmdbase->current_cmd->lck)); cmdbase->current_cmd = NULL; @@ -318,18 +317,25 @@ commands_exec_sync(struct commands_base *cmdbase, command_function func, command cmd.arg = arg; cmd.nonblock = 0; - pthread_mutex_lock(&cmd.lck); + CHECK_ERR(L_MAIN, mutex_init(&cmd.lck)); + CHECK_ERR(L_MAIN, pthread_cond_init(&cmd.cond, NULL)); + + CHECK_ERR(L_MAIN, pthread_mutex_lock(&cmd.lck)); ret = send_command(cmdbase, &cmd); if (ret < 0) { DPRINTF(E_LOG, L_MAIN, "Error sending command\n"); - pthread_mutex_unlock(&cmd.lck); - return -1; + cmd.ret = -1; } + else + { + CHECK_ERR(L_MAIN, pthread_cond_wait(&cmd.cond, &cmd.lck)); + } + CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmd.lck)); - pthread_cond_wait(&cmd.cond, &cmd.lck); - pthread_mutex_unlock(&cmd.lck); + CHECK_ERR(L_MAIN, pthread_cond_destroy(&cmd.cond)); + CHECK_ERR(L_MAIN, pthread_mutex_destroy(&cmd.lck)); return cmd.ret; } diff --git a/src/db.c b/src/db.c index ae2c2ca5..336d362c 100644 --- a/src/db.c +++ b/src/db.c @@ -35,8 +35,6 @@ #include #include -#include - #include #include "conffile.h" @@ -532,12 +530,12 @@ unlock_notify_cb(void **args, int nargs) { u = (struct db_unlock *)args[i]; - pthread_mutex_lock(&u->lck); + CHECK_ERR(L_DB, pthread_mutex_lock(&u->lck)); u->proceed = 1; - pthread_cond_signal(&u->cond); + CHECK_ERR(L_DB, pthread_cond_signal(&u->cond)); - pthread_mutex_unlock(&u->lck); + CHECK_ERR(L_DB, pthread_mutex_unlock(&u->lck)); } } @@ -548,25 +546,25 @@ db_wait_unlock(void) int ret; u.proceed = 0; - pthread_mutex_init(&u.lck, NULL); - pthread_cond_init(&u.cond, NULL); + CHECK_ERR(L_DB, mutex_init(&u.lck)); + CHECK_ERR(L_DB, pthread_cond_init(&u.cond, NULL)); ret = sqlite3_unlock_notify(hdl, unlock_notify_cb, &u); if (ret == SQLITE_OK) { - pthread_mutex_lock(&u.lck); + CHECK_ERR(L_DB, pthread_mutex_lock(&u.lck)); if (!u.proceed) { DPRINTF(E_INFO, L_DB, "Waiting for database unlock\n"); - pthread_cond_wait(&u.cond, &u.lck); + CHECK_ERR(L_DB, pthread_cond_wait(&u.cond, &u.lck)); } - pthread_mutex_unlock(&u.lck); + CHECK_ERR(L_DB, pthread_mutex_unlock(&u.lck)); } - pthread_cond_destroy(&u.cond); - pthread_mutex_destroy(&u.lck); + CHECK_ERR(L_DB, pthread_cond_destroy(&u.cond)); + CHECK_ERR(L_DB, pthread_mutex_destroy(&u.lck)); return ret; } diff --git a/src/logger.c b/src/logger.c index 3da8ceef..c801093a 100644 --- a/src/logger.c +++ b/src/logger.c @@ -20,6 +20,8 @@ # include #endif +#include "logger.h" + #include #include #include @@ -27,25 +29,31 @@ #include #include #include -#include #include #include #include "conffile.h" -#include "logger.h" +#include "misc.h" - -static pthread_mutex_t logger_lck = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t logger_lck; +static int logger_initialized; static int logdomains; static int threshold; -static int console; +static int console = 1; static char *logfilename; static FILE *logfile; static char *labels[] = { "config", "daap", "db", "httpd", "http", "main", "mdns", "misc", "rsp", "scan", "xcode", "event", "remote", "dacp", "ffmpeg", "artwork", "player", "raop", "laudio", "dmap", "dbperf", "spotify", "lastfm", "cache", "mpd", "stream", "cast", "fifo", "lib" }; static char *severities[] = { "FATAL", "LOG", "WARN", "INFO", "DEBUG", "SPAM" }; +/* We need our own check to avoid nested locking or recursive calls */ +#define LOGGER_CHECK_ERR(f) \ + do { int lerr; lerr = f; if (lerr != 0) { \ + vlogger_fatal("%s failed at line %d, err %d (%s)\n", #f, __LINE__, \ + lerr, strerror(lerr)); \ + abort(); \ + } } while(0) static int set_logdomains(char *domains) @@ -80,24 +88,13 @@ set_logdomains(char *domains) } static void -vlogger(int severity, int domain, const char *fmt, va_list args) +vlogger_writer(int severity, int domain, const char *fmt, va_list args) { va_list ap; char stamp[32]; time_t t; int ret; - if (!((1 << domain) & logdomains) || (severity > threshold)) - return; - - pthread_mutex_lock(&logger_lck); - - if (!logfile && !console) - { - pthread_mutex_unlock(&logger_lck); - return; - } - if (logfile) { t = time(NULL); @@ -122,8 +119,43 @@ vlogger(int severity, int domain, const char *fmt, va_list args) vfprintf(stderr, fmt, ap); va_end(ap); } +} - pthread_mutex_unlock(&logger_lck); +static void +vlogger_fatal(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vlogger_writer(E_FATAL, L_MISC, fmt, ap); + va_end(ap); +} + +static void +vlogger(int severity, int domain, const char *fmt, va_list args) +{ + + if(! logger_initialized) + { + /* lock not initialized, use stderr */ + vlogger_writer(severity, domain, fmt, args); + return; + } + + if (!((1 << domain) & logdomains) || (severity > threshold)) + return; + + LOGGER_CHECK_ERR(pthread_mutex_lock(&logger_lck)); + + if (!logfile && !console) + { + LOGGER_CHECK_ERR(pthread_mutex_unlock(&logger_lck)); + return; + } + + vlogger_writer(severity, domain, fmt, args); + + LOGGER_CHECK_ERR(pthread_mutex_unlock(&logger_lck)); } void @@ -204,7 +236,7 @@ logger_reinit(void) if (!logfile) return; - pthread_mutex_lock(&logger_lck); + LOGGER_CHECK_ERR(pthread_mutex_lock(&logger_lck)); fp = fopen(logfilename, "a"); if (!fp) @@ -218,7 +250,7 @@ logger_reinit(void) logfile = fp; out: - pthread_mutex_unlock(&logger_lck); + LOGGER_CHECK_ERR(pthread_mutex_unlock(&logger_lck)); } @@ -287,6 +319,11 @@ logger_init(char *file, char *domains, int severity) logfilename = file; + /* logging w/o locks before initialized complete */ + CHECK_ERR(L_MISC, mutex_init(&logger_lck)); + + logger_initialized = 1; + return 0; } @@ -294,5 +331,16 @@ void logger_deinit(void) { if (logfile) - fclose(logfile); + { + fclose(logfile); + logfile = NULL; + } + + if(logger_initialized) + { + /* logging w/o locks to stderr now */ + logger_initialized = 0; + console = 1; + CHECK_ERR(L_MISC, pthread_mutex_destroy(&logger_lck)); + } } diff --git a/src/main.c b/src/main.c index 7041b7cc..ace007d5 100644 --- a/src/main.c +++ b/src/main.c @@ -44,8 +44,6 @@ # include #endif -#include - #include #include #include @@ -419,26 +417,29 @@ signal_kqueue_cb(int fd, short event, void *arg) static int -ffmpeg_lockmgr(void **mutex, enum AVLockOp op) +ffmpeg_lockmgr(void **pmutex, enum AVLockOp op) { switch (op) { case AV_LOCK_CREATE: - *mutex = malloc(sizeof(pthread_mutex_t)); - if (!*mutex) + *pmutex = malloc(sizeof(pthread_mutex_t)); + if (!*pmutex) return 1; - - return !!pthread_mutex_init(*mutex, NULL); + CHECK_ERR(L_MAIN, mutex_init(*pmutex)); + return 0; case AV_LOCK_OBTAIN: - return !!pthread_mutex_lock(*mutex); + CHECK_ERR(L_MAIN, pthread_mutex_lock(*pmutex)); + return 0; case AV_LOCK_RELEASE: - return !!pthread_mutex_unlock(*mutex); + CHECK_ERR(L_MAIN, pthread_mutex_unlock(*pmutex)); + return 0; case AV_LOCK_DESTROY: - pthread_mutex_destroy(*mutex); - free(*mutex); + CHECK_ERR(L_MAIN, pthread_mutex_destroy(*pmutex)); + free(*pmutex); + *pmutex = NULL; return 0; } @@ -446,7 +447,6 @@ ffmpeg_lockmgr(void **mutex, enum AVLockOp op) return 1; } - int main(int argc, char **argv) { diff --git a/src/misc.c b/src/misc.c index 0abd07f1..bbacb8ea 100644 --- a/src/misc.c +++ b/src/misc.c @@ -927,3 +927,35 @@ timespec_cmp(struct timespec time1, struct timespec time2) else return 0; } + +int +mutex_init(pthread_mutex_t *mutex) +{ + pthread_mutexattr_t mattr; + int err; + + CHECK_ERR(L_MISC, pthread_mutexattr_init(&mattr)); + CHECK_ERR(L_MISC, pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK)); + err = pthread_mutex_init(mutex, &mattr); + CHECK_ERR(L_MISC, pthread_mutexattr_destroy(&mattr)); + + return err; +} + +void log_fatal_err(int domain, const char *func, int line, int err) { + DPRINTF(E_FATAL, domain, "%s failed at line %d, error %d (%s)\n", func, + line, err, strerror(err)); + abort(); +} + +void log_fatal_errno(int domain, const char *func, int line) { + DPRINTF(E_FATAL, domain, "%s failed at line %d, error %d (%s)\n", func, + line, errno, strerror(errno)); + abort(); +} + +void log_fatal_null(int domain, const char *func, int line) { + DPRINTF(E_FATAL, domain, "%s returned NULL at line %d\n", func, line); + abort(); +} + diff --git a/src/misc.h b/src/misc.h index 148fd4b2..88ed1f31 100644 --- a/src/misc.h +++ b/src/misc.h @@ -8,6 +8,7 @@ #include #include +#include struct onekeyval { char *name; @@ -98,4 +99,49 @@ timespec_add(struct timespec time1, struct timespec time2); int timespec_cmp(struct timespec time1, struct timespec time2); +/* initialize mutex with error checking (not default on all platforms) */ +int +mutex_init(pthread_mutex_t *mutex); + +/* Check that the function returns 0, logging a fatal error referencing + returned error (type errno) if it fails, and aborts the process. + Example: CHECK_ERR(L_MAIN, my_function()); */ +#define CHECK_ERR(d, f) \ + do { int chk_err; \ + if ( (chk_err = (f)) != 0) \ + log_fatal_err(d, #f, __LINE__, chk_err); \ + } while(0) + +/* Check that the function returns 0 or okval, logging a fatal + error referencing returned erro (type errno) if not, and aborts the process. + Example: int err; CHECK_ERR_EXCEPT(L_MAIN, my_wait(), err, ETIMEDOUT); */ +#define CHECK_ERR_EXCEPT(d, f, var, okval) \ + do { (var) = (f); \ + if (! (((var) == (okval)) || ((var) == 0))) \ + log_fatal_err(d, #f, __LINE__, (var)); \ + } while(0) + +/* Check that the function returns value >= 0, logging a fatal error + referencing errno if it not, and aborts the process. + Example: int ret; CHECK_ERRNO(L_MAIN, ret = my_function()); */ +#define CHECK_ERRNO(d, f) \ + do { \ + if ( (f) < 0 ) \ + log_fatal_errno(d, #f, __LINE__); \ + } while(0) + +/* Check that the function returns non-NULL, logging a fatal error if not, + and aborts the process. + Example: void *ptr; CHECK_NULL(L_MAIN, ptr = my_create()); */ +#define CHECK_NULL(d, f) \ + do { \ + if ( (f) == NULL ) \ + log_fatal_null(d, #f, __LINE__); \ + } while(0) + +/* Used by CHECK_*() macros */ +void log_fatal_err(int domain, const char *func, int line, int err); +void log_fatal_errno(int domain, const char *func, int line); +void log_fatal_null(int domain, const char *func, int line); + #endif /* !__MISC_H__ */ diff --git a/src/remote_pairing.c b/src/remote_pairing.c index 0f586e9b..ff76fe2d 100644 --- a/src/remote_pairing.c +++ b/src/remote_pairing.c @@ -39,7 +39,6 @@ #include #include #include -#include #ifdef HAVE_EVENTFD # include @@ -85,7 +84,7 @@ static int pairing_efd; static int pairing_pipe[2]; #endif static struct event *pairingev; -static pthread_mutex_t remote_lck = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t remote_lck; static struct remote_info *remote_list; @@ -661,7 +660,7 @@ pairing_cb(int fd, short event, void *arg) for (;;) { - pthread_mutex_lock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck)); for (ri = remote_list; ri; ri = ri->next) { @@ -673,7 +672,7 @@ pairing_cb(int fd, short event, void *arg) } } - pthread_mutex_unlock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck)); if (!ri) break; @@ -700,11 +699,11 @@ touch_remote_cb(const char *name, const char *type, const char *domain, const ch * failed; any subsequent attempt will need a new pairing pin, so * we can just forget everything we know about the remote. */ - pthread_mutex_lock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck)); remove_remote_address_byid(name, family); - pthread_mutex_unlock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck)); } else { @@ -762,7 +761,7 @@ touch_remote_cb(const char *name, const char *type, const char *domain, const ch DPRINTF(E_LOG, L_REMOTE, "Discovered remote '%s' (id %s) at %s:%d, paircode %s\n", devname, name, address, port, paircode); /* Add the data to the list, adding the remote to the list if needed */ - pthread_mutex_lock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck)); ret = add_remote_mdns_data(name, family, address, port, devname, paircode); @@ -776,7 +775,7 @@ touch_remote_cb(const char *name, const char *type, const char *domain, const ch else if (ret == 1) kickoff_pairing(); - pthread_mutex_unlock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck)); } } @@ -886,7 +885,7 @@ remote_pairing_read_pin(char *path) DPRINTF(E_LOG, L_REMOTE, "Read Remote pairing data (name '%s', pin '%s') from %s\n", devname, pin, path); - pthread_mutex_lock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck)); ret = add_remote_pin_data(devname, pin); free(devname); @@ -895,7 +894,7 @@ remote_pairing_read_pin(char *path) else kickoff_pairing(); - pthread_mutex_unlock(&remote_lck); + CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck)); } @@ -907,6 +906,8 @@ remote_pairing_init(void) remote_list = NULL; + CHECK_ERR(L_REMOTE, mutex_init(&remote_lck)); + #ifdef HAVE_EVENTFD pairing_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (pairing_efd < 0) @@ -990,4 +991,6 @@ remote_pairing_deinit(void) close(pairing_pipe[0]); close(pairing_pipe[1]); #endif + + CHECK_ERR(L_REMOTE, pthread_mutex_destroy(&remote_lck)); } diff --git a/src/spotify.c b/src/spotify.c index 9fd05c47..ce3eba70 100644 --- a/src/spotify.c +++ b/src/spotify.c @@ -1187,7 +1187,7 @@ audio_fifo_flush(void) DPRINTF(E_DBG, L_SPOTIFY, "Flushing audio fifo\n"); - pthread_mutex_lock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&g_audio_fifo->mutex)); while((afd = TAILQ_FIRST(&g_audio_fifo->q))) { TAILQ_REMOVE(&g_audio_fifo->q, afd, link); @@ -1196,7 +1196,7 @@ audio_fifo_flush(void) g_audio_fifo->qlen = 0; g_audio_fifo->fullcount = 0; - pthread_mutex_unlock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex)); } static enum command_state @@ -1366,6 +1366,7 @@ audio_get(void *arg, int *retval) int processed; int timeout; int ret; + int err; int s; audio = (struct audio_get_param *) arg; @@ -1376,7 +1377,7 @@ audio_get(void *arg, int *retval) if (g_state == SPOTIFY_STATE_PAUSED) playback_play(NULL, retval); - pthread_mutex_lock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&g_audio_fifo->mutex)); while ((processed < audio->wanted) && (g_state != SPOTIFY_STATE_STOPPED)) { @@ -1399,7 +1400,7 @@ audio_get(void *arg, int *retval) DPRINTF(E_DBG, L_SPOTIFY, "Waiting for audio\n"); timeout += 5; mk_reltime(&ts, 5); - pthread_cond_timedwait(&g_audio_fifo->cond, &g_audio_fifo->mutex, &ts); + CHECK_ERR_EXCEPT(L_SPOTIFY, pthread_cond_timedwait(&g_audio_fifo->cond, &g_audio_fifo->mutex, &ts), err, ETIMEDOUT); } if ((!afd) && (timeout >= SPOTIFY_TIMEOUT)) @@ -1423,7 +1424,7 @@ audio_get(void *arg, int *retval) if (ret < 0) { DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for evbuffer (tried to add %d bytes)\n", s); - pthread_mutex_unlock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex)); *retval = -1; return COMMAND_END; } @@ -1431,7 +1432,7 @@ audio_get(void *arg, int *retval) processed += s; } - pthread_mutex_unlock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex)); *retval = processed; @@ -1442,15 +1443,15 @@ static void artwork_loaded_cb(sp_image *image, void *userdata) { struct artwork_get_param *artwork; - + artwork = userdata; - - pthread_mutex_lock(&artwork->mutex); + + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork->mutex)); artwork->is_loaded = 1; - pthread_cond_signal(&artwork->cond); - pthread_mutex_unlock(&artwork->mutex); + CHECK_ERR(L_SPOTIFY, pthread_cond_signal(&artwork->cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&artwork->mutex)); } static enum command_state @@ -1666,10 +1667,10 @@ logged_out(sp_session *sess) { DPRINTF(E_INFO, L_SPOTIFY, "Logout complete\n"); - pthread_mutex_lock(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&login_lck)); - pthread_cond_signal(&login_cond); - pthread_mutex_unlock(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_cond_signal(&login_cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck)); } /** @@ -1694,7 +1695,7 @@ static int music_delivery(sp_session *sess, const sp_audioformat *format, if (num_frames == 0) return 0; // Audio discontinuity, do nothing - pthread_mutex_lock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&g_audio_fifo->mutex)); /* Buffer three seconds of audio */ if (g_audio_fifo->qlen > (3 * format->sample_rate)) @@ -1710,7 +1711,7 @@ static int music_delivery(sp_session *sess, const sp_audioformat *format, g_audio_fifo->fullcount = 0; } - pthread_mutex_unlock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex)); return 0; } @@ -1727,8 +1728,8 @@ static int music_delivery(sp_session *sess, const sp_audioformat *format, TAILQ_INSERT_TAIL(&g_audio_fifo->q, afd, link); g_audio_fifo->qlen += num_frames; - pthread_cond_signal(&g_audio_fifo->cond); - pthread_mutex_unlock(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_cond_signal(&g_audio_fifo->cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex)); return num_frames; } @@ -1993,29 +1994,30 @@ spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h) struct artwork_get_param artwork; struct timespec ts; int ret; + int err; artwork.evbuf = evbuf; artwork.path = path; artwork.max_w = max_w; artwork.max_h = max_h; - pthread_mutex_init(&artwork.mutex, NULL); - pthread_cond_init(&artwork.cond, NULL); + CHECK_ERR(L_SPOTIFY, mutex_init(&artwork.mutex)); + CHECK_ERR(L_SPOTIFY, pthread_cond_init(&artwork.cond, NULL)); ret = commands_exec_sync(cmdbase, artwork_get, NULL, &artwork); - + // Artwork was not ready, wait for callback from libspotify if (ret == 0) { - pthread_mutex_lock(&artwork.mutex); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork.mutex)); mk_reltime(&ts, SPOTIFY_ARTWORK_TIMEOUT); if (!artwork.is_loaded) - pthread_cond_timedwait(&artwork.cond, &artwork.mutex, &ts); - pthread_mutex_unlock(&artwork.mutex); + CHECK_ERR_EXCEPT(L_SPOTIFY, pthread_cond_timedwait(&artwork.cond, &artwork.mutex, &ts), err, ETIMEDOUT); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&artwork.mutex)); ret = commands_exec_sync(cmdbase, artwork_get_bh, NULL, &artwork); } - + return ret; } @@ -2104,7 +2106,7 @@ spotify_login(char *path) if (SP_CONNECTION_STATE_LOGGED_IN == fptr_sp_session_connectionstate(g_sess)) { - pthread_mutex_lock(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&login_lck)); DPRINTF(E_LOG, L_SPOTIFY, "Logging out of Spotify (current state is %d)\n", g_state); @@ -2114,12 +2116,12 @@ spotify_login(char *path) if (SP_ERROR_OK != err) { DPRINTF(E_LOG, L_SPOTIFY, "Could not logout of Spotify: %s\n", fptr_sp_error_message(err)); - pthread_mutex_unlock(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck)); return; } - pthread_cond_wait(&login_cond, &login_lck); - pthread_mutex_unlock(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_cond_wait(&login_cond, &login_lck)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck)); } DPRINTF(E_INFO, L_SPOTIFY, "Logging into Spotify\n"); @@ -2658,11 +2660,11 @@ spotify_init(void) } TAILQ_INIT(&g_audio_fifo->q); g_audio_fifo->qlen = 0; - pthread_mutex_init(&g_audio_fifo->mutex, NULL); - pthread_cond_init(&g_audio_fifo->cond, NULL); + CHECK_ERR(L_SPOTIFY, mutex_init(&g_audio_fifo->mutex)); + CHECK_ERR(L_SPOTIFY, pthread_cond_init(&g_audio_fifo->cond, NULL)); - pthread_mutex_init(&login_lck, NULL); - pthread_cond_init(&login_cond, NULL); + CHECK_ERR(L_SPOTIFY, mutex_init(&login_lck)); + CHECK_ERR(L_SPOTIFY, pthread_cond_init(&login_cond, NULL)); /* Spawn thread */ ret = pthread_create(&tid_spotify, NULL, spotify, NULL); @@ -2682,11 +2684,11 @@ spotify_init(void) return 0; thread_fail: - pthread_cond_destroy(&login_cond); - pthread_mutex_destroy(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&login_cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&login_lck)); - pthread_cond_destroy(&g_audio_fifo->cond); - pthread_mutex_destroy(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&g_audio_fifo->cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&g_audio_fifo->mutex)); free(g_audio_fifo); audio_fifo_fail: @@ -2746,12 +2748,12 @@ spotify_deinit(void) close(g_notify_pipe[1]); /* Destroy locks */ - pthread_cond_destroy(&login_cond); - pthread_mutex_destroy(&login_lck); + CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&login_cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&login_lck)); /* Clear audio fifo */ - pthread_cond_destroy(&g_audio_fifo->cond); - pthread_mutex_destroy(&g_audio_fifo->mutex); + CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&g_audio_fifo->cond)); + CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&g_audio_fifo->mutex)); free(g_audio_fifo); /* Release libspotify handle */ diff --git a/src/spotify_webapi.c b/src/spotify_webapi.c index 525f0cfb..01e41f2a 100644 --- a/src/spotify_webapi.c +++ b/src/spotify_webapi.c @@ -294,6 +294,7 @@ spotifywebapi_token_get(const char *code, const char *redirect_uri, const char * struct keyval kv; int ret; + *err = ""; memset(&kv, 0, sizeof(struct keyval)); ret = ( (keyval_add(&kv, "grant_type", "authorization_code") == 0) && (keyval_add(&kv, "code", code) == 0) &&