+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2011 New Dream Network
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
-
-#include "include/compat.h"
-#include "pthread.h"
-
-#include "common/BackTrace.h"
-#include "common/debug.h"
-#include "global/pidfile.h"
-#include "global/signal_handler.h"
-
-#include <poll.h>
-#include <signal.h>
-#include <sstream>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include "common/errno.h"
-#if defined(_AIX)
-extern char *sys_siglist[];
-#endif
-
-#define dout_context g_ceph_context
-
-void install_sighandler(int signum, signal_handler_t handler, int flags)
-{
- int ret;
- struct sigaction oldact;
- struct sigaction act;
- memset(&act, 0, sizeof(act));
-
- act.sa_handler = handler;
- sigemptyset(&act.sa_mask);
- act.sa_flags = flags;
-
- ret = sigaction(signum, &act, &oldact);
- if (ret != 0) {
- char buf[1024];
-#if defined(__sun)
- char message[SIG2STR_MAX];
- sig2str(signum,message);
- snprintf(buf, sizeof(buf), "install_sighandler: sigaction returned "
- "%d when trying to install a signal handler for %s\n",
- ret, message);
-#else
- snprintf(buf, sizeof(buf), "install_sighandler: sigaction returned "
- "%d when trying to install a signal handler for %s\n",
- ret, sig_str(signum));
-#endif
- dout_emergency(buf);
- exit(1);
- }
-}
-
-void sighup_handler(int signum)
-{
- g_ceph_context->reopen_logs();
-}
-
-static void reraise_fatal(int signum)
-{
- // Use default handler to dump core
- int ret = raise(signum);
-
- // Normally, we won't get here. If we do, something is very weird.
- char buf[1024];
- if (ret) {
- snprintf(buf, sizeof(buf), "reraise_fatal: failed to re-raise "
- "signal %d\n", signum);
- dout_emergency(buf);
- }
- else {
- snprintf(buf, sizeof(buf), "reraise_fatal: default handler for "
- "signal %d didn't terminate the process?\n", signum);
- dout_emergency(buf);
- }
- exit(1);
-}
-
-static void handle_fatal_signal(int signum)
-{
- // This code may itself trigger a SIGSEGV if the heap is corrupt. In that
- // case, SA_RESETHAND specifies that the default signal handler--
- // presumably dump core-- will handle it.
- char buf[1024];
- char pthread_name[16] = {0}; //limited by 16B include terminating null byte.
- int r = ceph_pthread_getname(pthread_self(), pthread_name, sizeof(pthread_name));
- (void)r;
-#if defined(__sun)
- char message[SIG2STR_MAX];
- sig2str(signum,message);
- snprintf(buf, sizeof(buf), "*** Caught signal (%s) **\n "
- "in thread %llx thread_name:%s\n", message, (unsigned long long)pthread_self(),
- pthread_name);
-#else
- snprintf(buf, sizeof(buf), "*** Caught signal (%s) **\n "
- "in thread %llx thread_name:%s\n", sig_str(signum), (unsigned long long)pthread_self(),
- pthread_name);
-#endif
- dout_emergency(buf);
- pidfile_remove();
-
- // TODO: don't use an ostringstream here. It could call malloc(), which we
- // don't want inside a signal handler.
- // Also fix the backtrace code not to allocate memory.
- BackTrace bt(0);
- ostringstream oss;
- bt.print(oss);
- dout_emergency(oss.str());
-
- // avoid recursion back into logging code if that is where
- // we got the SEGV.
- if (g_ceph_context &&
- g_ceph_context->_log &&
- !g_ceph_context->_log->is_inside_log_lock()) {
- // dump to log. this uses the heap extensively, but we're better
- // off trying than not.
- derr << buf << std::endl;
- bt.print(*_dout);
- *_dout << " NOTE: a copy of the executable, or `objdump -rdS <executable>` "
- << "is needed to interpret this.\n"
- << dendl;
-
- g_ceph_context->_log->dump_recent();
- }
-
- reraise_fatal(signum);
-}
-
-void install_standard_sighandlers(void)
-{
- install_sighandler(SIGSEGV, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGABRT, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGBUS, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGILL, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGFPE, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGXCPU, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGXFSZ, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
- install_sighandler(SIGSYS, handle_fatal_signal, SA_RESETHAND | SA_NODEFER);
-}
-
-
-
-/// --- safe handler ---
-
-#include "common/Thread.h"
-#include <errno.h>
-
-string get_name_by_pid(pid_t pid)
-{
- char proc_pid_path[PATH_MAX] = {0};
- snprintf(proc_pid_path, PATH_MAX, PROCPREFIX "/proc/%d/cmdline", pid);
- int fd = open(proc_pid_path, O_RDONLY);
-
- if (fd < 0) {
- fd = -errno;
- derr << "Fail to open '" << proc_pid_path
- << "' error = " << cpp_strerror(fd)
- << dendl;
- return "<unknown>";
- }
- // assuming the cmdline length does not exceed PATH_MAX. if it
- // really does, it's fine to return a truncated version.
- char buf[PATH_MAX] = {0};
- int ret = read(fd, buf, sizeof(buf));
- close(fd);
- if (ret < 0) {
- ret = -errno;
- derr << "Fail to read '" << proc_pid_path
- << "' error = " << cpp_strerror(ret)
- << dendl;
- return "<unknown>";
- }
- std::replace(buf, buf + ret, '\0', ' ');
- return string(buf, ret);
-}
-
-
-/**
- * safe async signal handler / dispatcher
- *
- * This is an async unix signal handler based on the design from
- *
- * http://evbergen.home.xs4all.nl/unix-signals.html
- *
- * Features:
- * - no unsafe work is done in the signal handler itself
- * - callbacks are called from a regular thread
- * - signals are not lost, unless multiple instances of the same signal
- * are sent twice in quick succession.
- */
-struct SignalHandler : public Thread {
- /// to kick the thread, for shutdown, new handlers, etc.
- int pipefd[2]; // write to [1], read from [0]
-
- /// to signal shutdown
- bool stop;
-
- /// for an individual signal
- struct safe_handler {
-
- safe_handler() {
- memset(pipefd, 0, sizeof(pipefd));
- memset(&handler, 0, sizeof(handler));
- memset(&info_t, 0, sizeof(info_t));
- }
-
- siginfo_t info_t;
- int pipefd[2]; // write to [1], read from [0]
- signal_handler_t handler;
- };
-
- /// all handlers
- safe_handler *handlers[32] = {nullptr};
-
- /// to protect the handlers array
- Mutex lock;
-
- SignalHandler()
- : stop(false), lock("SignalHandler::lock")
- {
- // create signal pipe
- int r = pipe(pipefd);
- assert(r == 0);
- r = fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
- assert(r == 0);
-
- // create thread
- create("signal_handler");
- }
-
- ~SignalHandler() override {
- shutdown();
- }
-
- void signal_thread() {
- int r = write(pipefd[1], "\0", 1);
- assert(r == 1);
- }
-
- void shutdown() {
- stop = true;
- signal_thread();
- join();
- }
-
- // thread entry point
- void *entry() override {
- while (!stop) {
- // build fd list
- struct pollfd fds[33];
-
- lock.Lock();
- int num_fds = 0;
- fds[num_fds].fd = pipefd[0];
- fds[num_fds].events = POLLIN | POLLERR;
- fds[num_fds].revents = 0;
- ++num_fds;
- for (unsigned i=0; i<32; i++) {
- if (handlers[i]) {
- fds[num_fds].fd = handlers[i]->pipefd[0];
- fds[num_fds].events = POLLIN | POLLERR;
- fds[num_fds].revents = 0;
- ++num_fds;
- }
- }
- lock.Unlock();
-
- // wait for data on any of those pipes
- int r = poll(fds, num_fds, -1);
- if (stop)
- break;
- if (r > 0) {
- char v;
-
- // consume byte from signal socket, if any.
- TEMP_FAILURE_RETRY(read(pipefd[0], &v, 1));
-
- lock.Lock();
- for (unsigned signum=0; signum<32; signum++) {
- if (handlers[signum]) {
- r = read(handlers[signum]->pipefd[0], &v, 1);
- if (r == 1) {
- siginfo_t * siginfo = &handlers[signum]->info_t;
- string task_name = get_name_by_pid(siginfo->si_pid);
- derr << "received signal: " << sig_str(signum)
- << " from " << " PID: " << siginfo->si_pid
- << " task name: " << task_name
- << " UID: " << siginfo->si_uid
- << dendl;
- handlers[signum]->handler(signum);
- }
- }
- }
- lock.Unlock();
- }
- }
- return NULL;
- }
-
- void queue_signal(int signum) {
- // If this signal handler is registered, the callback must be
- // defined. We can do this without the lock because we will never
- // have the signal handler defined without the handlers entry also
- // being filled in.
- assert(handlers[signum]);
- int r = write(handlers[signum]->pipefd[1], " ", 1);
- assert(r == 1);
- }
-
- void queue_signal_info(int signum, siginfo_t *siginfo, void * content) {
- // If this signal handler is registered, the callback must be
- // defined. We can do this without the lock because we will never
- // have the signal handler defined without the handlers entry also
- // being filled in.
- assert(handlers[signum]);
- memcpy(&handlers[signum]->info_t, siginfo, sizeof(siginfo_t));
- int r = write(handlers[signum]->pipefd[1], " ", 1);
- assert(r == 1);
- }
-
- void register_handler(int signum, signal_handler_t handler, bool oneshot);
- void unregister_handler(int signum, signal_handler_t handler);
-};
-
-static SignalHandler *g_signal_handler = NULL;
-
-static void handler_signal_hook(int signum, siginfo_t * siginfo, void * content) {
- g_signal_handler->queue_signal_info(signum, siginfo, content);
-}
-
-void SignalHandler::register_handler(int signum, signal_handler_t handler, bool oneshot)
-{
- int r;
-
- assert(signum >= 0 && signum < 32);
-
- safe_handler *h = new safe_handler;
-
- r = pipe(h->pipefd);
- assert(r == 0);
- r = fcntl(h->pipefd[0], F_SETFL, O_NONBLOCK);
- assert(r == 0);
-
- h->handler = handler;
- lock.Lock();
- handlers[signum] = h;
- lock.Unlock();
-
- // signal thread so that it sees our new handler
- signal_thread();
-
- // install our handler
- struct sigaction oldact;
- struct sigaction act;
- memset(&act, 0, sizeof(act));
-
- act.sa_handler = (signal_handler_t)handler_signal_hook;
- sigfillset(&act.sa_mask); // mask all signals in the handler
- act.sa_flags = SA_SIGINFO | (oneshot ? SA_RESETHAND : 0);
- int ret = sigaction(signum, &act, &oldact);
- assert(ret == 0);
-}
-
-void SignalHandler::unregister_handler(int signum, signal_handler_t handler)
-{
- assert(signum >= 0 && signum < 32);
- safe_handler *h = handlers[signum];
- assert(h);
- assert(h->handler == handler);
-
- // restore to default
- signal(signum, SIG_DFL);
-
- // _then_ remove our handlers entry
- lock.Lock();
- handlers[signum] = NULL;
- lock.Unlock();
-
- // this will wake up select() so that worker thread sees our handler is gone
- close(h->pipefd[0]);
- close(h->pipefd[1]);
- delete h;
-}
-
-
-// -------
-
-void init_async_signal_handler()
-{
- assert(!g_signal_handler);
- g_signal_handler = new SignalHandler;
-}
-
-void shutdown_async_signal_handler()
-{
- assert(g_signal_handler);
- delete g_signal_handler;
- g_signal_handler = NULL;
-}
-
-void queue_async_signal(int signum)
-{
- assert(g_signal_handler);
- g_signal_handler->queue_signal(signum);
-}
-
-void register_async_signal_handler(int signum, signal_handler_t handler)
-{
- assert(g_signal_handler);
- g_signal_handler->register_handler(signum, handler, false);
-}
-
-void register_async_signal_handler_oneshot(int signum, signal_handler_t handler)
-{
- assert(g_signal_handler);
- g_signal_handler->register_handler(signum, handler, true);
-}
-
-void unregister_async_signal_handler(int signum, signal_handler_t handler)
-{
- assert(g_signal_handler);
- g_signal_handler->unregister_handler(signum, handler);
-}
-
-
-