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