From: Mike Brady Date: Wed, 18 Jul 2018 14:32:07 +0000 (+0100) Subject: Add quit commands to the MPRIS and native D-Bus command set. Not tested ecologically. X-Git-Tag: 3.3RC0~286^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8c70b60160768fd69ce30759e9df089b6caadac;p=thirdparty%2Fshairport-sync.git Add quit commands to the MPRIS and native D-Bus command set. Not tested ecologically. --- diff --git a/common.h b/common.h index 86cfa1a1..7d556b96 100644 --- a/common.h +++ b/common.h @@ -2,6 +2,7 @@ #define _COMMON_H #include +#include #include #include #include @@ -79,6 +80,7 @@ typedef struct { char *password; char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running // on host %h" + #ifdef CONFIG_PA char *pa_application_name; // the name under which Shairport Sync shows up as an "Application" in // the Sound Preferences in most desktop Linuxes. @@ -263,6 +265,9 @@ uint64_t fp_time_at_startup, fp_time_at_last_debug_message; long endianness; uint32_t uatoi(const char *nptr); +// this is for allowing us to cancel the whole program +pthread_t main_thread_id; + shairport_cfg config; config_t config_file_stuff; diff --git a/dbus-service.c b/dbus-service.c index b16b22da..e8d50c2f 100644 --- a/dbus-service.c +++ b/dbus-service.c @@ -545,9 +545,13 @@ gboolean notify_loop_status_callback(ShairportSyncAdvancedRemoteControl *skeleto } static gboolean on_handle_quit(ShairportSync *skeleton, GDBusMethodInvocation *invocation, - __attribute__((unused)) const gchar *command, - __attribute__((unused)) gpointer user_data) { + __attribute__((unused)) const gchar *command, + __attribute__((unused)) gpointer user_data) { debug(1, "quit requested (native interface)"); + if (main_thread_id) + debug(1, "Cancelling main thread results in %d.", pthread_cancel(main_thread_id)); + else + debug(1, "Main thread ID is NULL."); shairport_sync_complete_quit(skeleton, invocation); return TRUE; } @@ -597,8 +601,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold", G_CALLBACK(notify_loudness_threshold_callback), NULL); - g_signal_connect(shairportSyncSkeleton, "handle-quit", - G_CALLBACK(on_handle_quit), NULL); + g_signal_connect(shairportSyncSkeleton, "handle-quit", G_CALLBACK(on_handle_quit), NULL); g_signal_connect(shairportSyncSkeleton, "handle-remote-command", G_CALLBACK(on_handle_remote_command), NULL); diff --git a/mpris-service.c b/mpris-service.c index 982623e1..668d776e 100644 --- a/mpris-service.c +++ b/mpris-service.c @@ -185,7 +185,8 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, __attribute__((unused) static gboolean on_handle_quit(MediaPlayer2 *skeleton, GDBusMethodInvocation *invocation, __attribute__((unused)) gpointer user_data) { - debug(1,"quit requested (MPRIS interface)."); + debug(1, "quit requested (MPRIS interface)."); + pthread_cancel(main_thread_id); media_player2_complete_quit(skeleton, invocation); return TRUE; } diff --git a/player.c b/player.c index ff115064..ff0f7392 100644 --- a/player.c +++ b/player.c @@ -785,12 +785,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { int notified_buffer_empty = 0; // diagnostic only debug_mutex_lock(&conn->ab_mutex, 30000, 1); - - + int wait; long dac_delay = 0; // long because alsa returns a long - - pthread_cleanup_push(buffer_get_frame_cleanup_handler, (void *)conn); // undo what's been done so far + + pthread_cleanup_push(buffer_get_frame_cleanup_handler, + (void *)conn); // undo what's been done so far do { // get the time local_time_now = get_absolute_time_in_fp(); // type okay @@ -830,7 +830,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { if (conn->flush_requested == 1) { if (config.output->flush) config.output->flush(); // no cancellation points - ab_resync(conn); // no cancellation points + ab_resync(conn); // no cancellation points conn->first_packet_timestamp = 0; conn->first_packet_time_to_play = 0; conn->time_since_play_started = 0; @@ -1215,7 +1215,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { time_of_wakeup.tv_sec = sec; time_of_wakeup.tv_nsec = nsec; // pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup); - int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup); // this is a pthread cancellation point + int rc = pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, + &time_of_wakeup); // this is a pthread cancellation point if (rc != 0) debug(3, "pthread_cond_timedwait returned error code %d.", rc); #endif @@ -1231,17 +1232,17 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { } while (wait); // seq_t read = conn->ab_read; - if (!curframe->ready) { - // debug(1, "Supplying a silent frame for frame %u", read); - conn->missing_packets++; - curframe->timestamp = 0; // indicate a silent frame should be substituted - } - curframe->ready = 0; - curframe->resend_level = 0; - conn->ab_read = SUCCESSOR(conn->ab_read); - - pthread_cleanup_pop(1); - return curframe; + if (!curframe->ready) { + // debug(1, "Supplying a silent frame for frame %u", read); + conn->missing_packets++; + curframe->timestamp = 0; // indicate a silent frame should be substituted + } + curframe->ready = 0; + curframe->resend_level = 0; + conn->ab_read = SUCCESSOR(conn->ab_read); + + pthread_cleanup_pop(1); + return curframe; } static inline short shortmean(short a, short b) { @@ -1435,7 +1436,8 @@ void player_thread_cleanup_handler(void *arg) { #ifdef HAVE_DACP_CLIENT - relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more... + relinquish_dacp_server_information( + conn); // say it doesn't belong to this conversation thread any more... #else // stop watching for DACP port number stuff @@ -1468,11 +1470,11 @@ void player_thread_cleanup_handler(void *arg) { if (conn->outbuf) { free(conn->outbuf); conn->outbuf = NULL; - } + } if (conn->sbuf) { free(conn->sbuf); conn->sbuf = NULL; - } + } if (conn->tbuf) { free(conn->tbuf); conn->tbuf = NULL; @@ -1647,15 +1649,17 @@ void *player_thread_func(void *arg) { // if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) { // debug(1,"Define tbuf of length // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change)); - conn->tbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio + - conn->max_frame_size_change)); + conn->tbuf = + malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio + + conn->max_frame_size_change)); if (conn->tbuf == NULL) die("Failed to allocate memory for the transition buffer."); // initialise this, because soxr stuffing might be chosen later - conn->sbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio + - conn->max_frame_size_change)); + conn->sbuf = + malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio + + conn->max_frame_size_change)); if (conn->sbuf == NULL) die("Failed to allocate memory for the sbuf buffer."); @@ -1685,7 +1689,7 @@ void *player_thread_func(void *arg) { if (conn->dapo_private_storage) debug(1, "DACP monitor already initialised?"); else - // this does not have pthread cancellation points in it (assuming avahi doesn't) + // this does not have pthread cancellation points in it (assuming avahi doesn't) conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id); // ?? #endif @@ -1734,12 +1738,12 @@ void *player_thread_func(void *arg) { debug(3, "Set initial volume to %f.", config.airplay_volume); player_volume(config.airplay_volume, conn); // ?? int64_t frames_to_drop = 0; - - // create and start the timing, control and audio receiver threads + + // create and start the timing, control and audio receiver threads pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn); pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn); pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn); - + pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far // debug(1, "Play begin"); @@ -2144,9 +2148,9 @@ void *player_thread_func(void *arg) { case ST_soxr: #ifdef HAVE_LIBSOXR // if (amount_to_stuff) debug(1,"Soxr stuff..."); - play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf, inbuflength, - config.output_format, conn->outbuf, amount_to_stuff, - enable_dither, conn); + play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf, + inbuflength, config.output_format, conn->outbuf, + amount_to_stuff, enable_dither, conn); #endif break; } @@ -2201,8 +2205,9 @@ void *player_thread_func(void *arg) { } else { // if there is no delay procedure, or it's not working or not allowed, there can be no // synchronising - play_samples = stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format, - conn->outbuf, 0, enable_dither, conn); + play_samples = + stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format, + conn->outbuf, 0, enable_dither, conn); if (conn->outbuf == NULL) debug(1, "NULL outbuf to play -- skipping it."); else @@ -2275,28 +2280,9 @@ void *player_thread_func(void *arg) { if (at_least_one_frame_seen) { if ((config.output->delay)) { if (config.no_sync == 0) { - inform( - "|%*.1f," /* Sync error in milliseconds */ - "%*.1f," /* net correction in ppm */ - "%*.1f," /* corrections in ppm */ - "%*d," /* total packets */ - "%*llu," /* missing packets */ - "%*llu," /* late packets */ - "%*llu," /* too late packets */ - "%*llu," /* resend requests */ - "%*lli," /* min DAC queue size */ - "%*d," /* min buffer occupancy */ - "%*d", /* max buffer occupancy */ - 10, - 1000 * moving_average_sync_error / config.output_rate, - 10, moving_average_correction * 1000000 / (352 * conn->output_sample_ratio), - 10, moving_average_insertions_plus_deletions * 1000000 / - (352 * conn->output_sample_ratio), - 12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7, - conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size, - 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); - } else { inform("|%*.1f," /* Sync error in milliseconds */ + "%*.1f," /* net correction in ppm */ + "%*.1f," /* corrections in ppm */ "%*d," /* total packets */ "%*llu," /* missing packets */ "%*llu," /* late packets */ @@ -2306,11 +2292,29 @@ void *player_thread_func(void *arg) { "%*d," /* min buffer occupancy */ "%*d", /* max buffer occupancy */ 10, - 1000 * moving_average_sync_error / config.output_rate, + 1000 * moving_average_sync_error / config.output_rate, 10, + moving_average_correction * 1000000 / (352 * conn->output_sample_ratio), + 10, moving_average_insertions_plus_deletions * 1000000 / + (352 * conn->output_sample_ratio), 12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); + } else { + inform("|%*.1f," /* Sync error in milliseconds */ + "%*d," /* total packets */ + "%*llu," /* missing packets */ + "%*llu," /* late packets */ + "%*llu," /* too late packets */ + "%*llu," /* resend requests */ + "%*lli," /* min DAC queue size */ + "%*d," /* min buffer occupancy */ + "%*d", /* max buffer occupancy */ + 10, + 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7, + conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7, + conn->resend_requests, 7, minimum_dac_queue_size, 5, + minimum_buffer_occupancy, 5, maximum_buffer_occupancy); } } else { inform("|%*.1f," /* Sync error in milliseconds */ @@ -2322,10 +2326,10 @@ void *player_thread_func(void *arg) { "%*d," /* min buffer occupancy */ "%*d", /* max buffer occupancy */ 10, - 1000 * moving_average_sync_error / config.output_rate, - 12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7, - conn->too_late_packets, 7, conn->resend_requests, 5, - minimum_buffer_occupancy, 5, maximum_buffer_occupancy); + 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7, + conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7, + conn->resend_requests, 5, minimum_buffer_occupancy, 5, + maximum_buffer_occupancy); } } else { inform("No frames received in the last sampling interval."); @@ -2339,73 +2343,74 @@ void *player_thread_func(void *arg) { } } } - - debug(1,"This should never be called."); - -/* all done in the cleanup... - - debug(3, "Connection %d: player thread main loop exit.", conn->connection_number); - - if (config.statistics_requested) { - int rawSeconds = (int)difftime(time(NULL), conn->playstart); - int elapsedHours = rawSeconds / 3600; - int elapsedMin = (rawSeconds / 60) % 60; - int elapsedSec = rawSeconds % 60; - inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin, - elapsedSec); - } - -#ifdef HAVE_DACP_CLIENT - relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread any more... + debug(1, "This should never be called."); -#else - // stop watching for DACP port number stuff - // this is only used for compatability, if dacp stuff isn't enabled. - if (conn->dapo_private_storage) { - mdns_dacp_dont_monitor(conn->dapo_private_storage); - conn->dapo_private_storage = NULL; - } else { - debug(2, "DACP Monitor already stopped"); - } -#endif + /* all done in the cleanup... - debug(2, "Cancelling timing, control and audio threads..."); - debug(2, "Cancel timing thread."); - pthread_cancel(rtp_timing_thread); - debug(2, "Join timing thread."); - pthread_join(rtp_timing_thread, NULL); - debug(2, "Timing thread terminated."); - debug(2, "Cancel control thread."); - pthread_cancel(rtp_control_thread); - debug(2, "Join control thread."); - pthread_join(rtp_control_thread, NULL); - debug(2, "Control thread terminated."); - debug(2, "Cancel audio thread."); - pthread_cancel(rtp_audio_thread); - debug(2, "Join audio thread."); - pthread_join(rtp_audio_thread, NULL); - debug(2, "Audio thread terminated."); - clear_reference_timestamp(conn); - conn->rtp_running = 0; + debug(3, "Connection %d: player thread main loop exit.", conn->connection_number); - debug(3, "Connection %d: stopping output device.", conn->connection_number); + if (config.statistics_requested) { + int rawSeconds = (int)difftime(time(NULL), conn->playstart); + int elapsedHours = rawSeconds / 3600; + int elapsedMin = (rawSeconds / 60) % 60; + int elapsedSec = rawSeconds % 60; + inform("Playback Stopped. Total playing time %02d:%02d:%02d.", elapsedHours, elapsedMin, + elapsedSec); + } - if (config.output->stop) - config.output->stop(); + #ifdef HAVE_DACP_CLIENT - debug(2, "Freeing audio buffers and decoders."); + relinquish_dacp_server_information(conn); // say it doesn't belong to this conversation thread + any more... - free_audio_buffers(conn); - terminate_decoders(conn); - debug(2, "Connection %d: player thread terminated.", conn->connection_number); - if (outbuf) - free(outbuf); - if (tbuf) - free(tbuf); - if (sbuf) - free(sbuf); - */ + #else + // stop watching for DACP port number stuff + // this is only used for compatability, if dacp stuff isn't enabled. + if (conn->dapo_private_storage) { + mdns_dacp_dont_monitor(conn->dapo_private_storage); + conn->dapo_private_storage = NULL; + } else { + debug(2, "DACP Monitor already stopped"); + } + #endif + + debug(2, "Cancelling timing, control and audio threads..."); + debug(2, "Cancel timing thread."); + pthread_cancel(rtp_timing_thread); + debug(2, "Join timing thread."); + pthread_join(rtp_timing_thread, NULL); + debug(2, "Timing thread terminated."); + debug(2, "Cancel control thread."); + pthread_cancel(rtp_control_thread); + debug(2, "Join control thread."); + pthread_join(rtp_control_thread, NULL); + debug(2, "Control thread terminated."); + debug(2, "Cancel audio thread."); + pthread_cancel(rtp_audio_thread); + debug(2, "Join audio thread."); + pthread_join(rtp_audio_thread, NULL); + debug(2, "Audio thread terminated."); + clear_reference_timestamp(conn); + conn->rtp_running = 0; + + debug(3, "Connection %d: stopping output device.", conn->connection_number); + + if (config.output->stop) + config.output->stop(); + + debug(2, "Freeing audio buffers and decoders."); + + free_audio_buffers(conn); + terminate_decoders(conn); + debug(2, "Connection %d: player thread terminated.", conn->connection_number); + if (outbuf) + free(outbuf); + if (tbuf) + free(tbuf); + if (sbuf) + free(sbuf); + */ pthread_cleanup_pop(1); pthread_exit(NULL); } @@ -2413,7 +2418,8 @@ void *player_thread_func(void *arg) { // takes the volume as specified by the airplay protocol void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) { - // no cancellation points here if we assume that the mute call to the back end has no cancellation points + // no cancellation points here if we assume that the mute call to the back end has no cancellation + // points // The volume ranges -144.0 (mute) or -30 -- 0. See // http://git.zx2c4.com/Airtunes2/about/#setting-volume @@ -2578,9 +2584,9 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c if (config.ignore_volume_control == 1) scaled_attenuation = max_db; else if (config.volume_control_profile == VCP_standard) - scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points + scaled_attenuation = vol2attn(airplay_volume, max_db, min_db); // no cancellation points else if (config.volume_control_profile == VCP_flat) - scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points + scaled_attenuation = flat_vol2attn(airplay_volume, max_db, min_db); // no cancellation points else debug(1, "Unrecognised volume control profile"); @@ -2615,7 +2621,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c // %f",software_attenuation,temp_fix_volume,airplay_volume); conn->fix_volume = temp_fix_volume; - memory_barrier(); // no cancellation points + memory_barrier(); // no cancellation points if (config.loudness) loudness_set_volume(software_attenuation / 100); diff --git a/player.h b/player.h index 295b0ccd..99dcecb8 100644 --- a/player.h +++ b/player.h @@ -74,9 +74,9 @@ typedef struct { // otherwise int64_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero // otherwise - + int fd; - int authorized; // set if a password is required and has been supplied + int authorized; // set if a password is required and has been supplied char *auth_nonce; // the session nonce, if needed stream_cfg stream; SOCKADDR remote, local; diff --git a/rtsp.c b/rtsp.c index 5b5a3428..2c056016 100644 --- a/rtsp.c +++ b/rtsp.c @@ -1889,7 +1889,7 @@ authenticate: } void rtsp_conversation_thread_cleanup_function(void *arg) { - debug(1,"rtsp_conversation_thread_func_cleanup_function called."); + debug(1, "rtsp_conversation_thread_func_cleanup_function called."); rtsp_conn_info *conn = (rtsp_conn_info *)arg; if (conn->fd > 0) close(conn->fd); @@ -1923,10 +1923,10 @@ void rtsp_conversation_thread_cleanup_function(void *arg) { rc = pthread_mutex_destroy(&conn->flush_mutex); if (rc) debug(1, "Connection %d: error %d destroying flush_mutex.", conn->connection_number, rc); - } +} void msg_cleanup_function(void *arg) { - debug(1,"msg_cleanup_function called."); + debug(1, "msg_cleanup_function called."); msg_free((rtsp_message *)arg); } @@ -1961,14 +1961,14 @@ static void *rtsp_conversation_thread_func(void *pconn) { int rtsp_read_request_attempt_count = 1; // 1 means exit immediately rtsp_message *req, *resp; - pthread_cleanup_push(rtsp_conversation_thread_cleanup_function,(void *)conn); + pthread_cleanup_push(rtsp_conversation_thread_cleanup_function, (void *)conn); while (conn->stop == 0) { int debug_level = 3; // for printing the request and response - reply = rtsp_read_request(conn,&req); + reply = rtsp_read_request(conn, &req); if (reply == rtsp_read_request_response_ok) { - pthread_cleanup_push(msg_cleanup_function,(void*)req); + pthread_cleanup_push(msg_cleanup_function, (void *)req); resp = msg_init(); - pthread_cleanup_push(msg_cleanup_function,(void*)resp); + pthread_cleanup_push(msg_cleanup_function, (void *)resp); resp->respcode = 400; if (strcmp(req->method, "OPTIONS") != @@ -2176,6 +2176,7 @@ void rtsp_listen_loop(void) { int acceptfd; struct timeval tv; do { + pthread_testcancel(); tv.tv_sec = 60; tv.tv_usec = 0; diff --git a/shairport.c b/shairport.c index 92521107..a2a049d9 100644 --- a/shairport.c +++ b/shairport.c @@ -60,6 +60,11 @@ #include #endif +#include "common.h" +#include "mdns.h" +#include "rtp.h" +#include "rtsp.h" + #if defined(HAVE_DACP_CLIENT) #include "dacp.h" #endif @@ -80,11 +85,6 @@ #include "mpris-service.h" #endif -#include "common.h" -#include "mdns.h" -#include "rtp.h" -#include "rtsp.h" - #include #include #include @@ -1131,7 +1131,7 @@ const char *pid_file_proc(void) { } void exit_function() { - // debug(1, "exit function called..."); + debug(1, "exit function called..."); if (config.cfg) config_destroy(config.cfg); if (config.appName) @@ -1139,7 +1139,19 @@ void exit_function() { // probably should be freeing malloc'ed memory here, including strdup-created strings... } +void main_cleanup_handler(__attribute__((unused)) void *arg) { + + debug(1, "main cleanup handler called."); + shairport_shutdown(); + daemon_log(LOG_NOTICE, "Unexpected exit..."); + daemon_retval_send(0); + daemon_pid_file_remove(); + daemon_signal_done(); + exit(0); +} + int main(int argc, char **argv) { + memset((void *)&main_thread_id, 0, sizeof(main_thread_id)); fp_time_at_startup = get_absolute_time_in_fp(); fp_time_at_last_debug_message = fp_time_at_startup; // debug(1,"startup"); @@ -1362,10 +1374,11 @@ int main(int argc, char **argv) { /* Close FDs */ if (daemon_close_all(-1) < 0) { daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno)); - /* Send the error condition to the parent process */ daemon_retval_send(1); - goto finish; + + daemon_signal_done(); + return 0; } /* Create the PID file if required */ @@ -1376,12 +1389,16 @@ int main(int argc, char **argv) { if ((result != 0) && (result != -EEXIST)) { // error creating or accessing the PID file directory daemon_retval_send(3); - goto finish; + + daemon_signal_done(); + return 0; } if (daemon_pid_file_create() < 0) { daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno)); + daemon_retval_send(2); - goto finish; + daemon_signal_done(); + return 0; } } @@ -1391,11 +1408,22 @@ int main(int argc, char **argv) { /* end libdaemon stuff */ } + // int old_cancel_state = 0; + // pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); + main_thread_id = pthread_self(); + if (main_thread_id) + debug(1, "Main thread ID set up."); + else + debug(1, "Main thread is set up to be NULL!"); + signal_setup(); // make sure the program can create files that group and world can read umask(S_IWGRP | S_IWOTH); + pthread_cleanup_push(main_cleanup_handler, NULL); + config.output = audio_get_output(config.output_name); if (!config.output) { audio_ls_outputs(); @@ -1587,10 +1615,11 @@ int main(int argc, char **argv) { rtsp_listen_loop(); // should not reach this... - shairport_shutdown(); -finish: - daemon_log(LOG_NOTICE, "Unexpected exit..."); - daemon_retval_send(255); - daemon_pid_file_remove(); - return 1; + // shairport_shutdown(); + // daemon_log(LOG_NOTICE, "Unexpected exit..."); + // daemon_retval_send(0); + // daemon_pid_file_remove(); + pthread_cleanup_pop(1); + debug(1, "Odd exit point"); + pthread_exit(NULL); }