WG14 threadsafe signals
Loading...
Searching...
No Matches
thrd_signal_handle.h File Reference
#include "config.h"
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
Include dependency graph for thrd_signal_handle.h:

Go to the source code of this file.

Classes

union  stdc_siginfo_value
 User defined value. More...
struct  stdc_siginfo
 A platform independent subset of siginfo_t. More...

Macros

#define SIGFENCE_GLUE(x, y)
#define SIGFENCE_RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, count, ...)
#define SIGFENCE_EXPAND_ARGS(args)
#define SIGFENCE_COUNT_ARGS_MAX8(...)
#define SIGFENCE_OVERLOAD_MACRO2(name, count)
#define SIGFENCE_OVERLOAD_MACRO1(name, count)
#define SIGFENCE_OVERLOAD_MACRO(name, count)
#define SIGFENCE_CALL_OVERLOAD(name, ...)
#define SIGFENCE_IMPL_0()
#define SIGFENCE_IMPL_1(a)
#define SIGFENCE_IMPL_2(a, b)
#define SIGFENCE_IMPL_3(a, b, c)
#define SIGFENCE_IMPL_4(a, b, c, d)
#define SIGFENCE_IMPL_5(a, b, c, d, e)
#define SIGFENCE_IMPL_6(a, b, c, d, e, f)
#define SIGFENCE_IMPL_7(a, b, c, d, e, f, g)
#define SIGFENCE_IMPL_8(a, b, c, d, e, f, g, h)
#define sigfence(...)
 A compiler-only memory barrier, including for local variables in the argument list.

Typedefs

typedef int thrd_raised_signal_error_code_t
 Typedef to a system specific error code type.
typedef struct __siginfo stdc_siginfo_siginfo_t
 A placeholder type for an OS specific siginfo_t * (POSIX) or PEXCEPTION_RECORD (Windows).
typedef ucontext_t stdc_siginfo_context_t
 A placeholder type for an OS specific ucontext_t (POSIX) or PCONTEXT (Windows).

Enumerations

enum  sig_decision_t { sig_decision_next_decider , sig_decision_resume_execution , sig_decision_invoke_recovery }
 The decision taken by the decider function. More...

Functions

void sigfence_force_escaped (int,...)
union stdc_siginfo_value sig_func_t (union stdc_siginfo_value)
 The type of the guarded function.
union stdc_siginfo_value sig_recover_t (const struct stdc_siginfo *)
 The type of the function called to recover from a signal being raised in a guarded section.
enum sig_decision_t sig_decide_t (struct stdc_siginfo *)
 The type of the function called when a signal is raised. Returns a decision of how to handle the signal.
int sigfillset_synchronous (sigset_t *set)
 THREADSAFE ASYNC-SIGNAL-SAFE Fills the set of synchronous signals for this platform.
int sigfillset_asynchronous_nondebug (sigset_t *set)
 THREADSAFE ASYNC-SIGNAL-SAFE Fills the set of non-debug asynchronous signals for this platform.
int sigfillset_asynchronous_debug (sigset_t *set)
 THREADSAFE ASYNC-SIGNAL-SAFE Fille the set of debug asynchronous signals for this platform.
union stdc_siginfo_value sigguarded (const sigset_t *signals, sig_func_t guarded, sig_recover_t recovery, sig_decide_t decider, union stdc_siginfo_value value)
 THREADSAFE USUALLY ASYNC-SIGNAL-SAFE Installs a thread-local signal guard for the calling thread, and calls the guarded function guarded.
bool stdc_raise (int signo, stdc_siginfo_siginfo_t *raw_info, stdc_siginfo_context_t *raw_context)
 THREADSAFE USUALLY ASYNC-SIGNAL-SAFE Call OUR currently installed signal decider for a signal (POSIX), or raise a Win32 structured exception (Windows), returning false if we have no decider installed for that signal.
void * siginstall (const sigset_t *guarded)
 THREADSAFE Installs, and potentially enables, the global signal handlers for the signals specified by guarded. Each signal installed is threadsafe reference counted, so this is safe to call from multiple threads or instantiate multiple times.
int siguninstall (void *i)
 THREADSAFE Uninstall a previously installed signal guard.
int siguninstall_system (int version)
 THREADSAFE Uninstall a previously system installed signal guard.
void * signal_decider_create (const sigset_t *guarded, bool callfirst, sig_decide_t decider, union stdc_siginfo_value value)
 THREADSAFE NOT REENTRANT Create a global signal continuation decider. Threadsafe with respect to other calls of this function, but not reentrant i.e. modifying the global signal continuation decider registry whilst inside a global signal continuation decider is racy, and in any case definitely not async signal handler safe. Called after all thread local handling is exhausted. Note that what you can safely do in the decider function is extremely limited, only async signal safe functions may be called.
int signal_decider_destroy (void *decider)
 THREADSAFE NOT REENTRANT Destroy a global signal continuation decider. Threadsafe with respect to other calls of this function, but not reentrant i.e. do not call whilst inside a global signal continuation decider.

Macro Definition Documentation

◆ sigfence

#define sigfence ( ...)
Value:
SIGFENCE_CALL_OVERLOAD(SIGFENCE_IMPL_, __VA_ARGS__)
#define SIGFENCE_CALL_OVERLOAD(name,...)

A compiler-only memory barrier, including for local variables in the argument list.

Definition at line 157 of file thrd_signal_handle.h.

◆ SIGFENCE_CALL_OVERLOAD

#define SIGFENCE_CALL_OVERLOAD ( name,
... )
Value:
(__VA_ARGS__))
#define SIGFENCE_COUNT_ARGS_MAX8(...)
#define SIGFENCE_OVERLOAD_MACRO(name, count)
#define SIGFENCE_GLUE(x, y)

Definition at line 92 of file thrd_signal_handle.h.

◆ SIGFENCE_COUNT_ARGS_MAX8

#define SIGFENCE_COUNT_ARGS_MAX8 ( ...)
Value:
SIGFENCE_EXPAND_ARGS((__VA_ARGS__ __VA_OPT__(, ) 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define SIGFENCE_EXPAND_ARGS(args)

Definition at line 85 of file thrd_signal_handle.h.

◆ SIGFENCE_EXPAND_ARGS

#define SIGFENCE_EXPAND_ARGS ( args)
Value:
#define SIGFENCE_RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, count,...)

Definition at line 84 of file thrd_signal_handle.h.

◆ SIGFENCE_GLUE

#define SIGFENCE_GLUE ( x,
y )
Value:
x y

Definition at line 80 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_0

#define SIGFENCE_IMPL_0 ( )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0)
void sigfence_force_escaped(int,...)

Definition at line 135 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_1

#define SIGFENCE_IMPL_1 ( a)
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a))

Definition at line 136 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_2

#define SIGFENCE_IMPL_2 ( a,
b )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b))

Definition at line 137 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_3

#define SIGFENCE_IMPL_3 ( a,
b,
c )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c))

Definition at line 139 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_4

#define SIGFENCE_IMPL_4 ( a,
b,
c,
d )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c), &(d))

Definition at line 141 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_5

#define SIGFENCE_IMPL_5 ( a,
b,
c,
d,
e )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c), &(d), &(e))

Definition at line 143 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_6

#define SIGFENCE_IMPL_6 ( a,
b,
c,
d,
e,
f )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c), &(d), &(e), \
&(f))

Definition at line 145 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_7

#define SIGFENCE_IMPL_7 ( a,
b,
c,
d,
e,
f,
g )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c), &(d), &(e), \
&(f), &(g))

Definition at line 148 of file thrd_signal_handle.h.

◆ SIGFENCE_IMPL_8

#define SIGFENCE_IMPL_8 ( a,
b,
c,
d,
e,
f,
g,
h )
Value:
WG14_SIGNALS_PREFIX(sigfence_force_escaped)(0, &(a), &(b), &(c), &(d), &(e), \
&(f), &(g), &(h))

Definition at line 151 of file thrd_signal_handle.h.

◆ SIGFENCE_OVERLOAD_MACRO

#define SIGFENCE_OVERLOAD_MACRO ( name,
count )
Value:
#define SIGFENCE_OVERLOAD_MACRO1(name, count)

Definition at line 90 of file thrd_signal_handle.h.

◆ SIGFENCE_OVERLOAD_MACRO1

#define SIGFENCE_OVERLOAD_MACRO1 ( name,
count )
Value:
#define SIGFENCE_OVERLOAD_MACRO2(name, count)

Definition at line 88 of file thrd_signal_handle.h.

◆ SIGFENCE_OVERLOAD_MACRO2

#define SIGFENCE_OVERLOAD_MACRO2 ( name,
count )
Value:
name##count

Definition at line 87 of file thrd_signal_handle.h.

◆ SIGFENCE_RETURN_ARG_COUNT

#define SIGFENCE_RETURN_ARG_COUNT ( _1_,
_2_,
_3_,
_4_,
_5_,
_6_,
_7_,
_8_,
count,
... )
Value:
count

Definition at line 81 of file thrd_signal_handle.h.

Typedef Documentation

◆ stdc_siginfo_context_t

typedef ucontext_t stdc_siginfo_context_t

A placeholder type for an OS specific ucontext_t (POSIX) or PCONTEXT (Windows).

Definition at line 215 of file thrd_signal_handle.h.

◆ stdc_siginfo_siginfo_t

typedef struct __siginfo stdc_siginfo_siginfo_t

A placeholder type for an OS specific siginfo_t * (POSIX) or PEXCEPTION_RECORD (Windows).

Definition at line 207 of file thrd_signal_handle.h.

◆ thrd_raised_signal_error_code_t

Typedef to a system specific error code type.

Definition at line 195 of file thrd_signal_handle.h.

Enumeration Type Documentation

◆ sig_decision_t

The decision taken by the decider function.

Enumerator
sig_decision_next_decider 

We have decided to do nothing.

sig_decision_resume_execution 

We have fixed the cause of the signal, please resume execution.

sig_decision_invoke_recovery 

Thread local signal deciders only: reset the stack and local state to entry to sigguarded(), and call the recovery function.

Definition at line 248 of file thrd_signal_handle.h.

Function Documentation

◆ sig_decide_t()

enum sig_decision_t sig_decide_t ( struct stdc_siginfo * )

The type of the function called when a signal is raised. Returns a decision of how to handle the signal.

◆ sig_func_t()

union stdc_siginfo_value sig_func_t ( union stdc_siginfo_value )

The type of the guarded function.

◆ sig_recover_t()

union stdc_siginfo_value sig_recover_t ( const struct stdc_siginfo * )

The type of the function called to recover from a signal being raised in a guarded section.

◆ sigfence_force_escaped()

void sigfence_force_escaped ( int ,
... )
extern

◆ sigfillset_asynchronous_debug()

int sigfillset_asynchronous_debug ( sigset_t * set)
extern

THREADSAFE ASYNC-SIGNAL-SAFE Fille the set of debug asynchronous signals for this platform.

Debug asynchronous signals are those which are delivered by the system to notify the process about some event which defaults to resulting in a core dump. This set can include platform-specific additions, however at least these POSIX signals are within this set:

SIGQUIT SIGTRAP SIGXCPU SIGXFSZ

◆ sigfillset_asynchronous_nondebug()

int sigfillset_asynchronous_nondebug ( sigset_t * set)
extern

THREADSAFE ASYNC-SIGNAL-SAFE Fills the set of non-debug asynchronous signals for this platform.

Non-debug asynchronous signals are those which are delivered by the system to notify the process about some event which does not default to resulting in a core dump. This set can include platform-specific additions, however at least these POSIX signals are within this set:

SIGALRM SIGCHLD SIGCONT SIGHUP SIGINT SIGKILL SIGSTOP SIGTERM SIGTSTP SIGTTIN SIGTTOU SIGUSR1 SIGUSR2 SIGPOLL SIGPROF SIGURG SIGVTALRM

◆ sigfillset_synchronous()

int sigfillset_synchronous ( sigset_t * set)
extern

THREADSAFE ASYNC-SIGNAL-SAFE Fills the set of synchronous signals for this platform.

Synchronous signals are those which can be raised by a thread in the course of its execution. This set can include platform-specific additions, however at least these POSIX signals are within this set:

SIGABRT SIGBUS SIGFPE SIGILL SIGPIPE SIGSEGV SIGSYS

◆ sigguarded()

union stdc_siginfo_value sigguarded ( const sigset_t * signals,
sig_func_t guarded,
sig_recover_t recovery,
sig_decide_t decider,
union stdc_siginfo_value value )
extern

THREADSAFE USUALLY ASYNC-SIGNAL-SAFE Installs a thread-local signal guard for the calling thread, and calls the guarded function guarded.

Returns
The value returned by guarded, or recovery.
Parameters
signalsThe set of signals to guard against.
guardedA function whose execution is to be guarded against signal raises.
recoveryA function to be called if a signal is raised.
deciderA function to be called to decide whether to recover from the signal and continue the execution of the guarded routine, or to abort and call the recovery routine.
valueA value to supply to the guarded routine.

By "usually async signal safe" we mean that if any function from this library has been called from the called from the calling thread, this is async signal safe. If you need to set up this library for a calling thread without doing anything else, calling stdc_raise(0, nullptr, nullptr), this will ensure the calling thread's thread local state is set up and return immediately doing nothing else.

◆ siginstall()

void * siginstall ( const sigset_t * guarded)
extern

THREADSAFE Installs, and potentially enables, the global signal handlers for the signals specified by guarded. Each signal installed is threadsafe reference counted, so this is safe to call from multiple threads or instantiate multiple times.

If guarded is null, all the standard POSIX signals are used.

POSIX only

Any existing global signal handlers are replaced with a filtering signal handler, which checks if the current kernel thread has installed a signal guard, and if so executes the guard. If no signal guard has been installed for the current kernel thread, global signal continuation handlers are executed. If none claims the signal, the previously installed signal handler is called.

After the new signal handlers have been installed, the guarded signals are globally enabled for all threads of execution. Be aware that the handlers are installed with SA_NODEFER to avoid the need to perform an expensive syscall when a signal is handled. However this may also produce surprise e.g. infinite loops.

Warning
This class is threadsafe with respect to other concurrent executions of itself, but is NOT threadsafe with respect to other code modifying the global signal handlers.

◆ signal_decider_create()

void * signal_decider_create ( const sigset_t * guarded,
bool callfirst,
sig_decide_t decider,
union stdc_siginfo_value value )
extern

THREADSAFE NOT REENTRANT Create a global signal continuation decider. Threadsafe with respect to other calls of this function, but not reentrant i.e. modifying the global signal continuation decider registry whilst inside a global signal continuation decider is racy, and in any case definitely not async signal handler safe. Called after all thread local handling is exhausted. Note that what you can safely do in the decider function is extremely limited, only async signal safe functions may be called.

Returns
An opaque pointer to the registered decider. NULL if malloc failed.
Parameters
guardedThe set of signals to be guarded against.
callfirstTrue if this decider should be called before any other. Otherwise call order is in the order of addition.
deciderA decider function, which must return true if execution is to resume, false if the next decider function should be called.
valueA user supplied value to set in the raised_signal_info passed to the decider callback.

◆ signal_decider_destroy()

int signal_decider_destroy ( void * decider)
extern

THREADSAFE NOT REENTRANT Destroy a global signal continuation decider. Threadsafe with respect to other calls of this function, but not reentrant i.e. do not call whilst inside a global signal continuation decider.

Returns
True if recognised and thus removed.

◆ siguninstall()

int siguninstall ( void * i)
extern

THREADSAFE Uninstall a previously installed signal guard.

◆ siguninstall_system()

int siguninstall_system ( int version)
extern

THREADSAFE Uninstall a previously system installed signal guard.

◆ stdc_raise()

bool stdc_raise ( int signo,
stdc_siginfo_siginfo_t * raw_info,
stdc_siginfo_context_t * raw_context )
extern

THREADSAFE USUALLY ASYNC-SIGNAL-SAFE Call OUR currently installed signal decider for a signal (POSIX), or raise a Win32 structured exception (Windows), returning false if we have no decider installed for that signal.

Note that on POSIX, we fetch OUR currently installed signal decider and call it directly. This allows us to supply custom raw_info and raw_context. Each decider in our chain will be invoked in turn until we reach whatever the signal handler was when this library was first initialised, and we hand off to that handler. If that handler was defaulted and the default handling is not to ignore, we reset the handler installation and execute pthread_kill(pthread_self(), signo) in order to invoke the default handling.

It is important to note that this call does not raise signals itself except in that final handling step as just described. Therefore, if your code overwrites the signal handlers installed by this library with a custom handler, and you wish to pass on signal handling to this library, this is the right API to call to do that.

On Windows, Win32 structured exceptions are capable of being used directly and so we do on that platform always call RaiseException().

By "usually async signal safe" we mean that if any function from this library has been called from the called from the calling thread, this is async signal safe. If you need to set up this library for a calling thread without doing anything else, specify zero for signo, this will ensure the calling thread's thread local state is set up and return immediately doing nothing else.