~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Monty Taylor
  • Date: 2008-08-02 00:06:32 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080802000632-jsse0zdd9r6ic5ku
Actually turn gettext on...

Show diffs side-by-side

added added

removed removed

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