~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

Merged in changes. 
Edited a the comment test case so deal with our version bump.

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
 
 
26
 
#include <sys/stat.h>
27
 
#include <fcntl.h>
28
 
 
29
 
static bool kill_in_progress= false;
30
 
static bool volatile signal_thread_in_use= false;
31
 
extern int cleanup_done;
32
 
extern "C" pthread_handler_t signal_hand(void *);
33
 
extern bool volatile abort_loop;
34
 
extern bool volatile shutdown_in_progress;
35
 
extern char pidfile_name[FN_REFLEN];
36
 
 
37
 
extern std::bitset<12> test_flags;
38
 
 
39
 
/* Prototypes -> all of these should be factored out into a propper shutdown */
40
 
extern void close_connections(void);
41
 
 
42
 
 
43
 
/**
44
 
  Force server down. Kill all connections and threads and exit.
45
 
 
46
 
  @param  sig_ptr       Signal number that caused kill_server to be called.
47
 
 
48
 
  @note
49
 
    A signal number of 0 mean that the function was not called
50
 
    from a signal handler and there is thus no signal to block
51
 
    or stop, we just want to kill the server.
52
 
*/
53
 
 
54
 
static void kill_server(void *sig_ptr)
55
 
{
56
 
  int sig=(int) (long) sig_ptr;                 // This is passed a int
57
 
  // if there is a signal during the kill in progress, ignore the other
58
 
  if (kill_in_progress)                         // Safety
59
 
    return;
60
 
  kill_in_progress=true;
61
 
  abort_loop=1;                                 // This should be set
62
 
  if (sig != 0) // 0 is not a valid signal number
63
 
    my_sigset(sig, SIG_IGN);                    /* purify inspected */
64
 
  if (sig == SIGTERM || sig == 0)
65
 
    errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),my_progname);
66
 
  else
67
 
    errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),my_progname,sig);
68
 
 
69
 
  close_connections();
70
 
  if (sig != SIGTERM && sig != 0)
71
 
    unireg_abort(1);
72
 
  else
73
 
    unireg_end();
74
 
}
75
 
 
76
 
/**
77
 
  Create file to store pid number.
78
 
*/
79
 
static void create_pid_file()
80
 
{
81
 
  int file;
82
 
  char buff[1024];
83
 
 
84
 
  assert(pidfile_name[0]);
85
 
  if ((file = open(pidfile_name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
86
 
  {
87
 
    int length;
88
 
 
89
 
    length= snprintf(buff, 1024, "%ld\n", (long) getpid()); 
90
 
 
91
 
    if ((write(file, buff, length)) == length)
92
 
    {
93
 
      if (close(file) != -1)
94
 
        return;
95
 
    }
96
 
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
97
 
  }
98
 
  snprintf(buff, 1024, "Can't start server: can't create PID file (%s)", pidfile_name);
99
 
  sql_perror(buff);
100
 
  exit(1);
101
 
}
102
 
 
103
 
 
104
 
/** This threads handles all signals and alarms. */
105
 
pthread_handler_t signal_hand(void *)
106
 
{
107
 
  sigset_t set;
108
 
  int sig;
109
 
  my_thread_init();                             // Init new thread
110
 
  signal_thread_in_use= true;
111
 
 
112
 
  if (thd_lib_detected != THD_LIB_LT && 
113
 
      (test_flags.test(TEST_SIGINT)))
114
 
  {
115
 
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
116
 
    (void) sigaddset(&set,SIGINT);              // For debugging
117
 
    (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
118
 
  }
119
 
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
120
 
#ifndef IGNORE_SIGHUP_SIGQUIT
121
 
  (void) sigaddset(&set,SIGQUIT);
122
 
  (void) sigaddset(&set,SIGHUP);
123
 
#endif
124
 
  (void) sigaddset(&set,SIGTERM);
125
 
  (void) sigaddset(&set,SIGTSTP);
126
 
 
127
 
  /* Save pid to this process (or thread on Linux) */
128
 
  create_pid_file();
129
 
 
130
 
#ifdef HAVE_STACK_TRACE_ON_SEGV
131
 
  if (opt_do_pstack)
132
 
  {
133
 
    sprintf(pstack_file_name,"drizzled-%lu-%%d-%%d.backtrace", (uint32_t)getpid());
134
 
    pstack_install_segv_action(pstack_file_name);
135
 
  }
136
 
#endif /* HAVE_STACK_TRACE_ON_SEGV */
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
 
      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
 
 
197
 
static int init(drizzled::plugin::Registry&)
198
 
{
199
 
  int error;
200
 
  pthread_attr_t thr_attr;
201
 
  size_t my_thread_stack_size= 65536;
202
 
 
203
 
  (void) pthread_attr_init(&thr_attr);
204
 
  pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
205
 
  (void) pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
206
 
  {
207
 
    struct sched_param tmp_sched_param;
208
 
 
209
 
    memset(&tmp_sched_param, 0, sizeof(tmp_sched_param));
210
 
    tmp_sched_param.sched_priority= INTERRUPT_PRIOR;
211
 
    (void)pthread_attr_setschedparam(&thr_attr, &tmp_sched_param);
212
 
  }
213
 
#if defined(__ia64__) || defined(__ia64)
214
 
  /*
215
 
    Peculiar things with ia64 platforms - it seems we only have half the
216
 
    stack size in reality, so we have to double it here
217
 
  */
218
 
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size*2);
219
 
# else
220
 
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size);
221
 
#endif
222
 
 
223
 
  (void) pthread_mutex_lock(&LOCK_thread_count);
224
 
  if ((error=pthread_create(&signal_thread, &thr_attr, signal_hand, 0)))
225
 
  {
226
 
      errmsg_printf(ERRMSG_LVL_ERROR, _("Can't create interrupt-thread (error %d, errno: %d)"),
227
 
                    error,errno);
228
 
    exit(1);
229
 
  }
230
 
  (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
231
 
  pthread_mutex_unlock(&LOCK_thread_count);
232
 
 
233
 
  (void) pthread_attr_destroy(&thr_attr);
234
 
 
235
 
  return 0;
236
 
}
237
 
 
238
 
/**
239
 
  This is mainly needed when running with purify, but it's still nice to
240
 
  know that all child threads have died when drizzled exits.
241
 
*/
242
 
static int deinit(drizzled::plugin::Registry&)
243
 
{
244
 
  uint32_t i;
245
 
  /*
246
 
    Wait up to 10 seconds for signal thread to die. We use this mainly to
247
 
    avoid getting warnings that my_thread_end has not been called
248
 
  */
249
 
  for (i= 0 ; i < 100 && signal_thread_in_use; i++)
250
 
  {
251
 
    if (pthread_kill(signal_thread, SIGTERM) != ESRCH)
252
 
      break;
253
 
    usleep(100);                                // Give it time to die
254
 
  }
255
 
 
256
 
  return 0;
257
 
}
258
 
 
259
 
static drizzle_sys_var* system_variables[]= {
260
 
  NULL
261
 
};
262
 
 
263
 
DRIZZLE_DECLARE_PLUGIN
264
 
{
265
 
  DRIZZLE_VERSION_ID,
266
 
  "signal_handler",
267
 
  "0.1",
268
 
  "Brian Aker",
269
 
  "Default Signal Handler",
270
 
  PLUGIN_LICENSE_GPL,
271
 
  init, /* Plugin Init */
272
 
  deinit, /* Plugin Deinit */
273
 
  NULL,   /* status variables */
274
 
  system_variables,   /* system variables */
275
 
  NULL    /* config options */
276
 
}
277
 
DRIZZLE_DECLARE_PLUGIN_END;