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