xref: /qemu/tests/tcg/multiarch/signals.c (revision 79854b95)
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 
21 static 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 
32 static 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  */
48 typedef struct ThreadJob ThreadJob;
49 
50 struct ThreadJob {
51     int number;
52     int sleep;
53     int count;
54 };
55 
56 static pthread_t *threads;
57 static int max_threads = 10;
58 __thread int signal_count;
59 int total_signal_count;
60 
61 static 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 
74 static 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 
88 static 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 
98 static 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 
107 static 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 
145 int main(int argc, char **argv)
146 {
147     test_signals();
148     return 0;
149 }
150