diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp index ac686e3a3..ef7c683d1 100644 --- a/common/JackAudioDriver.cpp +++ b/common/JackAudioDriver.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "JackLockedEngine.h" #include "JackException.h" #include +#include "JackServerGlobals.h" using namespace std; @@ -199,7 +200,11 @@ int JackAudioDriver::Write() int JackAudioDriver::Process() { - return (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync(); + int err = (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync(); + if(err && JackServerGlobals::on_failure != NULL) { + JackServerGlobals::on_failure(); + } + return err; } /* diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index c13640a97..75cd9ee33 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -26,6 +26,12 @@ #include #endif +#ifdef __linux__ +#include +#include +#include +#endif + #include "types.h" #include #include @@ -142,6 +148,35 @@ struct jackctl_parameter jack_driver_param_constraint_desc_t * constraint_ptr; }; +#ifdef __linux__ +/** Jack file descriptors */ +typedef enum +{ + JackSignalFD, /**< @brief File descriptor to accept the signals */ + JackEventFD, /**< @brief File descriptor to accept the events from threads */ + JackFDCount /**< @brief FD count, ensure this is the last element */ +} jackctl_fd; + +static int eventFD; +#endif + +static +void +on_failure() +{ +#ifdef __linux__ + int ret = 0; + const uint64_t ev = 1; + + ret = write(eventFD, &ev, sizeof(ev)); + if (ret < 0) { + fprintf(stderr, "JackServerGlobals::on_failure : write() failed with errno %d\n", -errno); + } +#else + fprintf(stderr, "JackServerGlobals::on_failure callback called from thread\n"); +#endif +} + const char * jack_get_self_connect_mode_description(char mode) { struct jack_constraint_enum_char_descriptor * descr_ptr; @@ -679,16 +714,70 @@ jackctl_setup_signals( SERVER_EXPORT void jackctl_wait_signals(jackctl_sigmask_t * sigmask) { - int sig; + int sig = 0; bool waiting = true; +#ifdef __linux__ + int err; + struct pollfd pfd[JackFDCount]; + struct signalfd_siginfo si; + memset(pfd, 0, sizeof(pfd)); + + /* Block the signals in order for signalfd to receive them */ + sigprocmask(SIG_BLOCK, &sigmask->signals, NULL); + + pfd[JackSignalFD].fd = signalfd(-1, &sigmask->signals, 0); + if(pfd[JackSignalFD].fd == -1) { + fprintf(stderr, "signalfd() failed with errno %d\n", -errno); + return; + } + pfd[JackSignalFD].events = POLLIN; + + pfd[JackEventFD].fd = eventfd(0, EFD_NONBLOCK); + if(pfd[JackEventFD].fd == -1) { + goto fail; + } + eventFD = pfd[JackEventFD].fd; + pfd[JackEventFD].events = POLLIN; + +#endif while (waiting) { #if defined(sun) && !defined(__sun__) // SUN compiler only, to check sigwait(&sigmask->signals); + fprintf(stderr, "Jack main caught signal\n"); + #elif defined(__linux__) + err = poll(pfd, JackFDCount, -1); + if (err < 0) { + if (errno == EINTR) { + continue; + } else { + fprintf(stderr, "Jack : poll() failed with errno %d\n", -errno); + break; + } + } else { + if ((pfd[JackSignalFD].revents & (POLLERR | POLLHUP | POLLNVAL)) || + pfd[JackEventFD].revents & (POLLERR | POLLHUP | POLLNVAL)) { + fprintf(stderr, "Jack : poll() exited with errno %d\n", -errno); + break; + } else if ((pfd[JackSignalFD].revents & POLLIN) != 0) { + err = read (pfd[JackSignalFD].fd, &si, sizeof(si)); + if (err < 0) { + fprintf(stderr, "Jack : read() on signalfd failed with errno %d\n", -errno); + break; + } + sig = si.ssi_signo; + fprintf(stderr, "Jack main caught signal %d\n", sig); + } else if ((pfd[JackEventFD].revents & POLLIN) != 0) { + sig = 0; /* Received an event from one of the Jack thread */ + fprintf(stderr, "Jack main received event from child thread, Exiting\n"); + } else { + continue; + } + } #else sigwait(&sigmask->signals, &sig); - #endif fprintf(stderr, "Jack main caught signal %d\n", sig); + #endif switch (sig) { case SIGUSR1: @@ -712,6 +801,16 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) // bugs that cause segfaults etc. during shutdown. sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0); } + +#ifdef __linux__ +fail: + for(int i = 0; i < JackFDCount; i++) { + if(pfd[i].fd != 0) { + close(pfd[i].fd); + } + } +#endif + } #endif @@ -931,6 +1030,7 @@ SERVER_EXPORT jackctl_server_t * jackctl_server_create2( JackServerGlobals::on_device_acquire = on_device_acquire; JackServerGlobals::on_device_release = on_device_release; JackServerGlobals::on_device_reservation_loop = on_device_reservation_loop; + JackServerGlobals::on_failure = on_failure; if (!jackctl_drivers_load(server_ptr)) { diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp index 3f08711a6..c207047ea 100644 --- a/common/JackServerGlobals.cpp +++ b/common/JackServerGlobals.cpp @@ -37,6 +37,7 @@ std::map JackServerGlobals::fInternalsList; bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; void (* JackServerGlobals::on_device_reservation_loop)(void) = NULL; +void (* JackServerGlobals::on_failure)() = NULL; int JackServerGlobals::Start(const char* server_name, jack_driver_desc_t* driver_desc, diff --git a/common/JackServerGlobals.h b/common/JackServerGlobals.h index 15fdfd973..99d9755cf 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -45,6 +45,7 @@ struct SERVER_EXPORT JackServerGlobals static bool (* on_device_acquire)(const char* device_name); static void (* on_device_release)(const char* device_name); static void (* on_device_reservation_loop)(void); + static void (* on_failure)(); /* Optional callback to be called from any thread on failure */ JackServerGlobals(); ~JackServerGlobals();