~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-03-21 01:02:23 UTC
  • mto: (960.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 961.
  • Revision ID: osullivan.padraig@gmail.com-20090321010223-j8cph7eeyt1u3xol
Fixed function object to ensure it correctly returns a boolean type since
memcmp returns an integer. Added some more comments.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
15
 
16
 
#include "config.h"
 
16
#include <drizzled/server_includes.h>
17
17
#include <drizzled/gettext.h>
18
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
 
#include "drizzled/signal_handler.h"
27
 
 
28
 
#include "drizzled/session/cache.h"
29
 
 
30
 
#include "drizzled/drizzled.h"
31
 
 
32
 
#include <boost/thread/thread.hpp>
33
 
#include <boost/filesystem.hpp>
34
 
 
35
 
#include <sys/stat.h>
36
 
#include <fcntl.h>
37
 
 
38
19
 
39
20
static bool kill_in_progress= false;
40
 
void signal_hand(void);
41
 
 
42
 
namespace drizzled
43
 
{
 
21
static bool volatile signal_thread_in_use= false;
44
22
extern int cleanup_done;
45
 
extern bool volatile abort_loop;
46
 
extern bool volatile shutdown_in_progress;
47
 
extern boost::filesystem::path pid_file;
 
23
 
 
24
 
48
25
/* Prototypes -> all of these should be factored out into a propper shutdown */
49
 
extern void close_connections(void);
50
 
extern std::bitset<12> test_flags;
51
 
}
52
 
 
53
 
using namespace drizzled;
54
 
 
55
 
 
 
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);
56
30
 
57
31
 
58
32
/**
66
40
    or stop, we just want to kill the server.
67
41
*/
68
42
 
69
 
static void kill_server(int sig)
 
43
static void *kill_server(void *sig_ptr)
70
44
{
 
45
  int sig=(int) (long) sig_ptr;                 // This is passed a int
71
46
  // if there is a signal during the kill in progress, ignore the other
72
47
  if (kill_in_progress)                         // Safety
73
 
    return;
 
48
    return NULL;
74
49
  kill_in_progress=true;
75
50
  abort_loop=1;                                 // This should be set
76
51
  if (sig != 0) // 0 is not a valid signal number
77
 
    ignore_signal(sig);                    /* purify inspected */
 
52
    my_sigset(sig, SIG_IGN);                    /* purify inspected */
78
53
  if (sig == SIGTERM || sig == 0)
79
 
    errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
 
54
    errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),my_progname);
80
55
  else
81
 
    errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
 
56
    errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),my_progname,sig); /* purecov: inspected */
 
57
 
82
58
  close_connections();
83
 
  clean_up(1);
 
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;;
84
71
}
85
72
 
86
73
/**
91
78
  int file;
92
79
  char buff[1024];
93
80
 
94
 
  if ((file = open(pid_file.file_string().c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
 
81
  assert(pidfile_name[0]);
 
82
  if ((file = open(pidfile_name, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
95
83
  {
96
84
    int length;
97
85
 
104
92
    }
105
93
    (void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
106
94
  }
107
 
  memset(buff, 0, sizeof(buff));
108
 
  snprintf(buff, sizeof(buff)-1, "Can't start server: can't create PID file (%s)", pid_file.file_string().c_str());
 
95
  snprintf(buff, 1024, "Can't start server: can't create PID file (%s)", pidfile_name);
109
96
  sql_perror(buff);
110
97
  exit(1);
111
98
}
112
99
 
113
100
 
114
101
/** This threads handles all signals and alarms. */
115
 
void signal_hand()
 
102
/* ARGSUSED */
 
103
extern "C"
 
104
pthread_handler_t signal_hand(void *)
116
105
{
117
106
  sigset_t set;
118
107
  int sig;
119
 
  internal::my_thread_init();                           // Init new thread
120
 
  boost::this_thread::at_thread_exit(&internal::my_thread_end);
 
108
  my_thread_init();                             // Init new thread
121
109
  signal_thread_in_use= true;
122
110
 
123
 
  if ((test_flags.test(TEST_SIGINT)))
 
111
  if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
124
112
  {
125
113
    (void) sigemptyset(&set);                   // Setup up SIGINT for debug
126
114
    (void) sigaddset(&set,SIGINT);              // For debugging
128
116
  }
129
117
  (void) sigemptyset(&set);                     // Setup up SIGINT for debug
130
118
#ifndef IGNORE_SIGHUP_SIGQUIT
131
 
  if (sigaddset(&set,SIGQUIT))
132
 
  {
133
 
    std::cerr << "failed setting sigaddset() with SIGQUIT\n";
134
 
  }
135
 
  if (sigaddset(&set,SIGHUP))
136
 
  {
137
 
    std::cerr << "failed setting sigaddset() with SIGHUP\n";
138
 
  }
 
119
  (void) sigaddset(&set,SIGQUIT);
 
120
  (void) sigaddset(&set,SIGHUP);
139
121
#endif
140
 
  if (sigaddset(&set,SIGTERM))
141
 
  {
142
 
    std::cerr << "failed setting sigaddset() with SIGTERM\n";
143
 
  }
144
 
  if (sigaddset(&set,SIGTSTP))
145
 
  {
146
 
    std::cerr << "failed setting sigaddset() with SIGTSTP\n";
147
 
  }
 
122
  (void) sigaddset(&set,SIGTERM);
 
123
  (void) sigaddset(&set,SIGTSTP);
148
124
 
149
125
  /* Save pid to this process (or thread on Linux) */
150
126
  create_pid_file();
151
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
 
152
136
  /*
153
137
    signal to init that we are ready
154
138
    This works by waiting for init to free mutex,
161
145
    (Asked MontyW over the phone about this.) -Brian
162
146
 
163
147
  */
164
 
  session::Cache::singleton().mutex().lock();
165
 
  session::Cache::singleton().mutex().unlock();
166
 
  COND_thread_count.notify_all();
167
 
 
168
 
  if (pthread_sigmask(SIG_BLOCK, &set, NULL))
169
 
  {
170
 
    std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
171
 
  }
172
 
 
 
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);
173
153
  for (;;)
174
154
  {
175
155
    int error;                                  // Used when debugging
176
 
 
177
156
    if (shutdown_in_progress && !abort_loop)
178
157
    {
179
158
      sig= SIGTERM;
180
159
      error=0;
181
160
    }
182
161
    else
183
 
    {
184
 
      while ((error= sigwait(&set, &sig)) == EINTR) ;
185
 
    }
186
 
 
 
162
      while ((error= sigwait(&set,&sig)) == EINTR) ;
187
163
    if (cleanup_done)
188
164
    {
 
165
      my_thread_end();
189
166
      signal_thread_in_use= false;
190
167
 
191
 
      return;
 
168
      return NULL;
192
169
    }
193
170
    switch (sig) {
194
171
    case SIGTERM:
195
172
    case SIGQUIT:
196
173
    case SIGKILL:
197
 
    case SIGTSTP:
198
174
      /* switch to the old log message processing */
199
175
      if (!abort_loop)
200
176
      {
201
177
        abort_loop=1;                           // mark abort for threads
202
 
        kill_server(sig);               // MIT THREAD has a alarm thread
 
178
        kill_server((void*) sig);       // MIT THREAD has a alarm thread
203
179
      }
204
180
      break;
205
181
    case SIGHUP:
206
182
      if (!abort_loop)
207
183
      {
208
 
        refresh_version++;
209
 
        drizzled::plugin::StorageEngine::flushLogs(NULL);
 
184
        bool not_used;
 
185
        reload_cache((Session*) 0, (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST ),
 
186
                     (TableList*) 0, &not_used); // Flush logs
210
187
      }
211
188
      break;
212
189
    default:
 
190
      break;                                    /* purecov: tested */
 
191
    }
 
192
  }
 
193
}
 
194
 
 
195
 
 
196
static int init(void *)
 
197
{
 
198
  int error;
 
199
  pthread_attr_t thr_attr;
 
200
  size_t my_thread_stack_size= 65536;
 
201
 
 
202
  (void) pthread_attr_init(&thr_attr);
 
203
  pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM);
 
204
  (void) pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
 
205
  {
 
206
    struct sched_param tmp_sched_param;
 
207
 
 
208
    memset(&tmp_sched_param, 0, sizeof(tmp_sched_param));
 
209
    tmp_sched_param.sched_priority= INTERRUPT_PRIOR;
 
210
    (void)pthread_attr_setschedparam(&thr_attr, &tmp_sched_param);
 
211
  }
 
212
#if defined(__ia64__) || defined(__ia64)
 
213
  /*
 
214
    Peculiar things with ia64 platforms - it seems we only have half the
 
215
    stack size in reality, so we have to double it here
 
216
  */
 
217
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size*2);
 
218
# else
 
219
  pthread_attr_setstacksize(&thr_attr, my_thread_stack_size);
 
220
#endif
 
221
 
 
222
  (void) pthread_mutex_lock(&LOCK_thread_count);
 
223
  if ((error=pthread_create(&signal_thread, &thr_attr, signal_hand, 0)))
 
224
  {
 
225
      errmsg_printf(ERRMSG_LVL_ERROR, _("Can't create interrupt-thread (error %d, errno: %d)"),
 
226
                    error,errno);
 
227
    exit(1);
 
228
  }
 
229
  (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
 
230
  pthread_mutex_unlock(&LOCK_thread_count);
 
231
 
 
232
  (void) pthread_attr_destroy(&thr_attr);
 
233
 
 
234
  return 0;
 
235
}
 
236
 
 
237
/**
 
238
  This is mainly needed when running with purify, but it's still nice to
 
239
  know that all child threads have died when drizzled exits.
 
240
*/
 
241
static int deinit(void *)
 
242
{
 
243
  uint32_t i;
 
244
  /*
 
245
    Wait up to 10 seconds for signal thread to die. We use this mainly to
 
246
    avoid getting warnings that my_thread_end has not been called
 
247
  */
 
248
  for (i= 0 ; i < 100 && signal_thread_in_use; i++)
 
249
  {
 
250
    if (pthread_kill(signal_thread, SIGTERM) != ESRCH)
213
251
      break;
214
 
    }
215
 
  }
216
 
}
217
 
 
218
 
class SignalHandler :
219
 
  public drizzled::plugin::Daemon
220
 
{
221
 
  SignalHandler(const SignalHandler &);
222
 
  SignalHandler& operator=(const SignalHandler &);
223
 
  boost::thread thread;
224
 
 
225
 
public:
226
 
  SignalHandler() :
227
 
    drizzled::plugin::Daemon("Signal Handler")
228
 
  {
229
 
    // @todo fix spurious wakeup issue
230
 
    boost::mutex::scoped_lock scopedLock(session::Cache::singleton().mutex());
231
 
    thread= boost::thread(signal_hand);
232
 
    signal_thread= thread.native_handle();
233
 
    COND_thread_count.wait(scopedLock);
234
 
  }
235
 
 
236
 
  /**
237
 
    This is mainly needed when running with purify, but it's still nice to
238
 
    know that all child threads have died when drizzled exits.
239
 
  */
240
 
  ~SignalHandler()
241
 
  {
242
 
    /*
243
 
      Wait up to 100000 micro-seconds for signal thread to die. We use this mainly to
244
 
      avoid getting warnings that internal::my_thread_end has not been called
245
 
    */
246
 
    bool completed= false;
247
 
    /*
248
 
     * We send SIGTERM and then do a timed join. If that fails we will on
249
 
     * the last pthread_kill() call SIGTSTP. OSX (and FreeBSD) seem to
250
 
     * prefer this. -Brian
251
 
   */
252
 
    uint32_t count= 2; // How many times to try join and see if the caller died.
253
 
    while (not completed and count--)
254
 
    {
255
 
      int error;
256
 
      int signal= count == 1 ? SIGTSTP : SIGTERM;
257
 
      
258
 
      if ((error= pthread_kill(thread.native_handle(), signal)))
259
 
      {
260
 
        char buffer[1024]; // No reason for number;
261
 
        strerror_r(error, buffer, sizeof(buffer));
262
 
        std::cerr << "pthread_kill() error on shutdown of signal thread (" << buffer << ")\n";
263
 
        break;
264
 
      }
265
 
      else
266
 
      {
267
 
        boost::posix_time::milliseconds duration(100);
268
 
        completed= thread.timed_join(duration);
269
 
      }
270
 
    }
271
 
  }
272
 
};
273
 
 
274
 
static int init(drizzled::module::Context& context)
275
 
{
276
 
  context.add(new SignalHandler);
 
252
    usleep(100);                                // Give it time to die
 
253
  }
277
254
 
278
255
  return 0;
279
256
}
280
257
 
281
 
 
282
 
static drizzle_sys_var* system_variables[]= {
 
258
static struct st_mysql_sys_var* system_variables[]= {
283
259
  NULL
284
260
};
285
261
 
286
 
DRIZZLE_DECLARE_PLUGIN
 
262
drizzle_declare_plugin(signal_handler)
287
263
{
288
 
  DRIZZLE_VERSION_ID,
 
264
  DRIZZLE_DAEMON_PLUGIN,
289
265
  "signal_handler",
290
266
  "0.1",
291
267
  "Brian Aker",
292
268
  "Default Signal Handler",
293
269
  PLUGIN_LICENSE_GPL,
294
270
  init, /* Plugin Init */
 
271
  deinit, /* Plugin Deinit */
 
272
  NULL,   /* status variables */
295
273
  system_variables,   /* system variables */
296
274
  NULL    /* config options */
297
275
}
298
 
DRIZZLE_DECLARE_PLUGIN_END;
 
276
drizzle_declare_plugin_end;