~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

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