Commit aa1bdc3e authored by Kenton Varda's avatar Kenton Varda

Allow setting of a different reserved signal than SIGUSR1.

parent bc56e509
...@@ -32,6 +32,9 @@ namespace kj { ...@@ -32,6 +32,9 @@ namespace kj {
namespace { namespace {
int reservedSignal = SIGUSR1;
bool tooLateToSetReserved = false;
struct SignalCapture { struct SignalCapture {
sigjmp_buf jumpTo; sigjmp_buf jumpTo;
siginfo_t siginfo; siginfo_t siginfo;
...@@ -48,6 +51,8 @@ void signalHandler(int, siginfo_t* siginfo, void*) { ...@@ -48,6 +51,8 @@ void signalHandler(int, siginfo_t* siginfo, void*) {
} }
void registerSignalHandler(int signum) { void registerSignalHandler(int signum) {
tooLateToSetReserved = true;
sigset_t mask; sigset_t mask;
sigemptyset(&mask); sigemptyset(&mask);
sigaddset(&mask, signum); sigaddset(&mask, signum);
...@@ -61,14 +66,14 @@ void registerSignalHandler(int signum) { ...@@ -61,14 +66,14 @@ void registerSignalHandler(int signum) {
sigaction(signum, &action, nullptr); sigaction(signum, &action, nullptr);
} }
void registerSigusr1() { void registerReservedSignal() {
registerSignalHandler(SIGUSR1); registerSignalHandler(reservedSignal);
// We also disable SIGPIPE because users of UnixEventLoop almost certainly don't want it. // We also disable SIGPIPE because users of UnixEventLoop almost certainly don't want it.
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
} }
pthread_once_t registerSigusr1Once = PTHREAD_ONCE_INIT; pthread_once_t registerReservedSignalOnce = PTHREAD_ONCE_INIT;
} // namespace } // namespace
...@@ -156,7 +161,7 @@ public: ...@@ -156,7 +161,7 @@ public:
}; };
UnixEventPort::UnixEventPort() { UnixEventPort::UnixEventPort() {
pthread_once(&registerSigusr1Once, &registerSigusr1); pthread_once(&registerReservedSignalOnce, &registerReservedSignal);
} }
UnixEventPort::~UnixEventPort() {} UnixEventPort::~UnixEventPort() {}
...@@ -170,10 +175,28 @@ Promise<siginfo_t> UnixEventPort::onSignal(int signum) { ...@@ -170,10 +175,28 @@ Promise<siginfo_t> UnixEventPort::onSignal(int signum) {
} }
void UnixEventPort::captureSignal(int signum) { void UnixEventPort::captureSignal(int signum) {
KJ_REQUIRE(signum != SIGUSR1, "Sorry, SIGUSR1 is reserved by the UnixEventPort implementation."); if (reservedSignal == SIGUSR1) {
KJ_REQUIRE(signum != SIGUSR1,
"Sorry, SIGUSR1 is reserved by the UnixEventPort implementation. You may call "
"UnixEventPort::setReservedSignal() to reserve a different signal.");
} else {
KJ_REQUIRE(signum != reservedSignal,
"Can't capture signal reserved using setReservedSignal().", signum);
}
registerSignalHandler(signum); registerSignalHandler(signum);
} }
void UnixEventPort::setReservedSignal(int signum) {
KJ_REQUIRE(!tooLateToSetReserved,
"setReservedSignal() must be called before any calls to `captureSignal()` and "
"before any `UnixEventPort` is constructed.");
if (reservedSignal != SIGUSR1 && reservedSignal != signum) {
KJ_FAIL_REQUIRE("Detected multiple conflicting calls to setReservedSignal(). Please only "
"call this once, or always call it with the same signal number.");
}
reservedSignal = signum;
}
class UnixEventPort::PollContext { class UnixEventPort::PollContext {
public: public:
PollContext(PollPromiseAdapter* ptr) { PollContext(PollPromiseAdapter* ptr) {
...@@ -224,7 +247,7 @@ private: ...@@ -224,7 +247,7 @@ private:
void UnixEventPort::wait() { void UnixEventPort::wait() {
sigset_t newMask; sigset_t newMask;
sigemptyset(&newMask); sigemptyset(&newMask);
sigaddset(&newMask, SIGUSR1); sigaddset(&newMask, reservedSignal);
{ {
auto ptr = signalHead; auto ptr = signalHead;
...@@ -243,7 +266,7 @@ void UnixEventPort::wait() { ...@@ -243,7 +266,7 @@ void UnixEventPort::wait() {
// We received a signal and longjmp'd back out of the signal handler. // We received a signal and longjmp'd back out of the signal handler.
threadCapture = nullptr; threadCapture = nullptr;
if (capture.siginfo.si_signo != SIGUSR1) { if (capture.siginfo.si_signo != reservedSignal) {
gotSignal(capture.siginfo); gotSignal(capture.siginfo);
} }
......
...@@ -43,8 +43,9 @@ class UnixEventPort: public EventPort { ...@@ -43,8 +43,9 @@ class UnixEventPort: public EventPort {
// just before `poll()` while using a signal handler which `siglongjmp()`s back to just before // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before
// the signal was unblocked, or it may use a nicer platform-specific API like signalfd. // the signal was unblocked, or it may use a nicer platform-specific API like signalfd.
// //
// The implementation uses SIGUSR1. The application must avoid using this signal for its own // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you
// purposes. // need to use SIGUSR1 for something else, you must offer a different signal by calling
// setReservedSignal() at startup.
public: public:
UnixEventPort(); UnixEventPort();
...@@ -79,6 +80,11 @@ public: ...@@ -79,6 +80,11 @@ public:
// To un-capture a signal, simply install a different signal handler and then un-block it from // To un-capture a signal, simply install a different signal handler and then un-block it from
// the signal mask. // the signal mask.
static void setReservedSignal(int signum);
// Sets the signal number which `UnixEventPort` reserves for internal use. If your application
// needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before
// constructing an `UnixEventPort`) to offer a different signal.
// implements EventPort ------------------------------------------------------ // implements EventPort ------------------------------------------------------
void wait() override; void wait() override;
void poll() override; void poll() override;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment