~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/signal_handler/signal_handler.cc

fix pthread atomics. operator precedence is important. The unit test now passes.

Show diffs side-by-side

added added

removed removed

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