gcleanup_unix.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gcleanup_unix.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gcleanup.h"
23 #include "gprocess.h"
24 #include "groot.h"
25 #include "glog.h"
26 #include <signal.h>
27 
28 extern "C"
29 {
30  void gcleanup_unix_handler_( int signum ) ;
31  typedef void (*Handler)( int ) ;
32 }
33 
34 namespace G
35 {
36  class CleanupImp ;
37 }
38 
43 {
44 public:
45  static void add( void (*fn)(SignalSafe,const char*) , const char * ) ;
46  static void installDefault( int ) ;
47  static void callHandlers() ;
48  static void ignore( int ) ;
49 
50 private:
51  static void init() ;
52  static void install( int , Handler ) ;
53  static void installHandler( int ) ;
54  static bool ignored( int ) ;
55 
56 private:
58  struct Link
59  {
60  void (*fn)(SignalSafe,const char*) ;
61  const char * arg ;
62  Link * next ;
63  } ;
64  static Link * m_head ;
65  static Link * m_tail ;
66 } ;
67 
68 G::CleanupImp::Link * G::CleanupImp::m_head = NULL ;
69 G::CleanupImp::Link * G::CleanupImp::m_tail = NULL ;
70 
71 // ===
72 
74 {
75  CleanupImp::ignore( SIGPIPE ) ;
76 }
77 
78 void G::Cleanup::add( void (*fn)(SignalSafe,const char*) , const char * arg )
79 {
80  if( arg != NULL )
81  CleanupImp::add( fn , arg ) ;
82 }
83 
84 // ===
85 
86 void G::CleanupImp::init()
87 {
88  // install our meta-handler for signals that normally terminate the process,
89  // except for sigpipe which we ignore
90  //
91  ignore( SIGPIPE ) ;
92  installHandler( SIGTERM ) ;
93  installHandler( SIGINT ) ;
94  installHandler( SIGHUP ) ;
95  installHandler( SIGQUIT ) ;
96  //installHandler( SIGUSR1 ) ;
97  //installHandler( SIGUSR2 ) ;
98 }
99 
100 void G::CleanupImp::add( void (*fn)(SignalSafe,const char*) , const char * arg )
101 {
102  Link * p = new Link ;
103  p->fn = fn ;
104  p->arg = arg ;
105  p->next = NULL ;
106 
107  // (this bit should be protected from signals)
108  if( m_head == NULL ) init() ;
109  if( m_tail != NULL ) m_tail->next = p ;
110  m_tail = p ;
111  if( m_head == NULL ) m_head = p ;
112 }
113 
114 void G::CleanupImp::installHandler( int signum )
115 {
116  if( ignored(signum) )
117  G_DEBUG( "G::CleanupImp::installHandler: signal " << signum << " is ignored" ) ;
118  else
119  install( signum , gcleanup_unix_handler_ ) ;
120 }
121 
123 {
124  install( signum , NULL ) ;
125 }
126 
127 bool G::CleanupImp::ignored( int signum )
128 {
129  static struct sigaction zero_action ;
130  struct sigaction action( zero_action ) ;
131  if( ::sigaction( signum , NULL , &action ) )
132  throw Cleanup::Error( "sigaction" ) ;
133  return action.sa_handler == SIG_IGN ;
134 }
135 
136 void G::CleanupImp::install( int signum , Handler fn )
137 {
138  // install the given handler, or the system default if null
139  static struct sigaction zero_action ;
140  struct sigaction action( zero_action ) ;
141  action.sa_handler = fn ? fn : SIG_DFL ;
142  if( ::sigaction( signum , &action , NULL ) && fn != NULL )
143  throw Cleanup::Error( "sigaction" ) ;
144 }
145 
146 void G::CleanupImp::ignore( int signum )
147 {
148  static struct sigaction zero_action ;
149  struct sigaction action( zero_action ) ;
150  action.sa_handler = SIG_IGN ;
151  if( ::sigaction( signum , &action , NULL ) )
152  throw Cleanup::Error( "sigaction" ) ;
153 }
154 
156 {
157  G::Root claim_root ;
158  for( const Link * p = m_head ; p != NULL ; p = p->next )
159  {
160  (*(p->fn))(SignalSafe(),p->arg) ;
161  }
162 }
163 
164 extern "C"
165 void gcleanup_unix_handler_( int signum )
166 {
167  // call the registered handler(s) and then do the system default action
168  try
169  {
170  int e = G::Process::errno_() ;
173  G::Process::errno_( e ) ;
174  ::raise( signum ) ;
175  }
176  catch(...)
177  {
178  }
179 }
180 
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:35
static void add(void(*fn)(SignalSafe, const char *), const char *)
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
void gcleanup_unix_handler_(int signum)
static void ignore(int)
static int errno_()
Returns the process's current 'errno' value.
Low-level classes.
#define G_DEBUG(expr)
Definition: glog.h:95
static void init()
An optional early-initialisation function.
static void callHandlers()
A private implementation class used by G::Cleanup.
static void installDefault(int)
void(* Handler)(int)
static void add(void(*fn)(SignalSafe, const char *), const char *arg)
Adds the given handler to the list which are to be called when the process terminates abnormally...