~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

Merged in latest plugin-slot-reorg.

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