1*f758e73fSJérôme Duval /*
2*f758e73fSJérôme Duval * Copyright 2024, Haiku, Inc. All Rights Reserved.
3*f758e73fSJérôme Duval * Distributed under the terms of the MIT License.
4*f758e73fSJérôme Duval *
5*f758e73fSJérôme Duval * Authors:
6*f758e73fSJérôme Duval * Jérôme Duval, jerome.duval@gmail.com
7*f758e73fSJérôme Duval * Inspired from Android signal_test.cpp
8*f758e73fSJérôme Duval */
9*f758e73fSJérôme Duval
10*f758e73fSJérôme Duval
11*f758e73fSJérôme Duval #include <errno.h>
12*f758e73fSJérôme Duval #include <pthread.h>
13*f758e73fSJérôme Duval #include <signal.h>
14*f758e73fSJérôme Duval #include <stdio.h>
15*f758e73fSJérôme Duval #include <stdlib.h>
16*f758e73fSJérôme Duval #include <sys/cdefs.h>
17*f758e73fSJérôme Duval #include <sys/types.h>
18*f758e73fSJérôme Duval #include <unistd.h>
19*f758e73fSJérôme Duval
20*f758e73fSJérôme Duval
21*f758e73fSJérôme Duval #define ASSERT_EQ(x,y) { if (x != y) { fprintf(stderr, "assert failed %s %s\n", #x, #y); exit(1); }}
22*f758e73fSJérôme Duval #define ASSERT_ERRNO(x) ASSERT_EQ(errno, x)
23*f758e73fSJérôme Duval
24*f758e73fSJérôme Duval
25*f758e73fSJérôme Duval class ScopedSignalHandler
26*f758e73fSJérôme Duval {
27*f758e73fSJérôme Duval public:
ScopedSignalHandler(int signal,void (* handler)(int,siginfo_t *,void *))28*f758e73fSJérôme Duval ScopedSignalHandler(int signal, void (*handler)(int, siginfo_t*, void*))
29*f758e73fSJérôme Duval : signalNumber(signal)
30*f758e73fSJérôme Duval {
31*f758e73fSJérôme Duval sigemptyset(&action.sa_mask);
32*f758e73fSJérôme Duval action.sa_flags = SA_SIGINFO;
33*f758e73fSJérôme Duval action.sa_sigaction = handler;
34*f758e73fSJérôme Duval sigaction(signalNumber, &action, &oldAction);
35*f758e73fSJérôme Duval }
~ScopedSignalHandler()36*f758e73fSJérôme Duval ~ScopedSignalHandler()
37*f758e73fSJérôme Duval {
38*f758e73fSJérôme Duval sigaction(signalNumber, &oldAction, NULL);
39*f758e73fSJérôme Duval }
40*f758e73fSJérôme Duval private:
41*f758e73fSJérôme Duval struct sigaction action;
42*f758e73fSJérôme Duval struct sigaction oldAction;
43*f758e73fSJérôme Duval const int signalNumber;
44*f758e73fSJérôme Duval };
45*f758e73fSJérôme Duval
46*f758e73fSJérôme Duval static int gSigqueueSignalHandlerCallCount = 0;
47*f758e73fSJérôme Duval
48*f758e73fSJérôme Duval static void
SigqueueSignalHandler(int signum,siginfo_t * info,void *)49*f758e73fSJérôme Duval SigqueueSignalHandler(int signum, siginfo_t* info, void*)
50*f758e73fSJérôme Duval {
51*f758e73fSJérôme Duval ASSERT_EQ(SIGALRM, signum);
52*f758e73fSJérôme Duval ASSERT_EQ(SIGALRM, info->si_signo);
53*f758e73fSJérôme Duval ASSERT_EQ(SI_QUEUE, info->si_code);
54*f758e73fSJérôme Duval ASSERT_EQ(1, info->si_value.sival_int);
55*f758e73fSJérôme Duval ++gSigqueueSignalHandlerCallCount;
56*f758e73fSJérôme Duval }
57*f758e73fSJérôme Duval
58*f758e73fSJérôme Duval
59*f758e73fSJérôme Duval void
signal_sigqueue()60*f758e73fSJérôme Duval signal_sigqueue()
61*f758e73fSJérôme Duval {
62*f758e73fSJérôme Duval gSigqueueSignalHandlerCallCount = 0;
63*f758e73fSJérôme Duval ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
64*f758e73fSJérôme Duval sigval sigval = {.sival_int = 1};
65*f758e73fSJérôme Duval errno = 0;
66*f758e73fSJérôme Duval ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
67*f758e73fSJérôme Duval ASSERT_ERRNO(0);
68*f758e73fSJérôme Duval ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
69*f758e73fSJérôme Duval }
70*f758e73fSJérôme Duval
71*f758e73fSJérôme Duval
72*f758e73fSJérôme Duval void
signal_pthread_sigqueue_self()73*f758e73fSJérôme Duval signal_pthread_sigqueue_self()
74*f758e73fSJérôme Duval {
75*f758e73fSJérôme Duval gSigqueueSignalHandlerCallCount = 0;
76*f758e73fSJérôme Duval ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
77*f758e73fSJérôme Duval sigval sigval = {.sival_int = 1};
78*f758e73fSJérôme Duval errno = 0;
79*f758e73fSJérôme Duval ASSERT_EQ(0, pthread_sigqueue(pthread_self(), SIGALRM, sigval));
80*f758e73fSJérôme Duval ASSERT_ERRNO(0);
81*f758e73fSJérôme Duval ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
82*f758e73fSJérôme Duval }
83*f758e73fSJérôme Duval
84*f758e73fSJérôme Duval
85*f758e73fSJérôme Duval void
signal_pthread_sigqueue_other()86*f758e73fSJérôme Duval signal_pthread_sigqueue_other()
87*f758e73fSJérôme Duval {
88*f758e73fSJérôme Duval gSigqueueSignalHandlerCallCount = 0;
89*f758e73fSJérôme Duval ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler);
90*f758e73fSJérôme Duval sigval sigval = {.sival_int = 1};
91*f758e73fSJérôme Duval sigset_t mask;
92*f758e73fSJérôme Duval sigfillset(&mask);
93*f758e73fSJérôme Duval pthread_sigmask(SIG_SETMASK, &mask, nullptr);
94*f758e73fSJérôme Duval pthread_t thread;
95*f758e73fSJérôme Duval int rc = pthread_create(&thread, nullptr,
96*f758e73fSJérôme Duval [](void*) -> void* {
97*f758e73fSJérôme Duval sigset_t mask;
98*f758e73fSJérôme Duval sigemptyset(&mask);
99*f758e73fSJérôme Duval sigsuspend(&mask);
100*f758e73fSJérôme Duval return nullptr;
101*f758e73fSJérôme Duval }, nullptr);
102*f758e73fSJérôme Duval ASSERT_EQ(0, rc);
103*f758e73fSJérôme Duval errno = 0;
104*f758e73fSJérôme Duval ASSERT_EQ(0, pthread_sigqueue(thread, SIGALRM, sigval));
105*f758e73fSJérôme Duval ASSERT_ERRNO(0);
106*f758e73fSJérôme Duval pthread_join(thread, nullptr);
107*f758e73fSJérôme Duval ASSERT_EQ(1, gSigqueueSignalHandlerCallCount);
108*f758e73fSJérôme Duval }
109*f758e73fSJérôme Duval
110*f758e73fSJérôme Duval
111*f758e73fSJérôme Duval extern "C" int
main()112*f758e73fSJérôme Duval main()
113*f758e73fSJérôme Duval {
114*f758e73fSJérôme Duval printf("signal_sigqueue\n");
115*f758e73fSJérôme Duval signal_sigqueue();
116*f758e73fSJérôme Duval printf("signal_pthread_sigqueue_self\n");
117*f758e73fSJérôme Duval signal_pthread_sigqueue_self();
118*f758e73fSJérôme Duval printf("signal_pthread_sigqueue_other\n");
119*f758e73fSJérôme Duval signal_pthread_sigqueue_other();
120*f758e73fSJérôme Duval }
121