# NAME

libslack(sig) - ISO C-compliant signal handling module

# SYNOPSIS

        #include <slack/std.h>
        #include <slack/sig.h>

        typedef void signal_handler_t(int signo);
        typedef void signal_siginfo_handler_t(int signo, siginfo_t *siginfo, void *context);

        int signal_set_handler(int signo, int flags, signal_handler_t *handler);
        int signal_set_siginfo_handler(int signo, int flags, signal_siginfo_handler_t *siginfo_handler);
        int signal_addset(int signo_handled, int signo_blocked);
        int signal_received(int signo);
        int signal_raise(int signo);
        int signal_handle(int signo);
        void signal_handle_all(void);

# DESCRIPTION

This module provides functions for ISO C-compliant signal handling. ISO C-compliant signal handlers may only set a single value of type sig_atomic_t. This is a very restrictive requirement. This module allows you to specify unrestricted signal handlers while (almost) transparently enforcing ISO C compliance.

When a handled signal arrives, an ISO C-compliant signal handler is invoked to merely record the fact that the signal was received. Then, in the main thread of execution, when signal_handle(3) or signal_handle_all(3) is invoked, the client supplied signal handlers for all signals received since the last invocation of signal_handle(3) or signal_handle_all(3) are invoked.

Since the user-supplied signal handlers execute in the main thread on execution, they are not subject to the normal restrictions on signal handlers. Also, they will execute with the same signals blocked as the real signal handler.

However, this indirection doesn't apply to the more dramatic signals (i.e. `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGBUS` and `SIGSYS`) whose signal handler functions are installed directly as the real signal handlers. Signal siginfo handler functions installed with signal_set_siginfo_handler(3) are installed directly as well. In general, these handler and siginfo_handler functions probably won't be ISO C-compliant signal handler functions but as long as they are POSIX-compliant signal handler functions (which is far less restrictive) it will be fine.

`int signal_set_handler(int signo, int flags, signal_handler_t *handler)`

  Installs `handler` as the signal handler function for the signal `signo`. `flags` is used as the sa_flags field of the `struct sigaction *act` argument to sigaction(2). The actual function that is set as the signal handler is not `handler`. It is an ISO C-compliant signal handler function that just records the fact that a signal was received. `handler` will only be invoked when the client invokes signal_handle(3) or signal_handle_all(3) from the main thread of execution. So there are no restrictions on `handler`. When `handler` is invoked, the `signo` signal will be blocked. Other signals can also be blocked when `handler` is invoked using signal_addset(3) or sigaddset(3). Several signals do not allow such treatment. Behaviour upon return from their handler function is undefined (or defined, but not very pleasant). They are `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGBUS`, `SIGSEGV` and `SIGSYS`. Handler function supplied for these signals are installed as the real signal handlers. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`int signal_set_siginfo_handler(int signo, int flags, signal_siginfo_handler_t *siginfo_handler)`

  Installs `siginfo_handler` as the signal siginfo handler function for the signal `signo`. A siginfo handler takes three arguments (`int signo`, `siginfo_t *siginfo` and `void *context`), rather than the usual single argument (`int signo`). `flags` is used as the sa_flags field of the struct sigaction *act argument to sigaction(2) (combined with `SA_SIGINFO`). Unlike usual signal `handler` functions, signal siginfo_hndler functions are installed directly. So there are POSIX-imposed restrictions on `siginfo_handler`. When `siginfo_handler` is invoked, the `signo` signal will be blocked. Other signals can also be blocked when `siginfo_handler` is invoked using signal_addset(3) or sigaddset(3). On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`int signal_addset(int signo_handled, int signo_blocked)`

  Adds `signo_blocked` to the set of signals that will be blocked when the handler for signal `signo_handled` is invoked. This must not be called before the call to signal_set_handler(3) for `signo_handled` which initialises the signal set to include `signo_handled`. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`int signal_received(int signo)`

  Returns the number of times that the signal `signo` has been received since the last call to signal_handle(3) with `signo` as its argument or signal_handle_all(3). On error (i.e. `signo` is out of range), returns `-1` and sets `errno` set to `EINVAL`.

`int signal_raise(int signo)`

  Simulates the receipt of the signal specified by `signo`. On success, returns the number of unhandled `signo` signals (including this one). On error (i.e. if `signo` is out of range), returns `-1` and sets `errno` to `EINVAL`.

`int signal_handle(int signo)`

  Executes the installed signal handler for the signal `signo`. The `signo` signal (and any others added with signal_addset(3)) is blocked during the execution of the signal handler. Clears the received status of the `signo` signal. On success, returns `0`. On error, returns `-1` with `errno` set appropriately.

`void signal_handle_all(void)`

  Executes the installed signal handlers for all signals that have been received since the last call to signal_handle(3) or signal_handle_all(3). During the execution of each signal handler, the corresponding signal (and possibly others) will be blocked. Clears the received status of all signals handled.

# ERRORS

`EINVAL`

  When a signal number argument is out of range.

# MT-Level

Unsafe

# EXAMPLE

        #include <slack/std.h>
        #include <slack/sig.h>

        void hup(int signo)  { printf("SIGHUP received\n"); }
        void term(int signo) { printf("SIGTERM received\n"); exit(EXIT_SUCCESS); }

        int main(int ac, char **av)
        {
            if (signal_set_handler(SIGHUP, 0, hup) == -1)
                return EXIT_FAILURE;
            if (signal_set_handler(SIGTERM, 0, term) == -1)
                return EXIT_FAILURE;

            for (;;)
            {
                char mesg[BUFSIZ];
                ssize_t n;

                signal_handle_all();

                // Signals arriving here are lost

                while ((n = read(STDIN_FILENO, mesg, BUFSIZ)) > 0)
                    fprintf(stderr, "%*.*s", n, n, mesg);

                if (n == -1 && errno == EINTR)
                    continue;

                exit((n == -1) ? EXIT_FAILURE : EXIT_SUCCESS);
            }

            return EXIT_SUCCESS;
        }

# SEE ALSO

libslack(3), prog(3)

# AUTHOR

20210220 raf <raf@raf.org>