#define _GNU_SOURCE 1 #include #include #include #include #include #include #define sys(code) if ((code) < 0) { perror(#code); exit(1); } pthread_t mainThread; pthread_t childThread; unsigned int receipts = 0; void handler(int signo, siginfo_t* siginfo, void* context) { if (pthread_equal(pthread_self(), mainThread)) { printf("received signal in main thread\n"); __atomic_fetch_or(&receipts, 1, __ATOMIC_RELAXED); } else if (pthread_equal(pthread_self(), childThread)) { printf("received signal in child thread\n"); __atomic_fetch_or(&receipts, 2, __ATOMIC_RELAXED); } else { printf("received signal in other thread (?)\n"); } } void* threadMain(void* param) { // Send SIGUSR1 to main thread. pthread_kill(mainThread, SIGUSR1); // Give main thread time to send us SIGUSR1. usleep(100000); // Unblock SIGUSR1 to see if it gets delivered. sigset_t mask; sys(sigemptyset(&mask)); sys(sigaddset(&mask, SIGUSR1)); sys(pthread_sigmask(SIG_UNBLOCK, &mask, NULL)); return NULL; } int main() { // Register a signal handler for SIGUSR1. struct sigaction action; memset(&action, 0, sizeof(action)); action.sa_sigaction = &handler; action.sa_flags = SA_SIGINFO; sys(sigaction(SIGUSR1, &action, NULL)); // Block SIGUSR1. sigset_t mask; sys(sigemptyset(&mask)); sys(sigaddset(&mask, SIGUSR1)); sys(pthread_sigmask(SIG_BLOCK, &mask, NULL)); // Start child thread. mainThread = pthread_self(); if (pthread_create(&childThread, NULL, &threadMain, NULL) < 0) { fprintf(stderr, "pthread_create failed\n"); exit(1); } // Send SIGUSR1 to child thread. pthread_kill(childThread, SIGUSR1); // Unblock SIGUSR1 to see if it gets delivered to this thread. sys(sigemptyset(&mask)); sys(sigaddset(&mask, SIGUSR1)); sys(pthread_sigmask(SIG_UNBLOCK, &mask, NULL)); pthread_join(childThread, NULL); if (receipts == 3) { printf("both threads received signal (CORRECT)\n"); } else if (receipts == 1 || receipts == 2) { printf("only one thread received signal (WRONG)\n"); } else { printf("signal not delivered at all (WRONG)\n"); } }