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
25class ScopedSignalHandler
26{
27public:
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	}
40private:
41	struct sigaction action;
42	struct sigaction oldAction;
43	const int signalNumber;
44};
45
46static int gSigqueueSignalHandlerCallCount = 0;
47
48static void
49SigqueueSignalHandler(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
59void
60signal_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
72void
73signal_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
85void
86signal_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
111extern "C" int
112main()
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