Man Linux: Main Page and Category List

NAME

       ggRegisterCleanup,  ggUnregisterCleanup,  ggCleanupForceExit  - Cleanup
       callback facilities

SYNOPSIS

       #include <ggi/gg.h>

       typedef void (ggcleanup_func)(void *);

       int ggRegisterCleanup(ggcleanup_func *func, void *arg);

       int ggUnregisterCleanup(ggcleanup_func *func, void *arg);

       void ggCleanupForceExit(void);

DESCRIPTION

       ggRegisterCleanup registers  a  callback  function  ("handler")  to  be
       executed  when  any  abnormal  or  unexpected  program  termination  is
       imminent. The function will be called with its argument.

       ggUnregisterCleanup    cancels    a     callback     installed     with
       ggRegisterCleanup.   If  more than one exactly identical callbacks have
       been installed, the most recently installed one is canceled.

       ggCleanupForceExit may only be  called  from  within  a  LibGG  cleanup
       handler.    Once   ggCleanupForceExit   is  called,  _exit(2)  will  be
       explicitly called after all registered cleanup callbacks have completed
       by  ggExit(3),  assuming  there  is  no  error  that prevents them from
       completing.  It is not possible to cancel such a request  once  it  has
       been made.

       Cleanup  functions  are executed in LIFO order.  They are guaranteed to
       only be executed once during program termination or during ggExit(3).

       These functions are for emergency use only, and should not be used as a
       substitute to proper memory deallocation routines.  They should only be
       used to restore system state that would  otherwise  be  left  corrupted
       after an abnormal program termination, for example, a video-card timing
       mode or tty mode.  When normal termination occurs,  ggUnregisterCleanup
       should  be  called  to  systematically  remove  the emergency callbacks
       before ggExit(3) or exit(3) are called.

       Callback  functions  registered  with  ggRegisterCleanup   should   not
       themselves  invoke  (or invoke any subroutines that may in turn invoke)
       any of the LibGG locking functions  ggLockCreate(3),  ggLockDestroy(3),
       ggLock(3),  ggUnlock(3), or ggTryLock(3).  However, since callbacks are
       only invoked during emergencies,  they  should  be  ignoring  locks  in
       general.   If  a  callback  function may be used by anything other than
       LibGG, it must also be reentrant.  Callback functions can come  at  any
       time, so write them with this in mind -- make them minimal and tolerant
       of concurrent access to global read/write data and avoid accessing such
       data in the first place if it is not absolutely necessary.

       The callback functions may be called by a normal call to ggExit(3).  As
       such, it is considered best  practice  to  use  ggUnregisterCleanup  to
       remove  cleanups when gracefully deinitializing LibGG or a library that
       uses LibGG, before ggExit(3) is called.

       ggRegisterCleanup and ggUnregisterCleanup are threadsafe, however, they
       are  not  safe  to call from a thread that may be canceled during their
       execution, and they are not guaranteed to be safe to  call  from  LibGG
       tasks  or  any  other  special  context  such  as a signal handler or a
       asyncronous procedure call.  Above all they should not be  called  from
       inside a LibGG cleanup handler.

RETURN VALUE

       ggRegisterCleanup  returns  GGI_OK  on  success,  or one of these error
       codes:

       ·   GGI_EUNKNOWN;

       ·   GGI_ENOMEM;

       ·   GGI_EBUSY.

       ggUnregisterCleanup returns GGI_OK on success, or one  of  these  error
       codes:

       ·   GGI_EBUSY;

       ·   GGI_ENOTALLOC;

       ·   GGI_ENOMEM.

INTERACTION WITH UNIX SIGNALS

       On UNIX systems the LibGG cleanup facilities install signal handlers as
       per signal(3) or sigaction(2).  It is advisible to  use  LibGG  cleanup
       handlers  instead  of  UNIX  signals  for the purpose of catching fatal
       signals because they are implemented portably,  however,  this  is  not
       always  an  option  when mixing LibGG with other libraries.  When LibGG
       must be used with  other  code  that  also  installs  signal  handlers,
       consult the following section.

       LibGG  installs  signal  handlers  for those signals which are normally
       fatal to the program.  The  exact  set  of  functions  that  is  caught
       depends  on the software platform.  LibGG installs signal handlers when
       the first LibGG cleanup handler is installed.  These  may  in  fact  be
       installed  in ggInit(3) as LibGG may use cleanups internally.  The only
       way to be sure that the LibGG  signal  handlers  are  installed  is  to
       install a cleanup after ggInit(3).

       By  setting any signal handler to SIG_IGN before calling ggInit(3), the
       application can force LibGG to ignore the signal, so that cleanups  are
       not  run  when  that  particular  signal  is received.  LibGG will also
       overload any application signal handlers for  fatal  signals  that  are
       present  when it installs a signal handler.  Overloaded signal handlers
       will be run before cleanups  are  run  when  the  signal  occurs.   The
       overloaded  signal handler is not guaranteed to be called exactly as it
       would be by the main application, for example,  support  for  the  long
       form  of the signal handler prototype available through sigaction(2) on
       some systems is not yet implemented, though it may be in the future.

       If the system uses the tradition (broken) UNIX  signal  behavior  where
       signal  handlers  are  set to SIG_DFL to ’block’ additional occurances,
       this may result in rare instances where signal handlers are  reentered.
       Thus  the  signal  handler  for  a given signal may call the overloaded
       cleanup multiple times before cleanup functions are called.  This  will
       also  apply  to signal handlers that manipulate the signal mask on more
       advanced sigaction(2) based systems.

       Signals that arrive  after  that  signal  which  triggers  the  cleanup
       callbacks may have their handlers run before or during the execution of
       the cleanups.

       After ggInit(3) and ggRegisterCleanup are  called,  individual  signals
       may  be  overridden  by  application-specific signal handlers or set to
       SIG_IGN or SIG_DFL.  This will prevent LibGG cleanups  from  being  run
       when  the  signal  occurs.   Within  limits,  it  is also acceptable to
       overload the LibGG signal handler.  However it  is  not  acceptable  to
       call  the LibGG signal handler with signum equal to any signal on which
       LibGG  did  not   initially   install   the   handler   function,   and
       deinitializing  LibGG  while  overloading  its signal handler may cause
       undefined bahavior.

SHORT TUTORIAL ON WRITING DECENT SIGNAL HANDLERS

       LibGG attempts to be tolerant of badly  written  signal  handlers,  but
       consistant,  correct behavior can only be guaranteed if signal handlers
       are written within the following guidelines.  First, a  signal  handler
       must  be  written  using  sigaction  if  sigaction is available, or the
       results may not be perfect.  If sigaction is not available, the  proper
       code for a simple, overloadable signal handler is such:

       lasthandler = signal(signum, SIG_DFL));
       /* do stuff */
       if (lasthandler == SIG_DFL) signal(signum, current_handler);
       else signal(signum, lasthandler);

       This  code  looks  circumlocuitous  but  each  part  is  important  for
       maintaining overloadability in a portable fashion.  The signal  handler
       should not reinstall itself unless it detects original UNIX signals are
       in effect by detecting the automatically installed SIG_DFL, or else  it
       might   get  called  directly,  skipping  the  parent  signal  handler.
       Installing SIG_DFL temporarily should be harmless to BSD style  signals
       because  the OS is required to block stacked signals through some other
       mechanism until the signal handler returns.

       In order to overload a signal handler, again  still  dealing  with  the
       situation  where  sigaction  is  not  available,  the above code can be
       modified as such:

       lasthandler = signal(signum, SIG_DFL);
       /* do stuff */
       if (had_oldhandler) {
            signal(signum, lasthandler);
            oldhandler(signum);
       }
       if (lasthandler == SIG_DFL) signal(signum, current_handler);
       else signal(signum, lasthandler);

       This is not perfect because it may allow lasthandler  to  be  reentered
       when  used  on  a  system with the original UNIX behavior, in the short
       period between when  lasthandler  is  reinstalled  and  the  oldhandler
       installs  SIG_DFL.   However,  if  the  handlers are all reentrant this
       should work fine.  In the BSD behavior, this again is harmless  because
       other OS mechanisms prevent reentry.

       Systems  without  sigaction  are pretty cretinous and rarer these days,
       however.  When sigaction(2) is available  we  can  assume  that  signal
       handlers  do  not need to reinstall themselves as per the original UNIX
       SIG_DFL behavior.  As such no special consideration is needed to  write
       a  proper overloading/overloadable handler, however, in order to assure
       that cleanup  functions  are  only  run  once  even  in  multithreaded,
       multiprocessor  environments,  LibGG may need to temporarily overload a
       signal handler which has overloaded LibGG’s signal handler with a dummy
       pass-through  handler, and as of this writing LibGG’s behavior when the
       signal mask is altered is not yet specified and  should  be  considered
       undefined.

       Measures are taken within LibGG to limit the impact of interaction with
       badly written signal handlers that reinstall their own handler when  it
       is not needed or desired, however it is recommended that libraries that
       use such handlers be updated to use better code when compiled  on  more
       modern systems.

       One  last  note  on  stacking  signal  handlers:  When  writing  for an
       environment  where  different  libraries  may  overload  signals,   all
       libraries  must  prevent loops from forming.  It is not sufficient that
       they simply check that they never overload their  own  signal  handler,
       because  another  library  may have overloaded it already, and thus you
       may have handler A calling handler B calling handler A which then calls
       handler  B  again.   Libraries  must keep track of whether their signal
       handlers are installed or not through other means.

FALLBACK MODE

       LibGG expects some sort of signal-like system  to  be  present  in  the
       environment,  otherwise  there  is  no  way  to  implement the behavior
       described above.  When LibGG is compiled on a system that has  no  such
       support,  a  fallback  mode  is  invoked  where  cleanup  handlers  are
       registered with the atexit(3) facility, or anything it may have that is
       like  atexit(3).   It  may  not  be  possible  to  unregister  cleanups
       supported in such a way, and they will always  run  at  normal  program
       exit,  even  after  LibGG  is  exited.  There is no way for them to run
       during abnormal termination.