~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
20
 
#include <drizzled/gettext.h>
21
 
#include <drizzled/error.h>
22
 
#include <drizzled/unireg.h>
23
 
#include <drizzled/plugin/storage_engine.h>
24
 
#include "drizzled/pthread_globals.h"
25
 
#include "drizzled/internal/my_pthread.h"
26
 
#include "drizzled/internal/my_sys.h"
27
 
#include "drizzled/plugin/daemon.h"
28
 
#include "drizzled/signal_handler.h"
29
 
 
30
 
#include <drizzled/session.h>
31
 
#include <drizzled/session/cache.h>
32
 
 
33
 
#include "drizzled/debug.h"
34
 
 
35
 
#include "drizzled/drizzled.h"
36
 
 
37
 
#include <drizzled/refresh_version.h>
38
 
 
39
 
#include <boost/thread/thread.hpp>
40
 
#include <boost/filesystem.hpp>
41
 
 
42
 
#include <sys/stat.h>
43
 
#include <fcntl.h>
44
 
 
45
 
 
46
 
static bool kill_in_progress= false;
47
 
void signal_hand(void);
48
 
 
49
 
namespace drizzled
50
 
{
51
 
extern int cleanup_done;
52
 
extern bool volatile abort_loop;
53
 
extern bool volatile shutdown_in_progress;
54
 
extern boost::filesystem::path pid_file;
55
 
/* Prototypes -> all of these should be factored out into a propper shutdown */
56
 
extern void close_connections(void);
57
 
}
58
 
 
59
 
using namespace drizzled;
60
 
 
61
 
 
62
 
 
63
 
 
64
 
/**
65
 
  Force server down. Kill all connections and threads and exit.
66
 
 
67
 
  @param  sig_ptr       Signal number that caused kill_server to be called.
68
 
 
69
 
  @note
70
 
    A signal number of 0 mean that the function was not called
71
 
    from a signal handler and there is thus no signal to block
72
 
    or stop, we just want to kill the server.
73
 
*/
74
 
 
75
 
static void kill_server(int sig)
76
 
{
77
 
  // if there is a signal during the kill in progress, ignore the other
78
 
  if (kill_in_progress)                         // Safety
79
 
    return;
80
 
  kill_in_progress=true;
81
 
  abort_loop=1;                                 // This should be set
82
 
  if (sig != 0) // 0 is not a valid signal number
83
 
    ignore_signal(sig);                    /* purify inspected */
84
 
  if (sig == SIGTERM || sig == 0)
85
 
    errmsg_printf(error::INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
86
 
  else
87
 
    errmsg_printf(error::ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
88
 
 
89
 
  close_connections();
90
 
  clean_up(1);
91
 
}
92
 
 
93
 
/**
94
 
  Create file to store pid number.
95
 
*/
96
 
static void create_pid_file()
97
 
{
98
 
  int file;
99
 
  char buff[1024];
100
 
 
101
 
  if ((file = open(pid_file.file_string().c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
102
 
  {
103
 
    int length;
104
 
 
105
 
    length= snprintf(buff, 1024, "%ld\n", (long) getpid()); 
106
 
 
107
 
    if ((write(file, buff, length)) == length)
108
 
    {
109
 
      if (close(file) != -1)
110
 
        return;
111
 
    }
112
 
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
113
 
  }
114
 
  memset(buff, 0, sizeof(buff));
115
 
  snprintf(buff, sizeof(buff)-1, "Can't start server: can't create PID file (%s)", pid_file.file_string().c_str());
116
 
  sql_perror(buff);
117
 
  exit(1);
118
 
}
119
 
 
120
 
 
121
 
/** This threads handles all signals and alarms. */
122
 
void signal_hand()
123
 
{
124
 
  sigset_t set;
125
 
  int sig;
126
 
  internal::my_thread_init();                           // Init new thread
127
 
  boost::this_thread::at_thread_exit(&internal::my_thread_end);
128
 
  signal_thread_in_use= true;
129
 
 
130
 
  if ((drizzled::getDebug().test(drizzled::debug::ALLOW_SIGINT)))
131
 
  {
132
 
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
133
 
    (void) sigaddset(&set,SIGINT);              // For debugging
134
 
    (void) pthread_sigmask(SIG_UNBLOCK, &set, NULL);
135
 
  }
136
 
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
137
 
#ifndef IGNORE_SIGHUP_SIGQUIT
138
 
  if (sigaddset(&set,SIGQUIT))
139
 
  {
140
 
    std::cerr << "failed setting sigaddset() with SIGQUIT\n";
141
 
  }
142
 
  if (sigaddset(&set,SIGHUP))
143
 
  {
144
 
    std::cerr << "failed setting sigaddset() with SIGHUP\n";
145
 
  }
146
 
#endif
147
 
  if (sigaddset(&set,SIGTERM))
148
 
  {
149
 
    std::cerr << "failed setting sigaddset() with SIGTERM\n";
150
 
  }
151
 
  if (sigaddset(&set,SIGTSTP))
152
 
  {
153
 
    std::cerr << "failed setting sigaddset() with SIGTSTP\n";
154
 
  }
155
 
 
156
 
  /* Save pid to this process (or thread on Linux) */
157
 
  create_pid_file();
158
 
 
159
 
  /*
160
 
    signal to init that we are ready
161
 
    This works by waiting for init to free mutex,
162
 
    after which we signal it that we are ready.
163
 
    At this pointer there is no other threads running, so there
164
 
    should not be any other pthread_cond_signal() calls.
165
 
 
166
 
    We call lock/unlock to out wait any thread/session which is
167
 
    dieing. Since only comes from this code, this should be safe.
168
 
    (Asked MontyW over the phone about this.) -Brian
169
 
 
170
 
  */
171
 
  session::Cache::singleton().mutex().lock();
172
 
  session::Cache::singleton().mutex().unlock();
173
 
  COND_thread_count.notify_all();
174
 
 
175
 
  if (pthread_sigmask(SIG_BLOCK, &set, NULL))
176
 
  {
177
 
    std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
178
 
  }
179
 
 
180
 
  for (;;)
181
 
  {
182
 
    int error;                                  // Used when debugging
183
 
 
184
 
    if (shutdown_in_progress && !abort_loop)
185
 
    {
186
 
      sig= SIGTERM;
187
 
      error=0;
188
 
    }
189
 
    else
190
 
    {
191
 
      while ((error= sigwait(&set, &sig)) == EINTR) ;
192
 
    }
193
 
 
194
 
    if (cleanup_done)
195
 
    {
196
 
      signal_thread_in_use= false;
197
 
 
198
 
      return;
199
 
    }
200
 
    switch (sig) {
201
 
    case SIGTERM:
202
 
    case SIGQUIT:
203
 
    case SIGKILL:
204
 
    case SIGTSTP:
205
 
      /* switch to the old log message processing */
206
 
      if (!abort_loop)
207
 
      {
208
 
        abort_loop=1;                           // mark abort for threads
209
 
        kill_server(sig);               // MIT THREAD has a alarm thread
210
 
      }
211
 
      break;
212
 
    case SIGHUP:
213
 
      if (!abort_loop)
214
 
      {
215
 
        refresh_version++;
216
 
        drizzled::plugin::StorageEngine::flushLogs(NULL);
217
 
      }
218
 
      break;
219
 
    default:
220
 
      break;
221
 
    }
222
 
  }
223
 
}
224
 
 
225
 
class SignalHandler :
226
 
  public drizzled::plugin::Daemon
227
 
{
228
 
  SignalHandler(const SignalHandler &);
229
 
  SignalHandler& operator=(const SignalHandler &);
230
 
  boost::thread thread;
231
 
 
232
 
public:
233
 
  SignalHandler() :
234
 
    drizzled::plugin::Daemon("Signal Handler")
235
 
  {
236
 
    // @todo fix spurious wakeup issue
237
 
    boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
238
 
    thread= boost::thread(signal_hand);
239
 
    signal_thread= thread.native_handle();
240
 
    COND_thread_count.wait(scopedLock);
241
 
  }
242
 
 
243
 
  /**
244
 
    This is mainly needed when running with purify, but it's still nice to
245
 
    know that all child threads have died when drizzled exits.
246
 
  */
247
 
  ~SignalHandler()
248
 
  {
249
 
    /*
250
 
      Wait up to 100000 micro-seconds for signal thread to die. We use this mainly to
251
 
      avoid getting warnings that internal::my_thread_end has not been called
252
 
    */
253
 
    bool completed= false;
254
 
    /*
255
 
     * We send SIGTERM and then do a timed join. If that fails we will on
256
 
     * the last pthread_kill() call SIGTSTP. OSX (and FreeBSD) seem to
257
 
     * prefer this. -Brian
258
 
   */
259
 
    uint32_t count= 2; // How many times to try join and see if the caller died.
260
 
    while (not completed and count--)
261
 
    {
262
 
      int error;
263
 
      int signal= count == 1 ? SIGTSTP : SIGTERM;
264
 
      
265
 
      if ((error= pthread_kill(thread.native_handle(), signal)))
266
 
      {
267
 
        char buffer[1024]; // No reason for number;
268
 
        strerror_r(error, buffer, sizeof(buffer));
269
 
        std::cerr << "pthread_kill() error on shutdown of signal thread (" << buffer << ")\n";
270
 
        break;
271
 
      }
272
 
      else
273
 
      {
274
 
        boost::posix_time::milliseconds duration(100);
275
 
        completed= thread.timed_join(duration);
276
 
      }
277
 
    }
278
 
  }
279
 
};
280
 
 
281
 
static int init(drizzled::module::Context& context)
282
 
{
283
 
  context.add(new SignalHandler);
284
 
 
285
 
  return 0;
286
 
}
287
 
 
288
 
 
289
 
DRIZZLE_DECLARE_PLUGIN
290
 
{
291
 
  DRIZZLE_VERSION_ID,
292
 
  "signal_handler",
293
 
  "0.1",
294
 
  "Brian Aker",
295
 
  "Default Signal Handler",
296
 
  PLUGIN_LICENSE_GPL,
297
 
  init, /* Plugin Init */
298
 
  NULL,   /* depends */
299
 
  NULL    /* config options */
300
 
}
301
 
DRIZZLE_DECLARE_PLUGIN_END;