qemu/tests/tcg/multiarch/signals.c
<<
>>
Prefs
   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}
 150