Add a multithreaded test for SIGSTOP and SIGCONT behaviour.
authorclaudio <claudio@openbsd.org>
Mon, 7 Oct 2024 14:01:12 +0000 (14:01 +0000)
committerclaudio <claudio@openbsd.org>
Mon, 7 Oct 2024 14:01:12 +0000 (14:01 +0000)
This actually installs a SIGTSTP handler which then triggers a SIGSTOP.
Currently unlinked since both SIGSTOP and SIGCONT delivery is busted.

regress/sys/kern/signal/sig-stop2/Makefile [new file with mode: 0644]
regress/sys/kern/signal/sig-stop2/sig-stop2.c [new file with mode: 0644]

diff --git a/regress/sys/kern/signal/sig-stop2/Makefile b/regress/sys/kern/signal/sig-stop2/Makefile
new file mode 100644 (file)
index 0000000..e0a93d7
--- /dev/null
@@ -0,0 +1,7 @@
+#      $OpenBSD: Makefile,v 1.1 2024/10/07 14:01:12 claudio Exp $
+
+PROG=  sig-stop2
+
+LDADD= -lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/kern/signal/sig-stop2/sig-stop2.c b/regress/sys/kern/signal/sig-stop2/sig-stop2.c
new file mode 100644 (file)
index 0000000..9486ed9
--- /dev/null
@@ -0,0 +1,137 @@
+/*     $OpenBSD: sig-stop2.c,v 1.1 2024/10/07 14:01:12 claudio Exp $   */
+/*
+ *     Written by Artur Grabowski <art@openbsd.org> 2007 Public Domain.
+ *     Written by Claudio Jeker <claudio@openbsd.org> 2024 Public Domain.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <err.h>
+#include <signal.h>
+#include <pthread.h>
+
+#define        THREAD_COUNT    4
+
+volatile sig_atomic_t tstp_count, cont_count;
+pid_t child;
+
+static void
+tstp_handler(int sig)
+{
+       tstp_count++;
+       dprintf(STDERR_FILENO, "SIGTSTP\n");
+       kill(getpid(), SIGSTOP);
+}
+
+static void
+cont_handler(int sig)
+{
+       dprintf(STDERR_FILENO, "SIGCONT\n");
+       cont_count++;
+}
+
+static void
+alrm_handler(int sig)
+{
+       kill(child, SIGKILL);
+       dprintf(STDERR_FILENO, "timeout\n");
+       _exit(2);
+}
+
+
+static void *
+thread(void *arg)
+{
+       struct timespec ts = { .tv_sec = 2 };
+
+       while (nanosleep(&ts, &ts) != 0)
+               ;
+
+       return NULL;
+}
+
+static int
+child_main(void)
+{
+       pthread_t self, pthread[THREAD_COUNT];
+       sigset_t set;
+       int i, r;
+
+       signal(SIGTSTP, tstp_handler);
+       signal(SIGCONT, cont_handler);
+
+       sigemptyset(&set);
+       sigaddset(&set, SIGTSTP);
+       sigaddset(&set, SIGCONT);
+
+       self = pthread_self();
+       for (i = 0; i < THREAD_COUNT; i++) {
+               if ((r = pthread_create(&pthread[i], NULL, thread, NULL))) {
+                       warnc(r, "could not create thread");
+                       pthread[i] = self;
+               }
+       }
+
+       sigprocmask(SIG_BLOCK, &set, NULL);
+
+       for (i = 0; i < THREAD_COUNT; i++) {
+               if (!pthread_equal(pthread[i], self) &&
+                   (r = pthread_join(pthread[i], NULL)))
+                       warnc(r, "could not join thread");
+       }
+
+       printf("#tstp = %d #cont = %d\n", tstp_count, cont_count);
+
+       return !(tstp_count == 1 && cont_count == 1);
+}
+
+int
+main(int argc, char **argv)
+{
+       struct timespec ts = { .tv_nsec = 200 * 1000 * 1000 };
+       int status;
+
+       switch((child = fork())) {
+       case -1:
+               err(1, "fork");
+       case 0:
+               exit(child_main());
+       default:
+               break;
+       }
+
+       signal(SIGALRM, alrm_handler);
+       alarm(5);
+
+       nanosleep(&ts, NULL);
+
+       if (kill(child, SIGTSTP) == -1)
+               err(1, "kill");
+
+       if (waitpid(child, &status, WCONTINUED|WUNTRACED) <= 0)
+               err(1, "waitpid");
+
+       nanosleep(&ts, NULL);
+
+       if (kill(child, SIGCONT) == -1)
+               err(1, "kill");
+
+       if (waitpid(child, &status, WCONTINUED|WUNTRACED) <= 0)
+               err(1, "waitpid");
+
+       nanosleep(&ts, NULL);
+
+       if (waitpid(child, &status, 0) <= 0)
+               err(1, "waitpid");
+
+       if (!WIFEXITED(status))
+               err(1, "bad status: %d", status);
+
+       return WEXITSTATUS(status);
+}