diff options
Diffstat (limited to 'redshift/signals.c')
-rw-r--r-- | redshift/signals.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/redshift/signals.c b/redshift/signals.c new file mode 100644 index 0000000..cd23773 --- /dev/null +++ b/redshift/signals.c @@ -0,0 +1,209 @@ +/*- + * redshift-ng - Automatically adjust display colour temperature according the Sun + * + * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> + * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> + * + * redshift-ng is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * redshift-ng is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with redshift-ng. If not, see <http://www.gnu.org/licenses/>. + */ +#include "common.h" + + +volatile sig_atomic_t exiting = 0; +volatile sig_atomic_t disable = 0; +volatile enum signals signals = 0; + + +/** + * Signal handler for exit signals (SIGINT, SIGTERM, SIGQUIT) + * + * @param signo The received signal + */ +static void +sigexit(int signo) +{ + exiting = 1; +#ifdef WINDOWS + signal(signo, &sigexit); +#endif + (void) signo; +} + + +#ifndef WINDOWS + +/** + * Signal handler for disable signal (SIGUSR1) + * + * @param signo The received signal + */ +static void +sigdisable(int signo) +{ + disable = 1; + (void) signo; +} + + +/** + * Signal handler for forceful exiting; installed by + * `install_forceful_exit_signal_handlers` + * + * @param signo The received signal + */ +static void +sigalrm(int signo) +{ + if (exiting || signo == SIGALRM) + exit(0); + exiting = 1; + alarm(1U); +} + + +/** + * Signal handler for SIGUSR2 + * + * @param signo The received signal + * @param info The received signal data + * @param uctx Interrupted stack context + */ +static void +sigipc(int signo, siginfo_t *info, void *uctx) +{ + int set, mask; + sigset_t sigusr2_mask; + + (void) signo; + (void) uctx; + + if (info->si_code != SI_QUEUE) + return; + + switch (info->si_value.sival_int) { + case 1: + case 2: + mask = 3 << 1; + break; + + case 5: + case 6: + mask = 3 << 5; + break; + + case 7: + case 8: + mask = 3 << 7; + break; + + case 11: + case 12: + mask = 3 << 11; + break; + + case 0: + case 3: + case 4: + case 9: + case 10: + mask = 0; + break; + + default: + return; + } + + signals |= set = 1 << info->si_value.sival_int; + signals &= ~mask | set; + + if (set == SIGNAL_ORDER_BARRIER) { + sigemptyset(&sigusr2_mask); + sigaddset(&sigusr2_mask, SIGUSR2); + if (sigprocmask(SIG_BLOCK, &sigusr2_mask, NULL)) + eprintf("sigprocmask:"); + } +} + +#endif + + +void +install_signal_handlers(void) +{ +#ifdef WINDOWS + if (signal(SIGINT, &sigexit) == SIG_ERR) + eprintf("signal SIGINT <function pointer>:"); + if (signal(SIGTERM, &sigexit) == SIG_ERR) + eprintf("signal SIGTERM <function pointer>:"); + +#else + struct sigaction sigact; + sigset_t sigset; + + memset(&sigact, 0, sizeof(sigact)); + sigemptyset(&sigset); + sigact.sa_mask = sigset; + + sigact.sa_flags = SA_NODEFER; + + sigact.sa_handler = &sigexit; + if (sigaction(SIGINT, &sigact, NULL)) + eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); + if (sigaction(SIGTERM, &sigact, NULL)) + eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); + if (sigaction(SIGQUIT, &sigact, NULL)) + eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); + + sigact.sa_handler = &sigdisable; + if (sigaction(SIGUSR1, &sigact, NULL)) + eprintf("sigaction SIGUSR1 &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=SA_NODEFER} NULL:"); + + sigact.sa_flags = 0; + + sigact.sa_handler = SIG_IGN; /* cause child processes (hooks) to be reaped automatically */ + if (sigaction(SIGCHLD, &sigact, NULL)) + eprintf("sigaction SIGCHLD &{.sa_handler=SIG_IGN, .sa_mask={}, .sa_flags=0} NULL:"); + + sigact.sa_flags = SA_SIGINFO; + + sigact.sa_sigaction = &sigipc; + if (sigaction(SIGUSR2, &sigact, NULL)) + eprintf("sigaction SIGUSR2 &{.sa_sigaction=<function pointer>, .sa_mask={}, .sa_flags=SA_SIGINFO} NULL:"); +#endif +} + + +#ifndef WINDOWS +void +install_forceful_exit_signal_handlers(void) +{ + struct sigaction sigact; + sigset_t sigset; + + exiting = 0; + memset(&sigact, 0, sizeof(sigact)); + sigemptyset(&sigset); + sigact.sa_mask = sigset; + sigact.sa_flags = 0; + sigact.sa_handler = &sigalrm; + if (sigaction(SIGINT, &sigact, NULL)) + eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGTERM, &sigact, NULL)) + eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGQUIT, &sigact, NULL)) + eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); + if (sigaction(SIGALRM, &sigact, NULL)) + eprintf("sigaction SIGALRM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:"); +} +#endif |