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- ...@@ -77,7 +77,7 @@ Unsupported libevent event types, and why-
* TIMEOUT - this library has specific timeout support, instead of * TIMEOUT - this library has specific timeout support, instead of
being attached to read/write fds. being attached to read/write fds.
* SIGNAL - similarly, signals are handled separately, see * SIGNAL - similarly, signals are handled separately, see
AsyncSignalHandler (TODO:currently in fbthrift) AsyncSignalHandler
* EV_ET - Currently all the implementations of EventHandler are set up * EV_ET - Currently all the implementations of EventHandler are set up
for level triggered. Benchmarking hasn't shown that edge triggered for level triggered. Benchmarking hasn't shown that edge triggered
provides much improvement. provides much improvement.
...@@ -249,9 +249,7 @@ per application. Using HHWheelTimer instead can clean up the code quite ...@@ -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 a bit, because only a single HHWheelTimer is needed per thread, as
opposed to one AsyncTimeoutSet per timeout time per thread. opposed to one AsyncTimeoutSet per timeout time per thread.
### TAsyncSignalHandler ### AsyncSignalHandler
TODO: still in fbthrift
Used to handle AsyncSignals. Similar to AsyncTimeout, for code Used to handle AsyncSignals. Similar to AsyncTimeout, for code
clarity, we don't reuse the same fd as a socket to receive signals. 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