00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <config.h>
00019 #include <drizzled/gettext.h>
00020 #include <drizzled/error.h>
00021 #include <drizzled/plugin/storage_engine.h>
00022 #include <drizzled/pthread_globals.h>
00023 #include <drizzled/internal/my_pthread.h>
00024 #include <drizzled/internal/my_sys.h>
00025 #include <drizzled/plugin/daemon.h>
00026 #include <drizzled/signal_handler.h>
00027 #include <drizzled/session.h>
00028 #include <drizzled/session/cache.h>
00029 #include <drizzled/debug.h>
00030 #include <drizzled/drizzled.h>
00031 #include <drizzled/open_tables_state.h>
00032
00033 #include <boost/thread/thread.hpp>
00034 #include <boost/filesystem.hpp>
00035
00036 #include <sys/stat.h>
00037 #include <fcntl.h>
00038
00039 static bool kill_in_progress= false;
00040 void signal_hand(void);
00041
00042 namespace drizzled {
00043
00044 extern int cleanup_done;
00045 extern bool volatile abort_loop;
00046 extern bool volatile shutdown_in_progress;
00047 extern boost::filesystem::path pid_file;
00048
00049 extern void close_connections(void);
00050 }
00051
00052 using namespace drizzled;
00053
00054
00055
00056
00068 static void kill_server(int sig)
00069 {
00070
00071 if (kill_in_progress)
00072 {
00073 return;
00074 }
00075
00076 kill_in_progress= true;
00077 abort_loop= true;
00078 if (sig != 0)
00079 {
00080 ignore_signal(sig);
00081 }
00082
00083 if (sig == SIGTERM || sig == 0)
00084 {
00085 errmsg_printf(error::INFO, _(ER(ER_NORMAL_SHUTDOWN)),internal::my_progname);
00086 }
00087 else
00088 {
00089 errmsg_printf(error::ERROR, _(ER(ER_GOT_SIGNAL)),internal::my_progname,sig);
00090 }
00091
00092 close_connections();
00093 clean_up(1);
00094 }
00095
00099 static void create_pid_file()
00100 {
00101 int file;
00102 char buff[1024];
00103
00104 if ((file = open(pid_file.file_string().c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRGRP|S_IROTH)) > 0)
00105 {
00106 int length;
00107
00108 length= snprintf(buff, 1024, "%ld\n", (long) getpid());
00109
00110 if ((write(file, buff, length)) == length)
00111 {
00112 if (close(file) != -1)
00113 return;
00114 }
00115 (void)close(file);
00116 }
00117 memset(buff, 0, sizeof(buff));
00118 snprintf(buff, sizeof(buff)-1, "Can't start server: can't create PID file (%s)", pid_file.file_string().c_str());
00119 sql_perror(buff);
00120 exit(EXIT_FAILURE);
00121 }
00122
00123
00125 void signal_hand()
00126 {
00127 sigset_t set;
00128 int sig;
00129 internal::my_thread_init();
00130 signal_thread_in_use= true;
00131
00132 if ((drizzled::getDebug().test(drizzled::debug::ALLOW_SIGINT)))
00133 {
00134 (void) sigemptyset(&set);
00135 (void) sigaddset(&set,SIGINT);
00136 (void) pthread_sigmask(SIG_UNBLOCK, &set, NULL);
00137 }
00138 (void) sigemptyset(&set);
00139 #ifndef IGNORE_SIGHUP_SIGQUIT
00140 if (sigaddset(&set,SIGQUIT))
00141 {
00142 std::cerr << "failed setting sigaddset() with SIGQUIT\n";
00143 }
00144 if (sigaddset(&set,SIGHUP))
00145 {
00146 std::cerr << "failed setting sigaddset() with SIGHUP\n";
00147 }
00148 #endif
00149 if (sigaddset(&set,SIGTERM))
00150 {
00151 std::cerr << "failed setting sigaddset() with SIGTERM\n";
00152 }
00153 if (sigaddset(&set,SIGTSTP))
00154 {
00155 std::cerr << "failed setting sigaddset() with SIGTSTP\n";
00156 }
00157
00158
00159 create_pid_file();
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 session::Cache::mutex().lock();
00174 session::Cache::mutex().unlock();
00175 COND_thread_count.notify_all();
00176
00177 if (pthread_sigmask(SIG_BLOCK, &set, NULL))
00178 {
00179 std::cerr << "Failed to set pthread_sigmask() in signal handler\n";
00180 }
00181
00182 for (;;)
00183 {
00184 if (shutdown_in_progress && not abort_loop)
00185 {
00186 sig= SIGTERM;
00187 }
00188 else
00189 {
00190 while (sigwait(&set, &sig) == EINTR)
00191 {
00192 }
00193 }
00194
00195 if (cleanup_done)
00196 {
00197 signal_thread_in_use= false;
00198 return;
00199 }
00200 switch (sig)
00201 {
00202 case SIGTERM:
00203 case SIGQUIT:
00204 case SIGKILL:
00205 case SIGTSTP:
00206
00207 if (!abort_loop)
00208 {
00209 abort_loop= 1;
00210 kill_server(sig);
00211 }
00212 break;
00213 case SIGHUP:
00214 if (not abort_loop)
00215 {
00216 g_refresh_version++;
00217 drizzled::plugin::StorageEngine::flushLogs(NULL);
00218 }
00219 break;
00220 }
00221 }
00222 }
00223
00224 class SignalHandler :
00225 public drizzled::plugin::Daemon
00226 {
00227 boost::thread thread;
00228
00229 public:
00230 SignalHandler() :
00231 drizzled::plugin::Daemon("Signal Handler")
00232 {
00233
00234 boost::mutex::scoped_lock scopedLock(session::Cache::mutex());
00235 thread= boost::thread(signal_hand);
00236 signal_thread= thread.native_handle();
00237 COND_thread_count.wait(scopedLock);
00238 }
00239
00244 ~SignalHandler()
00245 {
00246
00247
00248
00249
00250 bool completed= false;
00251
00252
00253
00254
00255
00256 uint32_t count= 2;
00257 while (not completed and count--)
00258 {
00259 int signal= count == 1 ? SIGTSTP : SIGTERM;
00260
00261 if (int error= pthread_kill(thread.native_handle(), signal))
00262 {
00263 char buffer[1024];
00264 strerror_r(error, buffer, sizeof(buffer));
00265 std::cerr << "pthread_kill() error on shutdown of signal thread (" << buffer << ")\n";
00266 break;
00267 }
00268 else
00269 {
00270 boost::posix_time::milliseconds duration(100);
00271 completed= thread.timed_join(duration);
00272 }
00273 }
00274 }
00275 };
00276
00277 static int init(drizzled::module::Context& context)
00278 {
00279 context.add(new SignalHandler);
00280
00281 return 0;
00282 }
00283
00284
00285 DRIZZLE_DECLARE_PLUGIN
00286 {
00287 DRIZZLE_VERSION_ID,
00288 "signal_handler",
00289 "0.1",
00290 "Brian Aker",
00291 "Default Signal Handler",
00292 PLUGIN_LICENSE_GPL,
00293 init,
00294 NULL,
00295 NULL
00296 }
00297 DRIZZLE_DECLARE_PLUGIN_END;