mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-07 02:32:32 +00:00
2cd70f4342
signal() is known to have portability problems. Some systems such as old Unix systems and System V employ a behavior in which the signal disposition is reset to SIG_DFL (default) upon invocation of a signal handler by the delivery of a signal. See issue #51 in which Solaris users experience signal-based issues. Solaris is a system which employs the SIG_DFL reset behavior even in version 11.1. See http://docs.oracle.com/cd/E26502_01/html/E29034/signal-3c.html > If signal() is used, disp is the address of a signal handler, and sig is not SIGILL, > SIGTRAP, or SIGPWR, the system first sets the signal's disposition to SIG_DFL before > executing the signal handler. On Solaris the default signal disposition for SIGUSR1 is to exit the application. See http://docs.oracle.com/cd/E26502_01/html/E29033/signal.h-3head.html If I'm correct in assuming this is the problem Solaris users are encountering, the solution to this (and likely any other portability issues that may arise) is to use sigaction() which has explicitly defined behavior as per the POSIX standards. As you can see, it's a pretty drop-in solution. In fact, on some systems such as Linux, glibc defines signal() as a wrapper around sigaction() to use BSD semantics (i.e. not the behavior detailed above), which is likely why few others have experienced these problems. See http://man7.org/linux/man-pages/man2/signal.2.html
144 lines
4.3 KiB
C++
144 lines
4.3 KiB
C++
// rTorrent - BitTorrent client
|
|
// Copyright (C) 2005-2011, Jari Sundell
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// In addition, as a special exception, the copyright holders give
|
|
// permission to link the code of portions of this program with the
|
|
// OpenSSL library under certain conditions as described in each
|
|
// individual source file, and distribute linked combinations
|
|
// including the two.
|
|
//
|
|
// You must obey the GNU General Public License in all respects for
|
|
// all of the code used other than OpenSSL. If you modify file(s)
|
|
// with this exception, you may extend this exception to your version
|
|
// of the file(s), but you are not obligated to do so. If you do not
|
|
// wish to do so, delete this exception statement from your version.
|
|
// If you delete this exception statement from all source files in the
|
|
// program, then also delete it here.
|
|
//
|
|
// Contact: Jari Sundell <jaris@ifi.uio.no>
|
|
//
|
|
// Skomakerveien 33
|
|
// 3185 Skoppum, NORWAY
|
|
|
|
#include "config.h"
|
|
|
|
#include <signal.h>
|
|
#include <stdexcept>
|
|
#include "rak/error_number.h"
|
|
#include "signal_handler.h"
|
|
|
|
#ifdef __sun__
|
|
#include <iso/signal_iso.h>
|
|
//extern "C" void (*signal (int sig, void (*disp)(int)))(int);
|
|
#endif
|
|
|
|
SignalHandler::Slot SignalHandler::m_handlers[HIGHEST_SIGNAL];
|
|
|
|
void
|
|
SignalHandler::set_default(unsigned int signum) {
|
|
if (signum > HIGHEST_SIGNAL)
|
|
throw std::logic_error("SignalHandler::set_default(...) received invalid signal value.");
|
|
|
|
signal(signum, SIG_DFL);
|
|
m_handlers[signum].disconnect();
|
|
}
|
|
|
|
void
|
|
SignalHandler::set_ignore(unsigned int signum) {
|
|
if (signum > HIGHEST_SIGNAL)
|
|
throw std::logic_error("SignalHandler::set_ignore(...) received invalid signal value.");
|
|
|
|
signal(signum, SIG_IGN);
|
|
m_handlers[signum].disconnect();
|
|
}
|
|
|
|
void
|
|
SignalHandler::set_handler(unsigned int signum, Slot slot) {
|
|
if (signum > HIGHEST_SIGNAL)
|
|
throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value.");
|
|
|
|
if (slot.empty())
|
|
throw std::logic_error("SignalHandler::set_handler(...) received an empty slot.");
|
|
|
|
struct sigaction sa;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = &SignalHandler::caught;
|
|
|
|
sigaction(signum, &sa, NULL);
|
|
|
|
m_handlers[signum] = slot;
|
|
}
|
|
|
|
void
|
|
SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) {
|
|
if (signum > HIGHEST_SIGNAL)
|
|
throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value.");
|
|
|
|
struct sigaction sa;
|
|
sa.sa_sigaction = slot;
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
if (sigaction(signum, &sa, NULL) == -1)
|
|
throw std::logic_error("Could not set sigaction: " + std::string(rak::error_number::current().c_str()));
|
|
}
|
|
|
|
void
|
|
SignalHandler::caught(int signum) {
|
|
if ((unsigned)signum > HIGHEST_SIGNAL)
|
|
throw std::logic_error("SignalHandler::caught(...) received invalid signal from the kernel, bork bork bork.");
|
|
|
|
if (m_handlers[signum].empty())
|
|
throw std::logic_error("SignalHandler::caught(...) received a signal we don't have a handler for.");
|
|
|
|
m_handlers[signum]();
|
|
}
|
|
|
|
const char*
|
|
SignalHandler::as_string(unsigned int signum) {
|
|
switch (signum) {
|
|
case SIGHUP:
|
|
return "Hangup detected";
|
|
case SIGINT:
|
|
return "Interrupt from keyboard";
|
|
case SIGQUIT:
|
|
return "Quit signal";
|
|
case SIGILL:
|
|
return "Illegal instruction";
|
|
case SIGABRT:
|
|
return "Abort signal";
|
|
case SIGFPE:
|
|
return "Floating point exception";
|
|
case SIGKILL:
|
|
return "Kill signal";
|
|
case SIGSEGV:
|
|
return "Segmentation fault";
|
|
case SIGPIPE:
|
|
return "Broken pipe";
|
|
case SIGALRM:
|
|
return "Timer signal";
|
|
case SIGTERM:
|
|
return "Termination signal";
|
|
case SIGBUS:
|
|
return "Bus error";
|
|
default:
|
|
return "Unlisted";
|
|
}
|
|
}
|