Guest User

benchmark_async_signal_handler.c

a guest
Mar 11th, 2025
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.71 KB | Source Code | 0 0
  1. #include <errno.h>
  2. #include <sched.h> /* sched_yield() */
  3. #include <signal.h>
  4. #include <stdatomic.h>
  5. #include <stdint.h> /* int64_t */
  6. #include <stdio.h>
  7. #include <string.h> /* strerror() */
  8. #include <time.h>   /* clock_gettime() */
  9. #include <unistd.h>
  10.  
  11. #define N_OF(array) (sizeof(array) / sizeof((array)[0]))
  12.  
  13. #if 1 /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) \
  14.        */
  15. #define ATOMIC _Atomic
  16. #else
  17. #define ATOMIC volatile
  18. #endif
  19.  
  20. static int c_errno(void) {
  21.   return -errno;
  22. }
  23.  
  24. static const char* c_strerror(int err) {
  25.   return strerror(err < 0 ? -err : err);
  26. }
  27.  
  28. static int c_init_failed(const char label[]) {
  29.   const int err = c_errno();
  30.   fprintf(stderr,
  31.           "error initializing POSIX subsystem: %s failed with error %s\n",
  32.           label,
  33.           c_strerror(err));
  34.   return err;
  35. }
  36.  
  37. static ATOMIC int c_sigusr1_received = 0;
  38.  
  39. static void c_sigusr1_handler(int sig_num) {
  40.   atomic_store(&c_sigusr1_received, 1);
  41. }
  42.  
  43. static int c_sigusr1_consume(void) {
  44.   return atomic_exchange(&c_sigusr1_received, 0);
  45. }
  46.  
  47. static int c_signals_init(void) {
  48.   struct sigaction action = {};
  49.   action.sa_handler       = &c_sigusr1_handler;
  50.   if (sigaction(SIGCHLD, &action, NULL) < 0) {
  51.     return c_init_failed("sigaction(SIGCHLD)");
  52.   }
  53.   return 0;
  54. }
  55.  
  56. static int c_signals_setdefault(void) {
  57.   struct sigaction action = {};
  58.   size_t           i      = 0;
  59.   action.sa_handler       = SIG_DFL;
  60.  
  61.   if (sigaction(SIGCHLD, &action, NULL) < 0) {
  62.     return c_errno();
  63.   }
  64.   return 0;
  65. }
  66.  
  67. static int c_pid_send_signal(pid_t pid, int sig) {
  68.   if (kill(pid, sig) < 0) {
  69.     return c_errno();
  70.   }
  71.   return 0;
  72. }
  73.  
  74. static int c_pid_fork(void) {
  75.   const pid_t pid = fork();
  76.   switch (pid) {
  77.     case -1: /* fork() failed */
  78.       return c_errno();
  79.     case 0: /* child */
  80.       return 0;
  81.     default: /* parent */
  82.       return pid;
  83.   }
  84. }
  85.  
  86. static int64_t c_steady_time_ns(void) {
  87.   struct timespec ts;
  88.   if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
  89.     return (int64_t)-1;
  90.   }
  91.   return ts.tv_nsec + ts.tv_sec * 1000000000;
  92. }
  93.  
  94. static ssize_t c_read(int fd, char buf[], size_t n) {
  95.   const ssize_t got = read(fd, buf, n);
  96.   return got >= 0 ? got : c_errno();
  97. }
  98.  
  99. static int c_run_child(void) {
  100.   ssize_t err;
  101.   char    buf[1];
  102.   for (;;) {
  103.     err = c_read(0, buf, sizeof(buf));
  104.     if (err > 0) {
  105.       continue;
  106.     } else if (err == 0 || (err < 0 && err != -EINTR)) {
  107.       return err;
  108.     }
  109.     if (c_sigusr1_consume()) {
  110.       fprintf(stdout, "signal handler executed in 0 ns\n");
  111.     } else {
  112.       const int64_t t1 = c_steady_time_ns();
  113.       while (!c_sigusr1_consume()) {
  114.         (void)sched_yield();
  115.       }
  116.       const int64_t t2 = c_steady_time_ns();
  117.       fprintf(stdout, "signal handler executed in %lld ns\n", (long long)(t2 - t1));
  118.     }
  119.     const int64_t t2 = c_steady_time_ns();
  120.     fflush(stdout);
  121.   }
  122. }
  123.  
  124. static int c_sleep(const int64_t s, const uint32_t ns) {
  125.   struct timespec ts;
  126.   ts.tv_sec  = s;
  127.   ts.tv_nsec = ns;
  128.   return nanosleep(&ts, NULL) < 0 ? c_errno() : 0;
  129. }
  130.  
  131. static int c_run_parent(pid_t child_pid) {
  132.   for (int i = 0; i < 10; i++) {
  133.     const int64_t t1 = c_steady_time_ns();
  134.     const int64_t t2 = c_steady_time_ns();
  135.     fprintf(stdout, "clock_gettime executed in %lld ns\n", (long long)(t2 - t1));
  136.   }
  137.   for (;;) {
  138.     (void)c_sleep(1, 0);
  139.     c_pid_send_signal(child_pid, SIGCHLD);
  140.   }
  141.   return 0;
  142. }
  143.  
  144. int main(int argc, char** argv) {
  145.   int err;
  146.   if ((err = c_signals_init()) < 0) {
  147.     return err;
  148.   }
  149. #if 1
  150.   if ((err = c_pid_fork()) < 0) {
  151.     return err;
  152.   }
  153. #endif
  154.   if (err == 0) {
  155.     return c_run_child();
  156.   } else {
  157.     return c_run_parent((pid_t)err);
  158.   }
  159. }
  160.  
Advertisement
Add Comment
Please, Sign In to add comment