|  | /* 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; | 
|  | } |