~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

Cleanup around SAFEMALLOC

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