signal_watcher, signal_watcher_impl

    // Members of dasynq::event_loop<T> instantiation:

    class signal_watcher;

    template <class Derived> class signal_watcher_impl; // : public signal_watcher;


Brief: signal_watcher is a member type of the event_loop template class. It represents an event watcher for POSIX signal reception events; a registered signal_watcher will receive callbacks when its associated signal is received. The signal_watcher class should not be subclassed directly; the signal_watcher_impl template provides a means for subclassing.





Details and Usage

Note: also see the watcher constraints section.

A signal_watcher implementation receives notification of delivery of the chosen POSIX signal. An application should establish a separate signal_watcher for each signal it wishes to monitor.

A signal should be (and should remain) blocked in all threads prior to registration of a watcher for the signal (this can be achieved using sigprocmask or pthread_sigmask). Threads inherit their signal mask from their creator; threads created by libraries should always have all signals blocked, but there may be badly-behaved libraries which fail to adhere to this rule. Therefore, it is recommended to block required signals early in the application lifetime (before initialising other libraries) if possible.

Note that signals are consumed before the watcher callback is called. A watched signal should not be consumed by any means any other polling the event loop (i.e. should not be unblocked, and should not be consumed using sigwaitinfo or similar functions).
Note: Dasynq in general does its best to work correctly when signals are consumed outside the event loop. However on some systems, especially those lacking realtime signal extensions (such as MacOS and OpenBSD), an unavoidable race condition occurs when a watched signal is consumed in a different thread while the loop is being polled, which may lead to a deadlock).

Subclassing signal_watcher

To specify callback behaviour, signal_watcher can be subclassed — however, it should not be directly subclassed; instead, use the signal_watcher_impl implementation wrapper template.

add_watch (#2)

// member of dasynq::event_loop<T>::signal_watcher
template <typename T>
static signal_watcher<event_loop_t> *add_watch(event_loop_t &eloop, int signo, T watch_hndlr);

This variant of the add_watch function can be used to create and register a dynamically-allocated signal_watcher. The first two parameters are the same as for add_watch(#1). The watch_hndlr parameter is a function or lambda of the form:

[](event_loop_t &eloop, int signo, siginfo_p siginfo) -> rearm { ... }

It acts as the callback function for the generated watcher. The watcher will delete itself when it is removed from the event loop.

This function can throw std::system_error or std::bad_alloc on failure.


Brief: The signal_watcher_impl provides a basis for implementing signal_watcher, using the "curiously recurring template pattern". Instead of subclassing signal_watcher directly, subclass an instantiation of signal_watcher_impl with the template parameter specified as the subclass itself. For example:

class my_watcher : public event_loop_t::signal_watcher_impl<my_watcher>
    // ...

Details and Usage

The callback function must be provided in the subclass and named received, with a signature compatible with the following:

rearm received(event_loop_t & loop, int signo, siginfo_p siginfo) noexcept;

The received function must be public, but need not be virtual. It will be called with the following parameters:

The return value specifies the rearm action.

A signal_watcher_impl instantiation has no public or protected members, other than those inherited from signal_watcher, which it publicly derives from.

siginfo_p - dasynq::event_loop<T>::signal_watcher::siginfo_p

class siginfo_p   // may be a typedef
    // mandatory functions:
    int get_signo();      // si_signo : signal number
    int get_sicode();     // si_code
    pid_t get_sipid();    // si_pid
    uid_t get_siuid();    // si_uid
    void * get_siaddr();  // si_addr
    int get_sistatus();   // si_status
    int get_sival_int();  // si_value.sival_int
    void * get_sival_ptr(); // si_value.sival_ptr

    // optional functions as per POSIX:
    int get_sierrno();    // si_errno
    int get_siband();     // si_band (not available on OpenBSD)
    // Linux-only functions:
    int get_sifd();       // si_fd
    int get_sitimerid();  // si_timerid
    int get_sioverrun();  // si_overrun
    int get_sitrapno();   // si_trapno
    clock_t get_siutime(); // si_utime
    clock_t get_sistime(); // si_stime
    short get_siaddr_lsb(); // si_addr_lsb

    // Other functions may be present.


The siginfo_p type is used to pass signal data as a function parameter. It may be a reference type. It is intended to be (or be a reference to) a wrapper around the POSIX siginfo_t type; various functions are available to retrieve the standard si_-prefixed data members.

Because different platforms tend to expose different members, this type may define different functions on different platforms. However, the "mandatory" functions should be available on all platforms, and other functions which provide access to POSIX-specified data members should be available if the corresponding POSIX functionality is present.