From fc9046998b6cdf048de57f5e55e182de095bb167 Mon Sep 17 00:00:00 2001 From: Laxmi Devi Date: Wed, 15 May 2019 11:57:52 +0530 Subject: [PATCH 1/2] JackControlAPI: Replacing sigwait with signalfd and poll This would be required so that the polling concept can be used to wait on signals as well as wait for events from the other threads. Signed-off-by: Laxmi Devi --- common/JackControlAPI.cpp | 55 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index 4d597e7d..632620e3 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -26,6 +26,11 @@ #include #endif +#ifdef __linux__ +#include +#include +#endif + #include "types.h" #include #include @@ -677,16 +682,56 @@ 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; + struct signalfd_siginfo si; + + /* Block the signals in order for signalfd to receive them */ + sigprocmask(SIG_BLOCK, &sigmask->signals, NULL); + + pfd.fd = signalfd(-1, &sigmask->signals, 0); + if(pfd.fd == -1) { + fprintf(stderr, "Jack : signalfd() failed with errno %d\n", -errno); + return; + } + pfd.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, 1, -1); + if (err < 0) { + if (errno == EINTR) { + continue; + } else { + fprintf(stderr, "Jack : poll() failed with errno %d\n", -errno); + break; + } + } else { + if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + fprintf(stderr, "Jack : poll() exited with errno %d\n", -errno); + break; + } else if ((pfd.revents & POLLIN) == 0) { + continue; + } + err = read (pfd.fd, &si, sizeof(si)); + if (err < 0) { + fprintf(stderr, "Jack : read() on signalfd failed with errno %d\n", -errno); + goto fail; + } + sig = si.ssi_signo; + fprintf(stderr, "Jack main caught signal %d\n", sig); + } #else sigwait(&sigmask->signals, &sig); - #endif fprintf(stderr, "Jack main caught signal %d\n", sig); + #endif switch (sig) { case SIGUSR1: @@ -710,6 +755,12 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) // bugs that cause segfaults etc. during shutdown. sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0); } + +#ifdef __linux__ +fail: + close(pfd.fd); +#endif + } #endif From 5435c546056ffe42ab92da46b8b8eecca240233b Mon Sep 17 00:00:00 2001 From: Laxmi Devi Date: Wed, 22 May 2019 14:17:08 +0530 Subject: [PATCH 2/2] JackControlAPI: Jack threads to notify failure to jackd by posting an event On failure, currently the jack thread exits without notifying the jackd. So jackd is just waiting for the signals, unaware of the failure. With this implementation, on error threads can post an event to jackd notifying it to to exit. Signed-off-by: Laxmi Devi --- common/JackAudioDriver.cpp | 7 +++- common/JackControlAPI.cpp | 81 +++++++++++++++++++++++++++++------- common/JackServerGlobals.cpp | 1 + common/JackServerGlobals.h | 1 + 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/common/JackAudioDriver.cpp b/common/JackAudioDriver.cpp index ac686e3a..ef7c683d 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 632620e3..26dafabb 100644 --- a/common/JackControlAPI.cpp +++ b/common/JackControlAPI.cpp @@ -29,6 +29,7 @@ #ifdef __linux__ #include #include +#include #endif #include "types.h" @@ -147,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; @@ -686,18 +716,27 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) bool waiting = true; #ifdef __linux__ int err; - struct pollfd pfd; + 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.fd = signalfd(-1, &sigmask->signals, 0); - if(pfd.fd == -1) { - fprintf(stderr, "Jack : signalfd() failed with errno %d\n", -errno); + pfd[JackSignalFD].fd = signalfd(-1, &sigmask->signals, 0); + if(pfd[JackSignalFD].fd == -1) { + fprintf(stderr, "signalfd() failed with errno %d\n", -errno); return; } - pfd.events = POLLIN; + 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) { @@ -705,7 +744,7 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) sigwait(&sigmask->signals); fprintf(stderr, "Jack main caught signal\n"); #elif defined(__linux__) - err = poll(&pfd, 1, -1); + err = poll(pfd, JackFDCount, -1); if (err < 0) { if (errno == EINTR) { continue; @@ -714,19 +753,24 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) break; } } else { - if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + 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.revents & POLLIN) == 0) { + } 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; } - err = read (pfd.fd, &si, sizeof(si)); - if (err < 0) { - fprintf(stderr, "Jack : read() on signalfd failed with errno %d\n", -errno); - goto fail; - } - sig = si.ssi_signo; - fprintf(stderr, "Jack main caught signal %d\n", sig); } #else sigwait(&sigmask->signals, &sig); @@ -758,7 +802,11 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask) #ifdef __linux__ fail: - close(pfd.fd); + for(int i = 0; i < JackFDCount; i++) { + if(pfd[i].fd != 0) { + close(pfd[i].fd); + } + } #endif } @@ -971,6 +1019,7 @@ SERVER_EXPORT jackctl_server_t * jackctl_server_create( JackServerGlobals::on_device_acquire = on_device_acquire; JackServerGlobals::on_device_release = on_device_release; + JackServerGlobals::on_failure = on_failure; if (!jackctl_drivers_load(server_ptr)) { diff --git a/common/JackServerGlobals.cpp b/common/JackServerGlobals.cpp index 16688411..592fb138 100644 --- a/common/JackServerGlobals.cpp +++ b/common/JackServerGlobals.cpp @@ -36,6 +36,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_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 beb1880f..ac5f46ed 100644 --- a/common/JackServerGlobals.h +++ b/common/JackServerGlobals.h @@ -44,6 +44,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_failure)(); /* Optional callback to be called from any thread on failure */ JackServerGlobals(); ~JackServerGlobals();