Jack threads to post event to jackd on error
Currently, on failure the jack threads exit without notifying the jackd, So jackd is just waiting for the signals, unaware of the failure. With the patch cbd92487a7b7cb9b14d0b0903df65aaabe74319b : sigwait() is replaced with signalfd() and poll(), so that polling can be implemented in jackd to wait on signals as well as for events from the other threads.
With the patch 3e25cb03cf39095717d10e4bbbcb12d71c299112 : eventfd() and polling() is implemented so the threads can use a on_failure callback to post an event to the jackd.
@DeviLaxmii thanks for the patch. Can you outline a scenario in which jackd can benefit from the patch? IIUC it's allowing for a better handling of jackd behavior when it has "lost" its threads under special circumstances?
A first feedback from Travis shows that the build on Mac OS doesn't seem to know signalfd.h
../common/JackControlAPI.cpp:28:10: fatal error: 'sys/signalfd.h' file not found
#include <sys/signalfd.h>
Can you outline a scenario in which jackd can benefit from the patch? IIUC it's allowing for a better handling of jackd behavior when it has "lost" its threads under special circumstances?
Currently if ALSA is unable to recover from XRUN, jack-alsa thread just throws an error and exits. But, since jackd is unaware of it, it is still alive.
And this on_failure() callback is called only in the error scenarios.
int JackAudioDriver::Process()
{
int err = (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync();
if(err && JackServerGlobals::on_failure != NULL) {
JackServerGlobals::on_failure();
}
return err;
}
A first feedback from Travis shows that the build on Mac OS doesn't seem to know signalfd.h
I have fixed it. Now the polling for signal and events is implemented only for Linux.
Diff between the previous and latest changes on the branch:
-------------------------- common/JackControlAPI.cpp --------------------------
index 68e4355..26dafab 100644
@@ -24,6 +24,9 @@
#include <stdint.h>
#include <dirent.h>
#include <pthread.h>
+#endif
+
+#ifdef __linux__
#include <poll.h>
#include <sys/signalfd.h>
#include <sys/eventfd.h>
@@ -145,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;
@@ -542,12 +574,6 @@ struct jackctl_sigmask
HANDLE wait_event;
};
-static void on_failure()
-{
- /* Do nothing */
- printf("Jack JackServerGlobals::on_failure called\n");
-}
-
static jackctl_sigmask sigmask;
static void signal_handler(int signum)
@@ -589,30 +615,6 @@ struct jackctl_sigmask
static jackctl_sigmask sigmask;
-/** 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;
-
-static
-void
-on_failure()
-{
- int ret = 0;
- const uint64_t ev = 1;
-
- fprintf(stderr, "JackServerGlobals::on_failure : posting an event to jackd\n");
- ret = write(eventFD, &ev, sizeof(ev));
- if (ret < 0) {
- fprintf(stderr, "JackServerGlobals::on_failure : write() failed with errno %d\n", -errno);
- }
-}
-
static
void
signal_handler(int sig)
@@ -712,7 +714,7 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask)
{
int sig = 0;
bool waiting = true;
-#if !defined(sun) && !defined(__sun__)
+#ifdef __linux__
int err;
struct pollfd pfd[JackFDCount];
struct signalfd_siginfo si;
@@ -741,28 +743,25 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask)
#if defined(sun) && !defined(__sun__) // SUN compiler only, to check
sigwait(&sigmask->signals);
fprintf(stderr, "Jack main caught signal\n");
- #elif defined(__sun__)
- sigwait(&sigmask->signals, &sig);
- fprintf(stderr, "Jack main caught signal %d\n", sig);
- #else
+ #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);
- goto fail;
+ 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);
- goto fail;
+ 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);
- goto fail;
+ break;
}
sig = si.ssi_signo;
fprintf(stderr, "Jack main caught signal %d\n", sig);
@@ -773,6 +772,9 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask)
continue;
}
}
+ #else
+ sigwait(&sigmask->signals, &sig);
+ fprintf(stderr, "Jack main caught signal %d\n", sig);
#endif
switch (sig) {
@@ -798,7 +800,7 @@ jackctl_wait_signals(jackctl_sigmask_t * sigmask)
sigprocmask(SIG_UNBLOCK, &sigmask->signals, 0);
}
-#if !defined(sun) && !defined(__sun__)
+#ifdef __linux__
fail:
for(int i = 0; i < JackFDCount; i++) {
if(pfd[i].fd != 0) {
Thanks for the explanation @DeviLaxmii Sounds reasonable to inform jackd when alsa thread terminated unexpectedly.