| /* Copyright (c) 2014 The Regents of the University of California |
| * Kevin Klues <klueska@cs.berkeley.edu> |
| * See LICENSE for details. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <parlib/parlib.h> |
| #include <pthread.h> |
| #include <futex.h> |
| #include <signal.h> |
| |
| // Signal handler run in vcore context which redirects signals to userspace by |
| // waking a thread waiting on a futex. Note, this does not guarantee that every |
| // signal that comes through this handler will be noticed or processed by the |
| // thread. |
| int __sigpending = 0; |
| void sig_handler(int signr) |
| { |
| __sigpending = 1; |
| futex(&__sigpending, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); |
| } |
| |
| // User level thread waiting on a futex to count signals |
| int count = 0; |
| void *count_signals(void *arg) |
| { |
| while(1) { |
| futex(&__sigpending, FUTEX_WAIT, 0, NULL, NULL, 0); |
| __sync_fetch_and_add(&count, 1); |
| __sigpending = 0; |
| } |
| } |
| |
| // Thread spamming us with signals |
| void *sig_thread(void *arg) |
| { |
| int *done = (int*)arg; |
| struct sigaction sigact = {.sa_handler = sig_handler, 0}; |
| |
| sigaction(SIGUSR1, &sigact, 0); |
| while(1) { |
| kill(getpid(), SIGUSR1); |
| cmb(); |
| if (*done) return NULL; |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int done = false; |
| |
| pthread_t pth_handle, pth_handle2; |
| // Spawn off a thread to spam us with signals |
| pthread_create(&pth_handle, NULL, &sig_thread, &done); |
| // Spawn off a thread to process those signals |
| pthread_create(&pth_handle2, NULL, &count_signals, NULL); |
| |
| // Sleep for 3 seconds by timing out on a futex |
| int dummy = 0; |
| struct timespec timeout = {.tv_sec = 3, 0}; |
| |
| futex(&dummy, FUTEX_WAIT, 0, &timeout, NULL, 0); |
| // Force the signal tread to exit |
| cmb(); |
| done = true; |
| pthread_join(pth_handle, NULL); |
| printf("count: %d\n", count); |
| return 0; |
| } |