From 58ab7eea9a090ad1f2710566fd77b1f662475c21 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. (cherry picked from adit) Change-Id: Ic7b8d4c816d601d4b5467ec9c2519f3c547ae59f Signed-off-by: Laxmi Devi Signed-off-by: Timo Wischer --- common/JackControlAPI.cpp | 55 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/common/JackControlAPI.cpp b/common/JackControlAPI.cpp index c13640a9..607d1e93 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 @@ -679,16 +684,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: @@ -712,6 +757,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 1335d724970bd30c59175ce9702ecc75db45bf93 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. (cherry picked from adit commit c430be1e337f52aba8312f7d29990e190cad204a) Change-Id: Ib484bb1e126f6bff0db76d44e6e036f92f5d8806 Signed-off-by: Laxmi Devi Signed-off-by: Timo Wischer --- 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 607d1e93..75cd9ee3 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; @@ -688,18 +718,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) { @@ -707,7 +746,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; @@ -716,19 +755,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); @@ -760,7 +804,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 } @@ -982,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 3f08711a..c207047e 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 15fdfd97..99d9755c 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();