Drizzled Public API Documentation

signal_handler.cc
1 /*
2  Copyright (C) 2011 Brian Aker
3  Copyright (C) 2006 MySQL AB
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
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, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17 
18 #include <config.h>
19 #include <drizzled/gettext.h>
20 #include <drizzled/error.h>
21 #include <drizzled/plugin/storage_engine.h>
22 #include <drizzled/pthread_globals.h>
23 #include <drizzled/internal/my_pthread.h>
24 #include <drizzled/internal/my_sys.h>
25 #include <drizzled/plugin/daemon.h>
26 #include <drizzled/signal_handler.h>
27 #include <drizzled/session.h>
28 #include <drizzled/session/cache.h>
29 #include <drizzled/debug.h>
30 #include <drizzled/drizzled.h>
31 #include <drizzled/open_tables_state.h>
32 
33 #include <boost/thread/thread.hpp>
34 #include <boost/filesystem.hpp>
35 
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 
39 static bool kill_in_progress= false;
40 void signal_hand(void);
41 
42 namespace drizzled {
43 
44 extern int cleanup_done;
45 extern bool volatile abort_loop;
46 extern bool volatile shutdown_in_progress;
47 /* Prototypes -> all of these should be factored out into a propper shutdown */
48 extern void close_connections(void);
49 }
50 
51 using namespace drizzled;
52 
53 
54 
55 
67 static void kill_server(int sig)
68 {
69  // if there is a signal during the kill in progress, ignore the other
70  if (kill_in_progress) // Safety
71  {
72  return;
73  }
74 
75  kill_in_progress= true;
76  abort_loop= true; // This should be set
77  if (sig != 0) // 0 is not a valid signal number
78  {
79  ignore_signal(sig); /* purify inspected */
80  }
81 
82  if (sig == SIGTERM || sig == 0)
83  {
84  errmsg_printf(error::INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
85  }
86  else
87  {
88  errmsg_printf(error::ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
89  }
90 
91  close_connections();
92  clean_up(1);
93 }
94 
95 
97 void signal_hand()
98 {
99  sigset_t set;
100  int sig;
101  internal::my_thread_init(); // Init new thread
102  signal_thread_in_use= true;
103 
104  if ((drizzled::getDebug().test(drizzled::debug::ALLOW_SIGINT)))
105  {
106  (void) sigemptyset(&set); // Setup up SIGINT for debug
107  (void) sigaddset(&set,SIGINT); // For debugging
108  (void) pthread_sigmask(SIG_UNBLOCK, &set, NULL);
109  }
110  (void) sigemptyset(&set); // Setup up SIGINT for debug
111 #ifndef IGNORE_SIGHUP_SIGQUIT
112  if (sigaddset(&set,SIGQUIT))
113  {
114  std::cerr << "failed setting sigaddset() with SIGQUIT\n";
115  }
116 
117  if (sigaddset(&set,SIGHUP))
118  {
119  std::cerr << "failed setting sigaddset() with SIGHUP\n";
120  }
121 #endif
122 
123  if (sigaddset(&set,SIGTERM))
124  {
125  std::cerr << "failed setting sigaddset() with SIGTERM\n";
126  }
127 
128  if (sigaddset(&set,SIGTSTP))
129  {
130  std::cerr << "failed setting sigaddset() with SIGTSTP\n";
131  }
132 
133  /*
134  signal to init that we are ready
135  This works by waiting for init to free mutex,
136  after which we signal it that we are ready.
137  At this pointer there is no other threads running, so there
138  should not be any other pthread_cond_signal() calls.
139 
140  We call lock/unlock to out wait any thread/session which is
141  dieing. Since only comes from this code, this should be safe.
142  (Asked MontyW over the phone about this.) -Brian
143 
144  */
145  session::Cache::mutex().lock();
146  session::Cache::mutex().unlock();
147  COND_thread_count.notify_all();
148 
149  if (pthread_sigmask(SIG_BLOCK, &set, NULL))
150  {
151  std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
152  }
153 
154  for (;;)
155  {
156  if (shutdown_in_progress and abort_loop == false)
157  {
158  sig= SIGTERM;
159  }
160  else
161  {
162  while (sigwait(&set, &sig) == EINTR)
163  { }
164  }
165 
166  if (cleanup_done)
167  {
168  signal_thread_in_use= false;
169  return;
170  }
171  switch (sig)
172  {
173  case SIGTERM:
174  case SIGQUIT:
175  case SIGKILL:
176  case SIGTSTP:
177  /* switch to the old log message processing */
178  if (abort_loop == false)
179  {
180  abort_loop= true; // mark abort for threads
181  kill_server(sig); // MIT THREAD has a alarm thread
182  }
183  break;
184  case SIGHUP:
185  if (abort_loop == false)
186  {
187  g_refresh_version++;
188  drizzled::plugin::StorageEngine::flushLogs(NULL);
189  }
190  break;
191  }
192  }
193 }
194 
197 {
198  boost::thread thread;
199 
200 public:
201  SignalHandler() :
202  drizzled::plugin::Daemon("signal_handler")
203  {
204  // @todo fix spurious wakeup issue
205  boost::mutex::scoped_lock scopedLock(session::Cache::mutex());
206  thread= boost::thread(signal_hand);
207  signal_thread= thread.native_handle();
208  COND_thread_count.wait(scopedLock);
209  }
210 
216  {
217  /*
218  Wait up to 100000 micro-seconds for signal thread to die. We use this mainly to
219  avoid getting warnings that internal::my_thread_end has not been called
220  */
221  bool completed= false;
222  /*
223  * We send SIGTERM and then do a timed join. If that fails we will on
224  * the last pthread_kill() call SIGTSTP. OSX (and FreeBSD) seem to
225  * prefer this. -Brian
226  */
227  uint32_t count= 2; // How many times to try join and see if the caller died.
228  while (completed == false and count--)
229  {
230  int signal= count == 1 ? SIGTSTP : SIGTERM;
231 
232  if (int error= pthread_kill(thread.native_handle(), signal))
233  {
234  char buffer[1024]; // No reason for number;
235  strerror_r(error, buffer, sizeof(buffer));
236  std::cerr << "pthread_kill() error on shutdown of signal thread (" << buffer << ")\n";
237  break;
238  }
239  else
240  {
241  boost::posix_time::milliseconds duration(100);
242  completed= thread.timed_join(duration);
243  }
244  }
245  }
246 };
247 
248 static int init(drizzled::module::Context& context)
249 {
250  context.add(new SignalHandler);
251 
252  return 0;
253 }
254 
255 
256 DRIZZLE_DECLARE_PLUGIN
257 {
258  DRIZZLE_VERSION_ID,
259  "signal_handler",
260  "0.1",
261  "Brian Aker",
262  N_("Signal handler"),
263  PLUGIN_LICENSE_GPL,
264  init,
265  NULL,
266  NULL
267 }
268 DRIZZLE_DECLARE_PLUGIN_END;
TODO: Rename this file - func.h is stupid.