Commit d2711b8a authored by Alan Frindell's avatar Alan Frindell Committed by afrind

Move TAsyncSignalHandler into folly

Summary:
TODO item, trying to remove unecessary dependencies on thrift

Test Plan: Unit tests

Reviewed By: davejwatson@fb.com

Subscribers: doug, fbcode-common-diffs@, davejwatson, andrewcox, alandau, bmatheny, anca, darshan, mshneer, folly-diffs@, bil, yfeldblum, haijunz, chalfant

FB internal diff: D1960215

Signature: t1:1960215:1427920934:8abd7e94c50676b05bf7ff79800df0db1bd04266
parent b6005aa3
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/io/async/AsyncSignalHandler.h>
#include <folly/io/async/EventBase.h>
#include <folly/Conv.h>
using std::make_pair;
using std::pair;
using std::string;
namespace folly {
AsyncSignalHandler::AsyncSignalHandler(EventBase* eventBase)
: eventBase_(eventBase) {
}
AsyncSignalHandler::~AsyncSignalHandler() {
// Unregister any outstanding events
for (SignalEventMap::iterator it = signalEvents_.begin();
it != signalEvents_.end();
++it) {
event_del(&it->second);
}
}
void AsyncSignalHandler::registerSignalHandler(int signum) {
pair<SignalEventMap::iterator, bool> ret =
signalEvents_.insert(make_pair(signum, event()));
if (!ret.second) {
// This signal has already been registered
throw std::runtime_error(folly::to<string>(
"handler already registered for signal ",
signum));
}
struct event* ev = &(ret.first->second);
try {
signal_set(ev, signum, libeventCallback, this);
if (event_base_set(eventBase_->getLibeventBase(), ev) != 0 ) {
throw std::runtime_error(folly::to<string>(
"error initializing event handler for signal ",
signum));
}
if (event_add(ev, nullptr) != 0) {
throw std::runtime_error(folly::to<string>(
"error adding event handler for signal ",
signum));
}
} catch (...) {
signalEvents_.erase(ret.first);
throw;
}
}
void AsyncSignalHandler::unregisterSignalHandler(int signum) {
SignalEventMap::iterator it = signalEvents_.find(signum);
if (it == signalEvents_.end()) {
throw std::runtime_error(folly::to<string>(
"unable to unregister handler for signal ",
signum, ": signal not registered"));
}
event_del(&it->second);
signalEvents_.erase(it);
}
void AsyncSignalHandler::libeventCallback(int signum, short events,
void* arg) {
AsyncSignalHandler* handler = static_cast<AsyncSignalHandler*>(arg);
handler->signalReceived(signum);
}
} // folly
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/io/async/EventBase.h>
#include <event.h>
#include <map>
namespace folly {
/**
* A handler to receive notification about POSIX signals.
*
* TAsyncSignalHandler allows code to process signals from within a EventBase
* loop. Standard signal handlers interrupt execution of the main thread, and
* are run while the main thread is paused. As a result, great care must be
* taken to avoid race conditions if the signal handler has to access or modify
* any data used by the main thread.
*
* TAsyncSignalHandler solves this problem by running the TAsyncSignalHandler
* callback in normal thread of execution, as a EventBase callback.
*
* TAsyncSignalHandler may only be used in a single thread. It will only
* process signals received by the thread where the TAsyncSignalHandler is
* registered. It is the user's responsibility to ensure that signals are
* delivered to the desired thread in multi-threaded programs.
*/
class AsyncSignalHandler {
public:
/**
* Create a new AsyncSignalHandler.
*/
explicit AsyncSignalHandler(EventBase* eventBase);
virtual ~AsyncSignalHandler();
/**
* Register to receive callbacks about the specified signal.
*
* Once the handler has been registered for a particular signal,
* signalReceived() will be called each time this thread receives this
* signal.
*
* Throws a TException if an error occurs, or if this handler is already
* registered for this signal.
*/
void registerSignalHandler(int signum);
/**
* Unregister for callbacks about the specified signal.
*
* Throws a TException if an error occurs, or if this signal was not
* registered.
*/
void unregisterSignalHandler(int signum);
/**
* signalReceived() will called to indicate that the specified signal has
* been received.
*
* signalReceived() will always be invoked from the EventBase loop (i.e.,
* after the main POSIX signal handler has returned control to the EventBase
* thread).
*/
virtual void signalReceived(int signum) noexcept = 0;
private:
typedef std::map<int, struct event> SignalEventMap;
// Forbidden copy constructor and assignment operator
AsyncSignalHandler(AsyncSignalHandler const &);
AsyncSignalHandler& operator=(AsyncSignalHandler const &);
static void libeventCallback(int signum, short events, void* arg);
EventBase* eventBase_;
SignalEventMap signalEvents_;
};
} // folly
......@@ -77,7 +77,7 @@ Unsupported libevent event types, and why-
* TIMEOUT - this library has specific timeout support, instead of
being attached to read/write fds.
* SIGNAL - similarly, signals are handled separately, see
AsyncSignalHandler (TODO:currently in fbthrift)
AsyncSignalHandler
* EV_ET - Currently all the implementations of EventHandler are set up
for level triggered. Benchmarking hasn't shown that edge triggered
provides much improvement.
......@@ -249,9 +249,7 @@ per application. Using HHWheelTimer instead can clean up the code quite
a bit, because only a single HHWheelTimer is needed per thread, as
opposed to one AsyncTimeoutSet per timeout time per thread.
### TAsyncSignalHandler
TODO: still in fbthrift
### AsyncSignalHandler
Used to handle AsyncSignals. Similar to AsyncTimeout, for code
clarity, we don't reuse the same fd as a socket to receive signals.
......
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