-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extract SignalHandler class for re-use #282
Changes from 9 commits
b973b75
fb5c434
1bd1d31
fcba594
ce5ead6
3f99119
111ba5d
89dfdf6
c457af6
e665347
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include "common/signal_handler.h" | ||
|
||
#include <csignal> | ||
|
||
#include "external/envoy/source/common/common/assert.h" | ||
#include "external/envoy/source/common/common/macros.h" | ||
|
||
namespace Nighthawk { | ||
|
||
namespace { | ||
std::function<void(int)> signal_handler_delegate; | ||
void signal_handler(int signal) { signal_handler_delegate(signal); } | ||
} // namespace | ||
|
||
SignalHandler::SignalHandler(const std::function<void()>& signal_callback) { | ||
pipe_fds_.resize(2); | ||
// The shutdown thread will be notified of by our signal handler and take it from there. | ||
RELEASE_ASSERT(pipe(pipe_fds_.data()) == 0, "pipe failed"); | ||
|
||
shutdown_thread_ = std::thread([this, signal_callback]() { | ||
int tmp; | ||
RELEASE_ASSERT(read(pipe_fds_[0], &tmp, sizeof(int)) >= 0, "read failed"); | ||
RELEASE_ASSERT(close(pipe_fds_[0]) == 0, "read side close failed"); | ||
RELEASE_ASSERT(close(pipe_fds_[1]) == 0, "write side close failed"); | ||
pipe_fds_.clear(); | ||
signal_callback(); | ||
}); | ||
|
||
signal_handler_delegate = [this](int) { onSignal(); }; | ||
signal(SIGTERM, signal_handler); | ||
signal(SIGINT, signal_handler); | ||
} | ||
|
||
SignalHandler::~SignalHandler() { | ||
initiateShutdown(); | ||
if (shutdown_thread_.joinable()) { | ||
shutdown_thread_.join(); | ||
} | ||
} | ||
|
||
void SignalHandler::initiateShutdown() { | ||
if (pipe_fds_.size() == 2) { | ||
const int tmp = 0; | ||
RELEASE_ASSERT(write(pipe_fds_[1], &tmp, sizeof(int)) == sizeof(int), "write failed"); | ||
} | ||
} | ||
|
||
void SignalHandler::onSignal() { initiateShutdown(); } | ||
|
||
} // namespace Nighthawk |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#pragma once | ||
|
||
#include <functional> | ||
#include <memory> | ||
#include <thread> | ||
#include <vector> | ||
|
||
#include "external/envoy/source/common/common/logger.h" | ||
|
||
namespace Nighthawk { | ||
|
||
using SignalCallback = std::function<void()>; | ||
|
||
class SignalHandler final : public Envoy::Logger::Loggable<Envoy::Logger::Id::main> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's also add documentation for the class including an example of usage. |
||
public: | ||
SignalHandler(const SignalCallback& signal_callback); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add documentation for the constructor? |
||
SignalHandler(SignalHandler const&) = delete; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add a single comment above these two to indicate the intention, something like: // Not copyable or movable. |
||
void operator=(SignalHandler const&) = delete; | ||
~SignalHandler(); | ||
|
||
private: | ||
/** | ||
* Fires on signal reception. | ||
*/ | ||
void onSignal(); | ||
|
||
/** | ||
* Notifies the thread responsible for shutting down the server that it is time to do so, if | ||
* needed. Safe to use in signal handling, and non-blocking. | ||
*/ | ||
void initiateShutdown(); | ||
|
||
std::thread shutdown_thread_; | ||
|
||
// Signal handling needs to be lean so we can't directly initiate shutdown while handling a | ||
// signal. Therefore we write a bite to a this pipe to propagate signal reception. Subsequently, | ||
// the read side will handle the actual shut down of the gRPC service without having to worry | ||
// about signal-safety. | ||
std::vector<int> pipe_fds_; | ||
}; | ||
|
||
using SignalHandlerPtr = std::unique_ptr<SignalHandler>; | ||
|
||
} // namespace Nighthawk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is part of the header - can we document it?