~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Mark Atwood
  • Date: 2008-10-16 11:33:16 UTC
  • mto: (520.1.13 drizzle)
  • mto: This revision was merged to the branch mainline in revision 530.
  • Revision ID: mark@fallenpegasus.com-20081016113316-ff6jdt31ck90sjdh
an implemention of the errmsg plugin

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