signals.c (3262B)
1/* 2 * linux-user signal handling tests. 3 * 4 * Copyright (c) 2021 Linaro Ltd 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9#include <stdarg.h> 10#include <stdint.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <unistd.h> 14#include <errno.h> 15#include <pthread.h> 16#include <string.h> 17#include <signal.h> 18#include <time.h> 19#include <sys/time.h> 20 21static void error1(const char *filename, int line, const char *fmt, ...) 22{ 23 va_list ap; 24 va_start(ap, fmt); 25 fprintf(stderr, "%s:%d: ", filename, line); 26 vfprintf(stderr, fmt, ap); 27 fprintf(stderr, "\n"); 28 va_end(ap); 29 exit(1); 30} 31 32static int __chk_error(const char *filename, int line, int ret) 33{ 34 if (ret < 0) { 35 error1(filename, line, "%m (ret=%d, errno=%d/%s)", 36 ret, errno, strerror(errno)); 37 } 38 return ret; 39} 40 41#define error(fmt, ...) error1(__FILE__, __LINE__, fmt, ## __VA_ARGS__) 42 43#define chk_error(ret) __chk_error(__FILE__, __LINE__, (ret)) 44 45/* 46 * Thread handling 47 */ 48typedef struct ThreadJob ThreadJob; 49 50struct ThreadJob { 51 int number; 52 int sleep; 53 int count; 54}; 55 56static pthread_t *threads; 57static int max_threads = 10; 58__thread int signal_count; 59int total_signal_count; 60 61static void *background_thread_func(void *arg) 62{ 63 ThreadJob *job = (ThreadJob *) arg; 64 65 printf("thread%d: started\n", job->number); 66 while (total_signal_count < job->count) { 67 usleep(job->sleep); 68 } 69 printf("thread%d: saw %d alarms from %d\n", job->number, 70 signal_count, total_signal_count); 71 return NULL; 72} 73 74static void spawn_threads(void) 75{ 76 int i; 77 threads = calloc(sizeof(pthread_t), max_threads); 78 79 for (i = 0; i < max_threads; i++) { 80 ThreadJob *job = calloc(sizeof(ThreadJob), 1); 81 job->number = i; 82 job->sleep = i * 1000; 83 job->count = i * 100; 84 pthread_create(threads + i, NULL, background_thread_func, job); 85 } 86} 87 88static void close_threads(void) 89{ 90 int i; 91 for (i = 0; i < max_threads; i++) { 92 pthread_join(threads[i], NULL); 93 } 94 free(threads); 95 threads = NULL; 96} 97 98static void sig_alarm(int sig, siginfo_t *info, void *puc) 99{ 100 if (sig != SIGRTMIN) { 101 error("unexpected signal"); 102 } 103 signal_count++; 104 __atomic_fetch_add(&total_signal_count, 1, __ATOMIC_SEQ_CST); 105} 106 107static void test_signals(void) 108{ 109 struct sigaction act; 110 struct itimerspec it; 111 timer_t tid; 112 struct sigevent sev; 113 114 /* Set up SIG handler */ 115 act.sa_sigaction = sig_alarm; 116 sigemptyset(&act.sa_mask); 117 act.sa_flags = SA_SIGINFO; 118 chk_error(sigaction(SIGRTMIN, &act, NULL)); 119 120 /* Create POSIX timer */ 121 sev.sigev_notify = SIGEV_SIGNAL; 122 sev.sigev_signo = SIGRTMIN; 123 sev.sigev_value.sival_ptr = &tid; 124 chk_error(timer_create(CLOCK_REALTIME, &sev, &tid)); 125 126 it.it_interval.tv_sec = 0; 127 it.it_interval.tv_nsec = 1000000; 128 it.it_value.tv_sec = 0; 129 it.it_value.tv_nsec = 1000000; 130 chk_error(timer_settime(tid, 0, &it, NULL)); 131 132 spawn_threads(); 133 134 do { 135 usleep(1000); 136 } while (total_signal_count < 2000); 137 138 printf("shutting down after: %d signals\n", total_signal_count); 139 140 close_threads(); 141 142 chk_error(timer_delete(tid)); 143} 144 145int main(int argc, char **argv) 146{ 147 test_signals(); 148 return 0; 149}