[threads] Update mutex/cond functions to use new CHECK_ERR macros

Added various macros to check return values and log any errors and abort
if the call fails.
Updated logging to handle early errors before logging initialized.
This commit is contained in:
Scott Shambarger 2017-01-21 07:11:20 -08:00
parent b54d94fda6
commit 8e3797ec43
8 changed files with 207 additions and 185 deletions

View File

@ -78,7 +78,7 @@ command_cb_sync(struct commands_base *cmdbase, struct command *cmd)
{
enum command_state cmdstate;
fork_mutex_lock(&cmd->lck);
CHECK_ERR(L_MAIN, pthread_mutex_lock(&cmd->lck));
cmdstate = cmd->func(cmd->arg, &cmd->ret);
if (cmdstate == COMMAND_PENDING)
@ -94,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
fork_cond_signal(&cmd->cond);
fork_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);
}
@ -283,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);
}
fork_cond_signal(&cmdbase->current_cmd->cond);
fork_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;
@ -317,10 +317,10 @@ commands_exec_sync(struct commands_base *cmdbase, command_function func, command
cmd.arg = arg;
cmd.nonblock = 0;
fork_mutex_init(&cmd.lck);
fork_cond_init(&cmd.cond);
CHECK_ERR(L_MAIN, mutex_init(&cmd.lck));
CHECK_ERR(L_MAIN, pthread_cond_init(&cmd.cond, NULL));
fork_mutex_lock(&cmd.lck);
CHECK_ERR(L_MAIN, pthread_mutex_lock(&cmd.lck));
ret = send_command(cmdbase, &cmd);
if (ret < 0)
@ -330,12 +330,12 @@ commands_exec_sync(struct commands_base *cmdbase, command_function func, command
}
else
{
fork_cond_wait(&cmd.cond, &cmd.lck);
CHECK_ERR(L_MAIN, pthread_cond_wait(&cmd.cond, &cmd.lck));
}
fork_mutex_unlock(&cmd.lck);
CHECK_ERR(L_MAIN, pthread_mutex_unlock(&cmd.lck));
fork_cond_destroy(&cmd.cond);
fork_mutex_destroy(&cmd.lck);
CHECK_ERR(L_MAIN, pthread_cond_destroy(&cmd.cond));
CHECK_ERR(L_MAIN, pthread_mutex_destroy(&cmd.lck));
return cmd.ret;
}

View File

@ -530,12 +530,12 @@ unlock_notify_cb(void **args, int nargs)
{
u = (struct db_unlock *)args[i];
fork_mutex_lock(&u->lck);
CHECK_ERR(L_DB, pthread_mutex_lock(&u->lck));
u->proceed = 1;
fork_cond_signal(&u->cond);
CHECK_ERR(L_DB, pthread_cond_signal(&u->cond));
fork_mutex_unlock(&u->lck);
CHECK_ERR(L_DB, pthread_mutex_unlock(&u->lck));
}
}
@ -546,25 +546,25 @@ db_wait_unlock(void)
int ret;
u.proceed = 0;
fork_mutex_init(&u.lck);
fork_cond_init(&u.cond);
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)
{
fork_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");
fork_cond_wait(&u.cond, &u.lck);
CHECK_ERR(L_DB, pthread_cond_wait(&u.cond, &u.lck));
}
fork_mutex_unlock(&u.lck);
CHECK_ERR(L_DB, pthread_mutex_unlock(&u.lck));
}
fork_cond_destroy(&u.cond);
fork_mutex_destroy(&u.lck);
CHECK_ERR(L_DB, pthread_cond_destroy(&u.cond));
CHECK_ERR(L_DB, pthread_mutex_destroy(&u.lck));
return ret;
}

View File

@ -37,15 +37,23 @@
#include "conffile.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" };
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;
fork_mutex_lock(&logger_lck);
if (!logfile && !console)
{
fork_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);
}
}
fork_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;
fork_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:
fork_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));
}
}

View File

@ -428,19 +428,19 @@ ffmpeg_lockmgr(void **pmutex, enum AVLockOp op)
*pmutex = malloc(sizeof(pthread_mutex_t));
if (!*pmutex)
return 1;
fork_mutex_init(*pmutex);
CHECK_ERR(L_MAIN, mutex_init(*pmutex));
return 0;
case AV_LOCK_OBTAIN:
fork_mutex_lock(*pmutex);
CHECK_ERR(L_MAIN, pthread_mutex_lock(*pmutex));
return 0;
case AV_LOCK_RELEASE:
fork_mutex_unlock(*pmutex);
CHECK_ERR(L_MAIN, pthread_mutex_unlock(*pmutex));
return 0;
case AV_LOCK_DESTROY:
fork_mutex_destroy(*pmutex);
CHECK_ERR(L_MAIN, pthread_mutex_destroy(*pmutex));
free(*pmutex);
*pmutex = NULL;
@ -450,7 +450,6 @@ ffmpeg_lockmgr(void **pmutex, enum AVLockOp op)
return 1;
}
int
main(int argc, char **argv)
{

View File

@ -920,87 +920,34 @@ timespec_cmp(struct timespec time1, struct timespec time2)
return 0;
}
void
fork_mutex_init(pthread_mutex_t *mutex)
int
mutex_init(pthread_mutex_t *mutex)
{
pthread_mutexattr_t mattr;
int err;
err = pthread_mutexattr_init(&mattr);
assert(err == 0);
err = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK);
assert(err == 0);
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);
assert(err == 0);
err = pthread_mutexattr_destroy(&mattr);
assert(err == 0);
}
CHECK_ERR(L_MISC, pthread_mutexattr_destroy(&mattr));
void
fork_mutex_lock(pthread_mutex_t *mutex)
{
int err;
err = pthread_mutex_lock(mutex);
assert(err == 0);
}
void
fork_mutex_unlock(pthread_mutex_t *mutex)
{
int err;
err = pthread_mutex_unlock(mutex);
assert(err == 0);
}
void
fork_mutex_destroy(pthread_mutex_t *mutex)
{
int err;
err = pthread_mutex_destroy(mutex);
assert(err == 0);
}
/* condition wrappers with checks */
void
fork_cond_init(pthread_cond_t *cond)
{
int err;
err = pthread_cond_init(cond, NULL);
assert(err == 0);
}
void
fork_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int err;
err = pthread_cond_wait(cond, mutex);
assert(err == 0);
}
int
fork_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *ts)
{
int err;
err = pthread_cond_timedwait(cond, mutex, ts);
if(err == ETIMEDOUT)
return err;
assert(err == 0);
return err;
}
void
fork_cond_signal(pthread_cond_t *cond)
{
int err;
err = pthread_cond_signal(cond);
assert(err == 0);
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
fork_cond_destroy(pthread_cond_t *cond)
{
int err;
err = pthread_cond_destroy(cond);
assert(err == 0);
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();
}

View File

@ -97,27 +97,49 @@ timespec_add(struct timespec time1, struct timespec time2);
int
timespec_cmp(struct timespec time1, struct timespec time2);
/* mutex wrappers with checks */
void
fork_mutex_init(pthread_mutex_t *mutex);
void
fork_mutex_lock(pthread_mutex_t *mutex);
void
fork_mutex_unlock(pthread_mutex_t *mutex);
void
fork_mutex_destroy(pthread_mutex_t *mutex);
/* condition wrappers with checks */
void
fork_cond_init(pthread_cond_t *cond);
void
fork_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
/* initialize mutex with error checking (not default on all platforms) */
int
fork_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *ts);
void
fork_cond_signal(pthread_cond_t *cond);
void
fork_cond_destroy(pthread_cond_t *cond);
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__ */

View File

@ -84,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;
@ -660,7 +660,7 @@ pairing_cb(int fd, short event, void *arg)
for (;;)
{
fork_mutex_lock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck));
for (ri = remote_list; ri; ri = ri->next)
{
@ -672,7 +672,7 @@ pairing_cb(int fd, short event, void *arg)
}
}
fork_mutex_unlock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck));
if (!ri)
break;
@ -699,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.
*/
fork_mutex_lock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck));
remove_remote_address_byid(name, family);
fork_mutex_unlock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck));
}
else
{
@ -761,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 */
fork_mutex_lock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck));
ret = add_remote_mdns_data(name, family, address, port, devname, paircode);
@ -775,7 +775,7 @@ touch_remote_cb(const char *name, const char *type, const char *domain, const ch
else if (ret == 1)
kickoff_pairing();
fork_mutex_unlock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck));
}
}
@ -885,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);
fork_mutex_lock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck));
ret = add_remote_pin_data(devname, pin);
free(devname);
@ -894,7 +894,7 @@ remote_pairing_read_pin(char *path)
else
kickoff_pairing();
fork_mutex_unlock(&remote_lck);
CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck));
}
@ -906,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)
@ -989,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));
}

View File

@ -1489,7 +1489,7 @@ audio_fifo_flush(void)
DPRINTF(E_DBG, L_SPOTIFY, "Flushing audio fifo\n");
fork_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);
@ -1498,7 +1498,7 @@ audio_fifo_flush(void)
g_audio_fifo->qlen = 0;
g_audio_fifo->fullcount = 0;
fork_mutex_unlock(&g_audio_fifo->mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex));
}
static enum command_state
@ -1668,6 +1668,7 @@ audio_get(void *arg, int *retval)
int processed;
int timeout;
int ret;
int err;
int s;
audio = (struct audio_get_param *) arg;
@ -1678,7 +1679,7 @@ audio_get(void *arg, int *retval)
if (g_state == SPOTIFY_STATE_PAUSED)
playback_play(NULL, retval);
fork_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))
{
@ -1701,7 +1702,7 @@ audio_get(void *arg, int *retval)
DPRINTF(E_DBG, L_SPOTIFY, "Waiting for audio\n");
timeout += 5;
mk_reltime(&ts, 5);
fork_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))
@ -1725,7 +1726,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);
fork_mutex_unlock(&g_audio_fifo->mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex));
*retval = -1;
return COMMAND_END;
}
@ -1733,7 +1734,7 @@ audio_get(void *arg, int *retval)
processed += s;
}
fork_mutex_unlock(&g_audio_fifo->mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex));
*retval = processed;
@ -1747,12 +1748,12 @@ artwork_loaded_cb(sp_image *image, void *userdata)
artwork = userdata;
fork_mutex_lock(&artwork->mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork->mutex));
artwork->is_loaded = 1;
fork_cond_signal(&artwork->cond);
fork_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
@ -1989,10 +1990,10 @@ logged_out(sp_session *sess)
{
DPRINTF(E_INFO, L_SPOTIFY, "Logout complete\n");
fork_mutex_lock(&login_lck);
CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&login_lck));
fork_cond_signal(&login_cond);
fork_mutex_unlock(&login_lck);
CHECK_ERR(L_SPOTIFY, pthread_cond_signal(&login_cond));
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck));
}
/**
@ -2017,7 +2018,7 @@ static int music_delivery(sp_session *sess, const sp_audioformat *format,
if (num_frames == 0)
return 0; // Audio discontinuity, do nothing
fork_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))
@ -2033,7 +2034,7 @@ static int music_delivery(sp_session *sess, const sp_audioformat *format,
g_audio_fifo->fullcount = 0;
}
fork_mutex_unlock(&g_audio_fifo->mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&g_audio_fifo->mutex));
return 0;
}
@ -2050,8 +2051,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;
fork_cond_signal(&g_audio_fifo->cond);
fork_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;
}
@ -2365,25 +2366,26 @@ 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;
fork_mutex_init(&artwork.mutex);
fork_cond_init(&artwork.cond);
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)
{
fork_mutex_lock(&artwork.mutex);
CHECK_ERR(L_SPOTIFY, pthread_mutex_lock(&artwork.mutex));
mk_reltime(&ts, SPOTIFY_ARTWORK_TIMEOUT);
if (!artwork.is_loaded)
fork_cond_timedwait(&artwork.cond, &artwork.mutex, &ts);
fork_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);
}
@ -2431,7 +2433,7 @@ void
spotify_oauth_callback(struct evbuffer *evbuf, struct evkeyvalq *param, const char *redirect_uri)
{
const char *code;
const char *err;
const char *err = "";
int total;
int ret;
@ -2499,7 +2501,7 @@ spotify_login(char *path)
if (SP_CONNECTION_STATE_LOGGED_IN == fptr_sp_session_connectionstate(g_sess))
{
fork_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);
@ -2509,12 +2511,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));
fork_mutex_unlock(&login_lck);
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck));
return;
}
fork_cond_wait(&login_cond, &login_lck);
fork_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");
@ -2649,11 +2651,11 @@ spotify_init(void)
}
TAILQ_INIT(&g_audio_fifo->q);
g_audio_fifo->qlen = 0;
fork_mutex_init(&g_audio_fifo->mutex);
fork_cond_init(&g_audio_fifo->cond);
CHECK_ERR(L_SPOTIFY, mutex_init(&g_audio_fifo->mutex));
CHECK_ERR(L_SPOTIFY, pthread_cond_init(&g_audio_fifo->cond, NULL));
fork_mutex_init(&login_lck);
fork_cond_init(&login_cond);
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);
@ -2673,11 +2675,11 @@ spotify_init(void)
return 0;
thread_fail:
fork_cond_destroy(&login_cond);
fork_mutex_destroy(&login_lck);
CHECK_ERR(L_SPOTIFY, pthread_cond_destroy(&login_cond));
CHECK_ERR(L_SPOTIFY, pthread_mutex_destroy(&login_lck));
fork_cond_destroy(&g_audio_fifo->cond);
fork_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:
@ -2737,12 +2739,12 @@ spotify_deinit(void)
close(g_notify_pipe[1]);
/* Destroy locks */
fork_cond_destroy(&login_cond);
fork_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 */
fork_cond_destroy(&g_audio_fifo->cond);
fork_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 */