Athena::Signal Class Reference

#include <SealSignal.h>

List of all members.

Public Types

typedef bool(* QuitHook )(int sig, siginfo_t *info, void *x)
typedef bool(* FatalHook )(int sig, siginfo_t *info, void *x)
typedef void(* FatalReturn )(int sig, siginfo_t *info, void *x)
typedef void(* HandlerType )(int sig, siginfo_t *info, void *extra)

Static Public Member Functions

static const char * name (int sig)
static HandlerType handler (int sig, sigset_t *mask=0)
static HandlerType handle (int sig, HandlerType handler, const sigset_t *blockMask=0)
static void revert (int sig)
static void ignore (int sig)
static void block (int sig, bool sense)
static void block (const sigset_t *mask, bool sense)
static void mask (const sigset_t *mask, sigset_t *old=0)
static int raise (int sig)
static int kill (pid_t process, int sig)
static int queue (int sig, int value=0)
static int queue (int sig, void *value)
static int queue (pid_t process, int sig, int value=0)
static int queue (pid_t process, int sig, void *value)
static bool pending (int sig)
static void pending (sigset_t *mask)
static void suspend (const sigset_t *mask)
static bool wait (int sig, siginfo_t *info=0, long msecs=-1)
static int wait (const sigset_t *mask, siginfo_t *info=0, long msecs=-1)
static void handleQuit (QuitHook hook=0)
static QuitHook handleQuitHook (void)
static void quit (int sig, siginfo_t *info, void *x)
static void handleFatal (const char *applicationName=0, IOFD fd=IOFD_INVALID, FatalHook hook=0, FatalReturn mainreturn=0, unsigned options=FATAL_DEFAULT)
static IOFD handleFatalFd (void)
static FatalHook handleFatalHook (void)
static FatalReturn handleFatalReturn (void)
static unsigned handleFatalOptions (void)
static void fatal (int sig, siginfo_t *info, void *x)
static bool fatalDump (int sig, siginfo_t *info, void *x)
static int fatalLevel (void)
static bool crashed (void)
static void dumpInfo (IOFD fd, char *buf, int sig, const siginfo_t *info)
static void dumpMemory (IOFD fd, char *buf, const void *data, size_t n)
static void dumpContext (IOFD fd, char *buf, const void *context)
static const char * describe (int sig, int code)

Static Public Attributes

static const int USR1_DUMP_CORE = 1
static const int FATAL_ON_QUIT = 2
static const int FATAL_ON_INT = 4
static const int FATAL_DUMP_CORE = 8
static const int FATAL_DUMP_SIG = 16
static const int FATAL_DUMP_STACK = 32
static const int FATAL_DUMP_LIBS = 64
static const int FATAL_DUMP_CONTEXT = 128
static const int FATAL_AUTO_EXIT = 256
static const int FATAL_DEFAULT

Detailed Description

Utilities for handling signals and fatal errors.

FIXME: POSIX single-threaded vs. multi-threaded signals?

The fatal error handling is largely inspired by code in DDD, the Data Display Debugger, and by the examples in GNU libc manual.


Member Typedef Documentation

typedef bool(* Athena::Signal::FatalHook)(int sig, siginfo_t *info, void *x)

Application hook to run in fatal(). The hook should return true if the signal handler should proceed to die. sig is the signal number, or its negative if core was dumped and, as far as can determined, successfully produced.

The fatal hooks should, if possible, perform clean-ups similar to QuitHook. The application may achieve this by actually using the quit by setting FATAL_AUTO_EXIT for handleFatal(), or it could reuse an internal function in both handlers.

typedef void(* Athena::Signal::FatalReturn)(int sig, siginfo_t *info, void *x)

Application hook to jump back to the main program from a fatal signal, for example using siglongjmp. It must never return. sig is the signal number, or its negative if core was dumped and, as far as can determined, successfully produced.

typedef void(* Athena::Signal::HandlerType)(int sig, siginfo_t *info, void *extra)

Signal handler type. This is defined explicitly and does not necessarily match the system's concept of signal handler type. If necessary, suitable trampolines are used internally to make sure the arguments make sense.

Parameters:
sig The signal number.
info Pointer to signal info. This pointer will be null on platforms that do not support POSIX signals.
extra Extra argument, e.g. the fault address. This pointer will be null on platforms that do not support POSIX signals.
typedef bool(* Athena::Signal::QuitHook)(int sig, siginfo_t *info, void *x)

Application clean-up hook invoked before quit() exits from program termination signals (SIGHUP, SIGTERM or SIGQUIT).

The handler should return true if the signal handler should proceed to exit the application. Note that certain options to handlFatal() cause this hook to be invoked for fatal signals. If such behaviour is enabled, be sure to check the crashed() status before deciding to let the application to continue.

The quit hook should take care of resetting terminal modes, killing child processes, removing lock files, and so forth.


Member Function Documentation

void Athena::Signal::block ( const sigset_t *  mask,
bool  sense 
) [static]

Block or unblock the signals specified by mask. The signals are blocked if sense is true, unblocked otherwise. This function is implemented only on systems with POSIX signals.

void Athena::Signal::block ( int  sig,
bool  sense 
) [static]

Block or unblock the signal number sig. The signal is blocked if sense is true, unblocked otherwise. This function is implemented only on systems with POSIX signals.

bool Athena::Signal::crashed ( void   )  [static]

Return the crash status indicator: true if a fatal signal has been received since the program started. Set if fatal() is entered with a fatal signal.

const char * Athena::Signal::describe ( int  sig,
int  code 
) [static]

Return the description for signal info code code for signal number sig. The code should come from siginfo_t::si_code.

void Athena::Signal::dumpContext ( IOFD  fd,
char *  buf,
const void *  context 
) [static]

Utility function to dump the process context, as obtained for instance through signal handler parameters, unix getcontext() or Windows GetThreadContext(). The output is written directly to the file descriptor fd, using buf as the formatting buffer.

void Athena::Signal::dumpInfo ( IOFD  fd,
char *  buf,
int  sig,
const siginfo_t info 
) [static]

Utility function to dump the signal info descriptor for signal sig, as obtained for instance through signal handler parameters or wait(). The output is written directly to the file descriptor fd, using buf as the formatting buffer.

void Athena::Signal::dumpMemory ( IOFD  fd,
char *  buf,
const void *  data,
size_t  n 
) [static]

Utility function to dump memory section from data for n bytes. Used to dump machine context on platforms where we don't know any better. The output is written directly to the file descriptor fd, using buf as the formatting buffer.

void Athena::Signal::fatal ( int  sig,
siginfo_t info,
void *  x 
) [static]

The fatal signal handler.

This is the handler installed by handleFatal(). Please use handleFatal() and this method instead of installing your handlers with handle(). You should be able use the handler options to specify all the control you need.

The first thing this handler does is to reinstall itself for the benefit of platforms with single-delivery signals. Immediately after that it unblocks the delivery of that signal again, in case the signal handler itself gets in trouble. The next step is to check if the current crash level (the recursion of calls to fatal(), see fatalLevel()) exceeds the predefined limit of 4; if so, we give up and let the application die with this this signal. The handler then determines whether the signal is fatal: everything except SIGINT is, and SIGINT is fatal if FATAL_ON_INT was set. If the signal is fatal, crash indicator is set (see crashed()).

If this is not a nested fatal signal, the signal is fatal, and FATAL_DUMP_CORE is set, the handler tries dump a core file. Then the handler will either attempt to quit or to return to the main program depending on FATAL_AUTO_EXIT option setting. If it is set or this is a nested fatal signal, the handler will attempt to exit as follows: the application hook (or fatalDump() in its absence) is invoked. If the hook returns true, quit() is called; otherwise the signal handler will return (and crash or get an infinite sequence of fatal signals). Note that if an application hook is registered, fataldump() is not called by default; the application hook must invoke it itself to get the dump.

If FATAL_AUTO_EXIT is not set, the application must have registered a main return hook, which will be invoked. The hook must not return, but do a siglongjmp back to the main program (it should not throw unless all code is built with options that allow exceptions to be thrown from signal handlers). Note that the fatal signal may be asynchronous and may have arisen in code left in unsafe state, so returning back to the main program may not buy you much. It may make sense for a few things like rogue null pointer dereferences or floating point exceptions.

An interactive application using a main return hook should do something like this when the sigsetjmp in the main loop returns:

  • disable "main loop entered" status
  • inform the user about the fatal error (e.g. with a popup); the popup window should be precreated for best stability
  • reset any locks the application holds, especially for user interface, including status bars, wait icons etc.
  • suggest to run a debugger against the program right there
  • in a windowing system ungrab pointer, keyboard and the server
  • unblock the signal via block(sig, false) as the operating system may think the signal is still being processed
  • add an idle processor to re-return the "main loop entered" once all pending event queue events have been drained
  • go onto processing gui events

Using a main return will most likely leak memory like a sieve, but in balance, the application just got a fatal signal and the leak is unlikely to be the greatest concern.

bool Athena::Signal::fatalDump ( int  sig,
siginfo_t info,
void *  extra 
) [static]

Dump application state information on a fatal signal.

Use this method to dump program state on a delivery of a fatal signal. fatal() uses this function automatically if no fatal handler hook has not been registered by the application.

This function attempts to be as maximally robust given that it runs in a signal handler in conditions where the program by definition is unstable. In other words, it allocates no memory and writes its output directly to a file descriptor with direct system calls. For this reason some initialisation is required; use handleFatal() to register the current application name and an output file descriptor, preferably as early in the program as possible.

The dump will consist of the following items:

  • if FATAL_DUMP_SIG option is set:
    • the application name if registered with handleFatal()
    • a title describing telling which fatal signal has been received (defined by sig, the signal number, or its negative if core has been dumped)
    • information available from the info argument
  • if FATAL_DUMP_CONTEXT option is set, all the available CPU context information like registers
  • if FATAL_DUMP_STACK option is set, the stack trace
  • if FATAL_DUMP_LIBS option is set, the list of currently loaded shared libraries

This always returns true so it is convenient for the application fatal hook to return with a call to this function.

Note that this function will not flush std::cerr or stderr before producing output, for stability reasons. If the streams have unflushed output in their buffers, that output may get mixed with unbuffered direct output from this function. If you wish to avoid this mixup and are willing to take the risk that those calls might crash, install an application hook that flushes the streams and then calls this function.

int Athena::Signal::fatalLevel ( void   )  [static]

Return the depth to which fatal() is currently recursively entered, or zero if fatal() is not currently active. Use this method in application fatal hook to decide which operations are safe to perform. For example, if the attempts to notify the user result in further signals, it is best to avoid such attempts at deeper recursion levels. Currently fatal() ceases to call the application's hooks and forces termination if the nesting level reaches 4.

Signal::HandlerType Athena::Signal::handle ( int  sig,
HandlerType  handler,
const sigset_t *  blockMask = 0 
) [static]

Install a new signal handler handler for signal number sig and returns the old handler.

This method uses the POSIX signal handling primitives if they are available, failing which falling back to the C standard signal() function.

When POSIX signals are used, signals other than sig are blocked according to blockMask (if null, no change is made) during the execution of handler. Note that the signal itself is always blocked during the handler execution and need not be mentioned in the mask explicitly. System calls are made restartable although this has little impact as this library always restarts interrupted system calls automatically despite the signal handling settings.

(FIXME: Expose option SA_NOCLDSTOP, SA_ONSTACK?) (FIXME: Threads vs. signals)

void Athena::Signal::handleFatal ( const char *  applicationName = 0,
IOFD  fd = IOFD_INVALID,
FatalHook  hook = 0,
FatalReturn  mainreturn = 0,
unsigned  options = FATAL_DEFAULT 
) [static]

Install default handler for fatal signals.

This method installs a handler for fatal signals such as floating point exceptions, illegal instructions, and memory violations. The behaviour is more precisely determined by options, a bitwise or of the option constants defined in the class declaration.

applicationName sets the application name to be used to report the signal in fatalDump(). fd sets the file descriptor to which the fatal signal message is written; by default this will be the standard error output. hook sets the pre-exit application hook to invoke, mainreturn sets the hook to return to back to the application "main loop" (i.e. ignore the signal by jumping out of the signal back to the somewhere higher up in the application).

Options left to default values will not change the current state. This allows one to re-install signal handlers without disturbing already registered information. Use this to restore handlers after some other library has meddled with the handlers.

This installs fatal() as the handler for fatal signals and on Windows for otherwise unhandled fatal structured exceptions. If FATAL_ON_QUIT is included in options, quitting related signals (see quit()) are also considered fatal. If FATAL_ON_INT is set, SIGINT is considered fatal---but see also fatal() documentation. If USR1_DUMP_CORE is set, DebugAids::coredump is registered as a handler for SIGUSR1 (please note the security risks of this option in its documentation).

A multi-threaded application should call this method in each thread. (FIXME: Calling this in one thread and blocking signals in others won't work on Linux, and in any case will probably produce non-sense stack traces (unless stacktrace can be fixed to dump the stacks of all the threads). Since the handler is always the same, I am not sure it will make the slightest difference which thread catches the signals, and on the other hand, it is best to dump the problems in the faulting thread if possible.)

IOFD Athena::Signal::handleFatalFd ( void   )  [static]

Return the file descriptor fataldump() uses for output. Registered through handleFatal().

Signal::FatalHook Athena::Signal::handleFatalHook ( void   )  [static]

Return the application fatal signal hook. Registered through handleFatal().

See also:
fatal()
unsigned Athena::Signal::handleFatalOptions ( void   )  [static]

Return the current fatal signal handling options. Set on invocation to handleFatal().

Signal::FatalReturn Athena::Signal::handleFatalReturn ( void   )  [static]

Return the application fatal signal return hook. Registered through handleFatal().

See also:
fatal().
Signal::QuitHook Athena::Signal::handleQuitHook ( void   )  [static]

Return the current application quit signal hook. Registered through handleQuit().

Signal::HandlerType Athena::Signal::handler ( int  sig,
sigset_t *  mask = 0 
) [static]

Return the current handler for signal number sig and its blocked signals in mask (if non-null).

void Athena::Signal::ignore ( int  sig  )  [static]

Ignore the signal number sig.

int Athena::Signal::kill ( pid_t  process,
int  sig 
) [static]

Send the signal sig to process identified by process. Implemented only on unixen.

void Athena::Signal::mask ( const sigset_t *  mask,
sigset_t *  old = 0 
) [static]

Set the list of currently blocked signals to mask and return the old setting in old (if non-null). This function is implemented only on systems with POSIX signals.

const char * Athena::Signal::name ( int  sig  )  [static]

Return the name of the signal number sig. The returned memory is statically allocated and must not be freed.

void Athena::Signal::pending ( sigset_t *  mask  )  [static]

Return in mask the list of signals pending for this process.

bool Athena::Signal::pending ( int  sig  )  [static]

Check if sig is pending for this process.

int Athena::Signal::queue ( pid_t  process,
int  sig,
void *  value 
) [static]

Queue signal sig with additional data value for process. Implemented only on systems with POSIX real-time signals.

int Athena::Signal::queue ( pid_t  process,
int  sig,
int  value = 0 
) [static]

Queue signal sig with additional data value for process. Implemented only on systems with POSIX real-time signals.

int Athena::Signal::queue ( int  sig,
void *  value 
) [static]

Queue signal sig for this process with additional data value. Implemented only on systems with POSIX real-time signals.

int Athena::Signal::queue ( int  sig,
int  value = 0 
) [static]

Queue signal sig for this process with additional data value. Implemented only on systems with POSIX real-time signals.

void Athena::Signal::quit ( int  sig,
siginfo_t info,
void *  x 
) [static]

The quit signal handler.

This is the handler installed by handleQuit(). Please use handleQuit() and this method instead of installing your own handlers with handle().

This handler first invokes the application hook if one was given to handleQuit(). If the hook returns true, the signal handler for this signal (number sig) is reset to its default handler, and the signal is re-raised. This causes the program to exit via the signal and have a the correct exit status.

The application should do whatever is necessary for a graceful shutdown. Note however that this signal may arrive asynchronously at any time, hence it probably isn't safe to allocate memory, use the standard output streams, and so forth. What you can do is to set a flag, return false to return back to your application, detect the flag setting and drain your current event loop, and then quit. But do note that if FATAL_AUTO_EXIT was set in call to handleFatal(), fatal() will call quit() which in turn calls the application hook. Thus the hook should make sure it returns true if the application has crashed as noted in the documentation for <<QuitHook>>.

int Athena::Signal::raise ( int  sig  )  [static]

Raise the signal number sig. Returns the exit code from the raise() system call (or kill() if raise() does not exist).

void Athena::Signal::revert ( int  sig  )  [static]

Revert the signal number sig back to its default behaviour.

void Athena::Signal::suspend ( const sigset_t *  mask  )  [static]

Temporarily replace the signal mask of the process with mask and then suspend until a signal is received.

int Athena::Signal::wait ( const sigset_t *  mask,
siginfo_t info = 0,
long  msecs = -1 
) [static]

Suspend the thread waiting for signals specified by mask for at most msecs milliseconds. If msecs is negative (the default), waits until a signal is delivered. Otherwise waits up to the specified time limit. Returns the number of the signal that was received, or -1 if the time limit expired. If info is given, fills it with the information that the handler would have otherwise been given. Note that the signals must be blocked (in a multi-threaded application in all the threads, not just the calling one) and not be ignored before calling this function; if a handler is registered, it won't be called. Implemented only on systems with POSIX real-time signals.

bool Athena::Signal::wait ( int  sig,
siginfo_t info = 0,
long  msecs = -1 
) [static]

Suspend the thread waiting for signal sig at most msecs milliseconds. If msecs is negative (the default), waits until a signal is delivered. Otherwise waits up to the specified time limit. Returns true if the signal was received. Note that the signal must be blocked (in a multi-threaded application in all the threads, not just the calling one) and not be ignored before calling this function; if a handler is registered, it won't be called. Implemented only on systems with POSIX real-time signals.


Member Data Documentation

const int Athena::Signal::FATAL_AUTO_EXIT = 256 [static]

Option to make fatal() exit via quit(). This will cause all the application clean-up hook to run.

const int Athena::Signal::FATAL_DEFAULT [static]
const int Athena::Signal::FATAL_DUMP_CONTEXT = 128 [static]

Option to make fataldump() (invoked by fatal()) to dump the machine context (registers etc.) from the fault position.

const int Athena::Signal::FATAL_DUMP_CORE = 8 [static]

Option to make fatal() dump a core file before crashing.

const int Athena::Signal::FATAL_DUMP_LIBS = 64 [static]

Option to make fataldump() (invoked by fatal()) to dump the list of currently loaded shared libraries.

const int Athena::Signal::FATAL_DUMP_SIG = 16 [static]

Option to make fataldump() (invoked by fatal()) to dump the signal name (as reported by name()).

const int Athena::Signal::FATAL_DUMP_STACK = 32 [static]

Option to make fataldump() (invoked by fatal()) to dump stack backtrace for the offending code location.

const int Athena::Signal::FATAL_ON_INT = 4 [static]

Option to make SIGINT fatal. It will still just quit, not crash.

const int Athena::Signal::FATAL_ON_QUIT = 2 [static]

Option to make SIGHUP, SIGTERM and SIGQUIT fatal instead of just quit() signals.

const int Athena::Signal::USR1_DUMP_CORE = 1 [static]

Option that instructs fatal() to call coredump() on SIGUSR1. This is merely a request to drop a core; no attempt is made to guarantee success. Failure may result for example for lack of permissions, for lack of disk space, or due to low resource limits. Please note that core files can only be created on unixen. Note also that dropping a core is a security risk and should never be enabled in setuid or setgid programs or for production applications.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 15 Apr 2017 for RootCore Packages by  doxygen 1.6.1