jack2 icon indicating copy to clipboard operation
jack2 copied to clipboard

Jack threads to post event to jackd on error

Open DeviLaxmii opened this issue 6 years ago • 4 comments

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 avatar May 21 '19 05:05 DeviLaxmii

@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>

7890 avatar May 21 '19 14:05 7890

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) {

DeviLaxmii avatar May 22 '19 11:05 DeviLaxmii

Thanks for the explanation @DeviLaxmii Sounds reasonable to inform jackd when alsa thread terminated unexpectedly.

7890 avatar May 22 '19 16:05 7890

I am also fine with this PR.

Acked-by: Timo Wischer <[email protected]>

twischer-adit avatar May 23 '19 06:05 twischer-adit