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;
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.
Members
Types
- event_loop_t — the event loop type that this watcher registers with.
- siginfo_p — a receiver type for signal parameters / information. May be a reference type.
Constructors
- signal_watcher() — default constructor.
Functions
- (#1) void add_watch(event_loop_t &eloop, int signo, int prio = DEFAULT_PRIORITY)
— register a watcher with an event loop. signo specifies the signal to watch. May throw std::bad_alloc or std::system_error. - (#2) template <typename T>
static signal_watcher<event_loop_t> *add_watch(event_loop_t &eloop, int signo, T watch_hndlr)
— add a dynamically-allocated watch with the specified callback. The watch is automatically deleted when removed. See details below. - void deregister(event_loop_t &eloop) noexcept
— request removal from the event loop. - virtual void watch_removed() noexcept — called when the watcher has been removed from the event loop.
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.
signal_watcher_impl
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:
- loop — a reference to the event loop.
- signo — the signal number.
- siginfo — the signal data associated with the delivered signal instance.
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. };
Details
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.