1
/* Copyright (C) 2006 MySQL AB
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.
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.
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 */
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
#include "drizzled/signal_handler.h"
28
#include "drizzled/session_list.h"
30
#include "drizzled/drizzled.h"
32
#include <boost/thread/thread.hpp>
33
#include <boost/filesystem.hpp>
39
static bool kill_in_progress= false;
40
void signal_hand(void);
44
extern int cleanup_done;
45
extern bool volatile abort_loop;
46
extern bool volatile shutdown_in_progress;
47
extern boost::filesystem::path pid_file;
48
/* 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;
53
using namespace drizzled;
59
Force server down. Kill all connections and threads and exit.
61
@param sig_ptr Signal number that caused kill_server to be called.
64
A signal number of 0 mean that the function was not called
65
from a signal handler and there is thus no signal to block
66
or stop, we just want to kill the server.
69
static void kill_server(int sig)
71
// if there is a signal during the kill in progress, ignore the other
72
if (kill_in_progress) // Safety
74
kill_in_progress=true;
75
abort_loop=1; // This should be set
76
if (sig != 0) // 0 is not a valid signal number
77
ignore_signal(sig); /* purify inspected */
78
if (sig == SIGTERM || sig == 0)
79
errmsg_printf(ERRMSG_LVL_INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
81
errmsg_printf(ERRMSG_LVL_ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
87
Create file to store pid number.
89
static void create_pid_file()
94
if ((file = open(pid_file.file_string().c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
98
length= snprintf(buff, 1024, "%ld\n", (long) getpid());
100
if ((write(file, buff, length)) == length)
102
if (close(file) != -1)
105
(void)close(file); /* We can ignore the error, since we are going to error anyway at this point */
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());
114
/** This threads handles all signals and alarms. */
119
internal::my_thread_init(); // Init new thread
120
boost::this_thread::at_thread_exit(&internal::my_thread_end);
121
signal_thread_in_use= true;
123
if ((test_flags.test(TEST_SIGINT)))
125
(void) sigemptyset(&set); // Setup up SIGINT for debug
126
(void) sigaddset(&set,SIGINT); // For debugging
127
(void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
129
(void) sigemptyset(&set); // Setup up SIGINT for debug
130
#ifndef IGNORE_SIGHUP_SIGQUIT
131
if (sigaddset(&set,SIGQUIT))
133
std::cerr << "failed setting sigaddset() with SIGQUIT\n";
135
if (sigaddset(&set,SIGHUP))
137
std::cerr << "failed setting sigaddset() with SIGHUP\n";
140
if (sigaddset(&set,SIGTERM))
142
std::cerr << "failed setting sigaddset() with SIGTERM\n";
144
if (sigaddset(&set,SIGTSTP))
146
std::cerr << "failed setting sigaddset() with SIGTSTP\n";
149
/* Save pid to this process (or thread on Linux) */
153
signal to init that we are ready
154
This works by waiting for init to free mutex,
155
after which we signal it that we are ready.
156
At this pointer there is no other threads running, so there
157
should not be any other pthread_cond_signal() calls.
159
We call lock/unlock to out wait any thread/session which is
160
dieing. Since only comes from this code, this should be safe.
161
(Asked MontyW over the phone about this.) -Brian
164
session::Cache::singleton().mutex().lock();
165
session::Cache::singleton().mutex().unlock();
166
COND_thread_count.notify_all();
168
if (pthread_sigmask(SIG_BLOCK, &set, NULL))
170
std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
175
int error; // Used when debugging
177
if (shutdown_in_progress && !abort_loop)
184
while ((error= sigwait(&set, &sig)) == EINTR) ;
189
signal_thread_in_use= false;
198
/* switch to the old log message processing */
201
abort_loop=1; // mark abort for threads
202
kill_server(sig); // MIT THREAD has a alarm thread
209
drizzled::plugin::StorageEngine::flushLogs(NULL);
218
class SignalHandler :
219
public drizzled::plugin::Daemon
221
SignalHandler(const SignalHandler &);
222
SignalHandler& operator=(const SignalHandler &);
223
boost::thread thread;
227
drizzled::plugin::Daemon("Signal Handler")
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);
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.
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
246
bool completed= false;
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
252
uint32_t count= 2; // How many times to try join and see if the caller died.
253
while (not completed and count--)
256
int signal= count == 1 ? SIGTSTP : SIGTERM;
258
if ((error= pthread_kill(thread.native_handle(), signal)))
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";
267
boost::posix_time::milliseconds duration(100);
268
completed= thread.timed_join(duration);
274
static int init(drizzled::module::Context& context)
276
context.add(new SignalHandler);
282
static drizzle_sys_var* system_variables[]= {
286
DRIZZLE_DECLARE_PLUGIN
292
"Default Signal Handler",
294
init, /* Plugin Init */
295
system_variables, /* system variables */
296
NULL /* config options */
298
DRIZZLE_DECLARE_PLUGIN_END;