~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Monty Taylor
  • Date: 2009-03-08 23:45:12 UTC
  • mto: (923.2.1 mordred)
  • mto: This revision was merged to the branch mainline in revision 921.
  • Revision ID: mordred@inaugust.com-20090308234512-tqkygxtu1iaig23s
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards!

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
  int file;
 
79
  char buff[1024];
 
80
 
 
81
  assert(pidfile_name[0]);
 
82
  if ((file = open(pidfile_name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
 
83
  {
 
84
    int length;
 
85
 
 
86
    length= snprintf(buff, 1024, "%ld\n", (long) getpid()); 
 
87
 
 
88
    if ((write(file, buff, length)) == length)
 
89
    {
 
90
      if (close(file) != -1)
 
91
        return;
 
92
    }
 
93
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
 
94
  }
 
95
  snprintf(buff, 1024, "Can't start server: can't create PID file (%s)", pidfile_name);
 
96
  sql_perror(buff);
 
97
  exit(1);
 
98
}
 
99
 
 
100
 
 
101
/** This threads handles all signals and alarms. */
 
102
/* ARGSUSED */
 
103
extern "C"
 
104
pthread_handler_t signal_hand(void *)
 
105
{
 
106
  sigset_t set;
 
107
  int sig;
 
108
  my_thread_init();                             // Init new thread
 
109
  signal_thread_in_use= true;
 
110
 
 
111
  if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
 
112
  {
 
113
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
 
114
    (void) sigaddset(&set,SIGINT);              // For debugging
 
115
    (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
 
116
  }
 
117
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
 
118
#ifndef IGNORE_SIGHUP_SIGQUIT
 
119
  (void) sigaddset(&set,SIGQUIT);
 
120
  (void) sigaddset(&set,SIGHUP);
 
121
#endif
 
122
  (void) sigaddset(&set,SIGTERM);
 
123
  (void) sigaddset(&set,SIGTSTP);
 
124
 
 
125
  /* Save pid to this process (or thread on Linux) */
 
126
  create_pid_file();
 
127
 
 
128
#ifdef HAVE_STACK_TRACE_ON_SEGV
 
129
  if (opt_do_pstack)
 
130
  {
 
131
    sprintf(pstack_file_name,"drizzled-%lu-%%d-%%d.backtrace", (uint32_t)getpid());
 
132
    pstack_install_segv_action(pstack_file_name);
 
133
  }
 
134
#endif /* HAVE_STACK_TRACE_ON_SEGV */
 
135
 
 
136
  /*
 
137
    signal to init that we are ready
 
138
    This works by waiting for init to free mutex,
 
139
    after which we signal it that we are ready.
 
140
    At this pointer there is no other threads running, so there
 
141
    should not be any other pthread_cond_signal() calls.
 
142
 
 
143
    We call lock/unlock to out wait any thread/session which is
 
144
    dieing. Since only comes from this code, this should be safe.
 
145
    (Asked MontyW over the phone about this.) -Brian
 
146
 
 
147
  */
 
148
  if (pthread_mutex_lock(&LOCK_thread_count) == 0)
 
149
    (void) pthread_mutex_unlock(&LOCK_thread_count);
 
150
  (void) pthread_cond_broadcast(&COND_thread_count);
 
151
 
 
152
  (void) pthread_sigmask(SIG_BLOCK,&set,NULL);
 
153
  for (;;)
 
154
  {
 
155
    int error;                                  // Used when debugging
 
156
    if (shutdown_in_progress && !abort_loop)
 
157
    {
 
158
      sig= SIGTERM;
 
159
      error=0;
 
160
    }
 
161
    else
 
162
      while ((error= sigwait(&set,&sig)) == EINTR) ;
 
163
    if (cleanup_done)
 
164
    {
 
165
      my_thread_end();
 
166
      signal_thread_in_use= false;
 
167
 
 
168
      return NULL;
 
169
    }
 
170
    switch (sig) {
 
171
    case SIGTERM:
 
172
    case SIGQUIT:
 
173
    case SIGKILL:
 
174
      /* switch to the old log message processing */
 
175
      if (!abort_loop)
 
176
      {
 
177
        abort_loop=1;                           // mark abort for threads
 
178
        kill_server((void*) sig);       // MIT THREAD has a alarm thread
 
179
      }
 
180
      break;
 
181
    case SIGHUP:
 
182
      if (!abort_loop)
 
183
      {
 
184
        bool not_used;
 
185
        reload_cache((Session*) 0,
 
186
                     (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
 
187
                      REFRESH_HOSTS),
 
188
                     (TableList*) 0, &not_used); // Flush logs
 
189
      }
 
190
      break;
 
191
    default:
 
192
      break;                                    /* purecov: tested */
 
193
    }
 
194
  }
 
195
}
 
196
 
 
197
 
 
198
static int init(void *)
 
199
{
 
200
  int error;
 
201
  pthread_attr_t thr_attr;
 
202
  size_t my_thread_stack_size= 65536;
 
203
 
 
204
  (void) pthread_attr_init(&thr_attr);
 
205
  pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
 
206
  (void) pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
 
207
  {
 
208
    struct sched_param tmp_sched_param;
 
209
 
 
210
    memset(&tmp_sched_param, 0, sizeof(tmp_sched_param));
 
211
    tmp_sched_param.sched_priority= INTERRUPT_PRIOR;
 
212
    (void)pthread_attr_setschedparam(&thr_attr, &tmp_sched_param);
 
213
  }
 
214
#if defined(__ia64__) || defined(__ia64)
 
215
  /*
 
216
    Peculiar things with ia64 platforms - it seems we only have half the
 
217
    stack size in reality, so we have to double it here
 
218
  */
 
219
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size*2);
 
220
# else
 
221
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size);
 
222
#endif
 
223
 
 
224
  (void) pthread_mutex_lock(&LOCK_thread_count);
 
225
  if ((error=pthread_create(&signal_thread, &thr_attr, signal_hand, 0)))
 
226
  {
 
227
      errmsg_printf(ERRMSG_LVL_ERROR, _("Can't create interrupt-thread (error %d, errno: %d)"),
 
228
                    error,errno);
 
229
    exit(1);
 
230
  }
 
231
  (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
232
  pthread_mutex_unlock(&LOCK_thread_count);
 
233
 
 
234
  (void) pthread_attr_destroy(&thr_attr);
 
235
 
 
236
  return 0;
 
237
}
 
238
 
 
239
/**
 
240
  This is mainly needed when running with purify, but it's still nice to
 
241
  know that all child threads have died when drizzled exits.
 
242
*/
 
243
static int deinit(void *)
 
244
{
 
245
  uint32_t i;
 
246
  /*
 
247
    Wait up to 10 seconds for signal thread to die. We use this mainly to
 
248
    avoid getting warnings that my_thread_end has not been called
 
249
  */
 
250
  for (i= 0 ; i < 100 && signal_thread_in_use; i++)
 
251
  {
 
252
    if (pthread_kill(signal_thread, SIGTERM) != ESRCH)
 
253
      break;
 
254
    usleep(100);                                // Give it time to die
 
255
  }
 
256
 
 
257
  return 0;
 
258
}
 
259
 
 
260
static struct st_mysql_sys_var* system_variables[]= {
 
261
  NULL
 
262
};
 
263
 
 
264
drizzle_declare_plugin(signal_handler)
 
265
{
 
266
  DRIZZLE_DAEMON_PLUGIN,
 
267
  "signal_handler",
 
268
  "0.1",
 
269
  "Brian Aker",
 
270
  "Default Signal Handler",
 
271
  PLUGIN_LICENSE_GPL,
 
272
  init, /* Plugin Init */
 
273
  deinit, /* Plugin Deinit */
 
274
  NULL,   /* status variables */
 
275
  system_variables,   /* system variables */
 
276
  NULL    /* config options */
 
277
}
 
278
drizzle_declare_plugin_end;