~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Brian Aker
  • Date: 2010-05-27 01:25:56 UTC
  • mfrom: (1567.1.4 new-staging)
  • Revision ID: brian@gaz-20100527012556-5zgkirkl7swbigd6
Merge of Brian, Paul. PBXT compile issue, and test framework cleanup. 

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 <sys/stat.h>
 
29
#include <fcntl.h>
 
30
 
 
31
 
 
32
static bool kill_in_progress= false;
 
33
static bool volatile signal_thread_in_use= false;
 
34
extern "C" pthread_handler_t signal_hand(void *);
 
35
 
 
36
namespace drizzled
 
37
{
 
38
extern int cleanup_done;
 
39
extern bool volatile abort_loop;
 
40
extern bool volatile shutdown_in_progress;
 
41
extern char pidfile_name[FN_REFLEN];
 
42
/* Prototypes -> all of these should be factored out into a propper shutdown */
 
43
extern void close_connections(void);
 
44
extern std::bitset<12> test_flags;
 
45
}
 
46
 
 
47
using namespace drizzled;
 
48
 
 
49
 
 
50
 
 
51
/**
 
52
  Force server down. Kill all connections and threads and exit.
 
53
 
 
54
  @param  sig_ptr       Signal number that caused kill_server to be called.
 
55
 
 
56
  @note
 
57
    A signal number of 0 mean that the function was not called
 
58
    from a signal handler and there is thus no signal to block
 
59
    or stop, we just want to kill the server.
 
60
*/
 
61
 
 
62
static void kill_server(void *sig_ptr)
 
63
{
 
64
  int sig=(int) (long) sig_ptr;                 // This is passed a int
 
65
  // if there is a signal during the kill in progress, ignore the other
 
66
  if (kill_in_progress)                         // Safety
 
67
    return;
 
68
  kill_in_progress=true;
 
69
  abort_loop=1;                                 // This should be set
 
70
  if (sig != 0) // 0 is not a valid signal number
 
71
    ignore_signal(sig);                    /* purify inspected */
 
72
  if (sig == SIGTERM || sig == 0)
 
73
    errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
 
74
  else
 
75
    errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
 
76
 
 
77
  close_connections();
 
78
  if (sig != SIGTERM && sig != 0)
 
79
    unireg_abort(1);
 
80
  else
 
81
    unireg_end();
 
82
}
 
83
 
 
84
/**
 
85
  Create file to store pid number.
 
86
*/
 
87
static void create_pid_file()
 
88
{
 
89
  int file;
 
90
  char buff[1024];
 
91
 
 
92
  assert(pidfile_name[0]);
 
93
  if ((file = open(pidfile_name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
 
94
  {
 
95
    int length;
 
96
 
 
97
    length= snprintf(buff, 1024, "%ld\n", (long) getpid()); 
 
98
 
 
99
    if ((write(file, buff, length)) == length)
 
100
    {
 
101
      if (close(file) != -1)
 
102
        return;
 
103
    }
 
104
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
 
105
  }
 
106
  snprintf(buff, 1024, "Can't start server: can't create PID file (%s)", pidfile_name);
 
107
  sql_perror(buff);
 
108
  exit(1);
 
109
}
 
110
 
 
111
 
 
112
/** This threads handles all signals and alarms. */
 
113
pthread_handler_t signal_hand(void *)
 
114
{
 
115
  sigset_t set;
 
116
  int sig;
 
117
  internal::my_thread_init();                           // Init new thread
 
118
  signal_thread_in_use= true;
 
119
 
 
120
  if (internal::thd_lib_detected != THD_LIB_LT && 
 
121
      (test_flags.test(TEST_SIGINT)))
 
122
  {
 
123
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
 
124
    (void) sigaddset(&set,SIGINT);              // For debugging
 
125
    (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
 
126
  }
 
127
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
 
128
#ifndef IGNORE_SIGHUP_SIGQUIT
 
129
  (void) sigaddset(&set,SIGQUIT);
 
130
  (void) sigaddset(&set,SIGHUP);
 
131
#endif
 
132
  (void) sigaddset(&set,SIGTERM);
 
133
  (void) sigaddset(&set,SIGTSTP);
 
134
 
 
135
  /* Save pid to this process (or thread on Linux) */
 
136
  create_pid_file();
 
137
 
 
138
  /*
 
139
    signal to init that we are ready
 
140
    This works by waiting for init to free mutex,
 
141
    after which we signal it that we are ready.
 
142
    At this pointer there is no other threads running, so there
 
143
    should not be any other pthread_cond_signal() calls.
 
144
 
 
145
    We call lock/unlock to out wait any thread/session which is
 
146
    dieing. Since only comes from this code, this should be safe.
 
147
    (Asked MontyW over the phone about this.) -Brian
 
148
 
 
149
  */
 
150
  if (pthread_mutex_lock(&LOCK_thread_count) == 0)
 
151
    (void) pthread_mutex_unlock(&LOCK_thread_count);
 
152
  (void) pthread_cond_broadcast(&COND_thread_count);
 
153
 
 
154
  (void) pthread_sigmask(SIG_BLOCK,&set,NULL);
 
155
  for (;;)
 
156
  {
 
157
    int error;                                  // Used when debugging
 
158
    if (shutdown_in_progress && !abort_loop)
 
159
    {
 
160
      sig= SIGTERM;
 
161
      error=0;
 
162
    }
 
163
    else
 
164
      while ((error= sigwait(&set,&sig)) == EINTR) ;
 
165
    if (cleanup_done)
 
166
    {
 
167
      internal::my_thread_end();
 
168
      signal_thread_in_use= false;
 
169
 
 
170
      return NULL;
 
171
    }
 
172
    switch (sig) {
 
173
    case SIGTERM:
 
174
    case SIGQUIT:
 
175
    case SIGKILL:
 
176
      /* switch to the old log message processing */
 
177
      if (!abort_loop)
 
178
      {
 
179
        abort_loop=1;                           // mark abort for threads
 
180
        kill_server((void*) sig);       // MIT THREAD has a alarm thread
 
181
      }
 
182
      break;
 
183
    case SIGHUP:
 
184
      if (!abort_loop)
 
185
      {
 
186
        refresh_version++;
 
187
        drizzled::plugin::StorageEngine::flushLogs(NULL);
 
188
      }
 
189
      break;
 
190
    default:
 
191
      break;
 
192
    }
 
193
  }
 
194
}
 
195
 
 
196
class SignalHandler :
 
197
  public drizzled::plugin::Daemon
 
198
{
 
199
  SignalHandler(const SignalHandler &);
 
200
  SignalHandler& operator=(const SignalHandler &);
 
201
public:
 
202
  SignalHandler()
 
203
    : drizzled::plugin::Daemon("Signal Handler")
 
204
  {
 
205
    int error;
 
206
    pthread_attr_t thr_attr;
 
207
    size_t my_thread_stack_size= 65536;
 
208
 
 
209
    (void) pthread_attr_init(&thr_attr);
 
210
    pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
 
211
    (void) pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
 
212
    {
 
213
      struct sched_param tmp_sched_param;
 
214
 
 
215
      memset(&tmp_sched_param, 0, sizeof(tmp_sched_param));
 
216
      tmp_sched_param.sched_priority= INTERRUPT_PRIOR;
 
217
      (void)pthread_attr_setschedparam(&thr_attr, &tmp_sched_param);
 
218
    }
 
219
#if defined(__ia64__) || defined(__ia64)
 
220
    /*
 
221
      Peculiar things with ia64 platforms - it seems we only have half the
 
222
      stack size in reality, so we have to double it here
 
223
    */
 
224
    pthread_attr_setstacksize(&thr_attr, my_thread_stack_size*2);
 
225
# else
 
226
    pthread_attr_setstacksize(&thr_attr, my_thread_stack_size);
 
227
#endif
 
228
 
 
229
    (void) pthread_mutex_lock(&LOCK_thread_count);
 
230
    if ((error=pthread_create(&signal_thread, &thr_attr, signal_hand, 0)))
 
231
    {
 
232
      errmsg_printf(ERRMSG_LVL_ERROR,
 
233
                    _("Can't create interrupt-thread (error %d, errno: %d)"),
 
234
                    error,errno);
 
235
      exit(1);
 
236
    }
 
237
    (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
238
    pthread_mutex_unlock(&LOCK_thread_count);
 
239
 
 
240
    (void) pthread_attr_destroy(&thr_attr);
 
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
    uint32_t i;
 
250
    /*
 
251
      Wait up to 10 seconds for signal thread to die. We use this mainly to
 
252
      avoid getting warnings that internal::my_thread_end has not been called
 
253
    */
 
254
    for (i= 0 ; i < 100 && signal_thread_in_use; i++)
 
255
    {
 
256
      if (pthread_kill(signal_thread, SIGTERM) != ESRCH)
 
257
        break;
 
258
      usleep(100);                              // Give it time to die
 
259
    }
 
260
 
 
261
  }
 
262
};
 
263
 
 
264
static int init(drizzled::module::Context& context)
 
265
{
 
266
  SignalHandler *handler= new SignalHandler;
 
267
  context.add(handler);
 
268
  return 0;
 
269
}
 
270
 
 
271
 
 
272
static drizzle_sys_var* system_variables[]= {
 
273
  NULL
 
274
};
 
275
 
 
276
DRIZZLE_DECLARE_PLUGIN
 
277
{
 
278
  DRIZZLE_VERSION_ID,
 
279
  "signal_handler",
 
280
  "0.1",
 
281
  "Brian Aker",
 
282
  "Default Signal Handler",
 
283
  PLUGIN_LICENSE_GPL,
 
284
  init, /* Plugin Init */
 
285
  system_variables,   /* system variables */
 
286
  NULL    /* config options */
 
287
}
 
288
DRIZZLE_DECLARE_PLUGIN_END;