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