signal-handler.c (3536B)
1 #include "signal-handler.h" 2 3 #include <signal.h> 4 #include <stdint.h> 5 #include <stdio.h> 6 #include <sys/signalfd.h> 7 #include <sys/types.h> 8 #include <unistd.h> 9 10 #include "block.h" 11 #include "main.h" 12 #include "timer.h" 13 14 typedef struct signalfd_siginfo signal_info; 15 16 signal_handler signal_handler_new( 17 block *const blocks, const unsigned short block_count, 18 const signal_refresh_callback refresh_callback, 19 const signal_timer_callback timer_callback) { 20 signal_handler handler = { 21 .refresh_callback = refresh_callback, 22 .timer_callback = timer_callback, 23 24 .blocks = blocks, 25 .block_count = block_count, 26 }; 27 28 return handler; 29 } 30 31 int signal_handler_init(signal_handler *const handler) { 32 signal_set set; 33 (void)sigemptyset(&set); 34 35 // Handle user-generated signal for refreshing the status. 36 (void)sigaddset(&set, REFRESH_SIGNAL); 37 38 // Handle SIGALRM generated by the timer. 39 (void)sigaddset(&set, TIMER_SIGNAL); 40 41 // Handle termination signals. 42 (void)sigaddset(&set, SIGINT); 43 (void)sigaddset(&set, SIGTERM); 44 45 for (unsigned short i = 0; i < handler->block_count; ++i) { 46 const block *const block = &handler->blocks[i]; 47 if (block->signal > 0) { 48 if (sigaddset(&set, SIGRTMIN + block->signal) != 0) { 49 (void)fprintf( 50 stderr, 51 "error: invalid or unsupported signal specified for " 52 "\"%s\" block\n", 53 block->command); 54 return 1; 55 } 56 } 57 } 58 59 // Create a signal file descriptor for epoll to watch. 60 handler->fd = signalfd(-1, &set, 0); 61 if (handler->fd == -1) { 62 (void)fprintf(stderr, 63 "error: could not create file descriptor for signals\n"); 64 return 1; 65 } 66 67 // Block all realtime and handled signals. 68 for (int i = SIGRTMIN; i <= SIGRTMAX; ++i) { 69 (void)sigaddset(&set, i); 70 } 71 (void)sigprocmask(SIG_BLOCK, &set, NULL); 72 73 return 0; 74 } 75 76 int signal_handler_deinit(signal_handler *const handler) { 77 if (close(handler->fd) != 0) { 78 (void)fprintf(stderr, 79 "error: could not close signal file descriptor\n"); 80 return 1; 81 } 82 83 return 0; 84 } 85 86 int signal_handler_process(signal_handler *const handler, timer *const timer) { 87 signal_info info; 88 const ssize_t bytes_read = read(handler->fd, &info, sizeof(info)); 89 if (bytes_read == -1) { 90 (void)fprintf(stderr, "error: could not read info of incoming signal"); 91 return 1; 92 } 93 94 const int signal = (int)info.ssi_signo; 95 switch (signal) { 96 case TIMER_SIGNAL: 97 if (handler->timer_callback(handler->blocks, handler->block_count, 98 timer) != 0) { 99 return 1; 100 } 101 return 0; 102 case REFRESH_SIGNAL: 103 if (handler->refresh_callback(handler->blocks, 104 handler->block_count) != 0) { 105 return 1; 106 } 107 return 0; 108 case SIGTERM: 109 // fall through 110 case SIGINT: 111 return 1; 112 default: 113 break; 114 } 115 116 for (unsigned short i = 0; i < handler->block_count; ++i) { 117 block *const block = &handler->blocks[i]; 118 if (block->signal == signal - SIGRTMIN) { 119 const uint8_t button = (uint8_t)info.ssi_int; 120 block_execute(block, button); 121 break; 122 } 123 } 124 125 return 0; 126 }