#include #include #include #include #include "morse.h" #define RINGSIZE 256 /* ** Ring buffer to store the morse signals. ** Each transmitted letter consists of a null-terminated string ** of '.' and '-' characters. ** We can buffer at most RINGSIZE letters. */ char ring[RINGSIZE][8]; /* ** Two indices into the ring buffer: ** - rpos: Number of the letter to be printed next. ** - wpos: Number of the letter that is currently received. ** We cannot receive more letters than the largest value of sig_atomic_t. */ volatile sig_atomic_t rpos = 0, wpos = 0; /* Number of signals received for the current character. */ volatile sig_atomic_t snum = 0; /* ** Handler for SIGUSR1 and SIGUSR2. Which one it is can be seen in sig. ** Note: Don't do I/O in a signal handler! */ void usr_handler(int sig, siginfo_t *siginfo, void *context) { if (siginfo->si_pid) { kill(siginfo->si_pid, SIGINT); } /* Not more than 6 symbols per letter possible; ignore the rest. */ if (snum >= 7) { return; } /* Write symbol in output buffer */ ring[wpos%RINGSIZE][snum++] = (sig == SIGUSR1) ? '.' : '-'; /* Always terminate the string. Gets overwritten by next symbol. */ ring[wpos%RINGSIZE][snum] = '\0'; } /* ** Handler for SIGTERM (= end of character). ** NOTE: Don't do I/O in a signal handler! */ void term_handler(int sig, siginfo_t *siginfo, void *context) { if (siginfo->si_pid) { kill(siginfo->si_pid, SIGINT); } /* move write position to the next character */ wpos++; /* reset number of signals received for this character */ snum = 0; if (wpos < 0) { /* Integer overflow. Abort. */ _exit(1); } if (wpos - rpos >= RINGSIZE) { /* Ring buffer overflow. Abort. */ _exit(2); } } int main() { struct sigaction act; act.sa_flags = SA_SIGINFO; /* signals to be blocked during processing of signal handler. */ sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGUSR1); sigaddset(&act.sa_mask, SIGUSR2); sigaddset(&act.sa_mask, SIGTERM); act.sa_sigaction = usr_handler; if (sigaction(SIGUSR1, &act, 0) < 0) { perror("sigaction(SIGUSR1)"); exit(3); } if (sigaction(SIGUSR2, &act, 0) < 0) { perror("sigaction(SIGUSR2)"); exit(3); } act.sa_sigaction = term_handler; if (sigaction(SIGTERM, &act, 0) < 0) { perror("sigaction(SIGUSR2)"); exit(3); } while (1) { /* as long as we have something to print */ while (rpos < wpos) { putchar((char) decode(ring[rpos%RINGSIZE])); rpos++; } fflush(stdout); /* don't forget */ /* Sleep while waiting. Signals will wake us up anyway. */ sleep(1); } return 0; }