Commit 7eb3e009 authored by octal's avatar octal

Http::Endpoint: added a threaded serving mode that will spawn an acceptor...

Http::Endpoint: added a threaded serving mode that will spawn an acceptor thread rather than running in the same thread
parent 725e53ea
...@@ -93,7 +93,7 @@ struct LoadMonitor { ...@@ -93,7 +93,7 @@ struct LoadMonitor {
~LoadMonitor() { ~LoadMonitor() {
shutdown_ = true; shutdown_ = true;
thread->join(); if (thread) thread->join();
} }
private: private:
...@@ -156,6 +156,9 @@ int main(int argc, char *argv[]) { ...@@ -156,6 +156,9 @@ int main(int argc, char *argv[]) {
monitor.setInterval(std::chrono::seconds(5)); monitor.setInterval(std::chrono::seconds(5));
monitor.start(); monitor.start();
server->serve(); server->serveThreaded();
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "Shutdowning server" << std::endl;
server->shutdown();
monitor.shutdown(); monitor.shutdown();
} }
...@@ -587,16 +587,19 @@ Endpoint::setHandler(const std::shared_ptr<Handler>& handler) { ...@@ -587,16 +587,19 @@ Endpoint::setHandler(const std::shared_ptr<Handler>& handler) {
void void
Endpoint::serve() Endpoint::serve()
{ {
if (!handler_) serveImpl(&Tcp::Listener::run);
throw std::runtime_error("Must call setHandler() prior to serve()"); }
listener.setHandler(handler_); void
Endpoint::serveThreaded()
{
serveImpl(&Tcp::Listener::runThreaded);
}
if (listener.bind()) { void
const auto& addr = listener.address(); Endpoint::shutdown()
cout << "Now listening on " << "http://" + addr.host() << ":" << addr.port() << endl; {
listener.run(); listener.shutdown();
}
} }
Async::Promise<Tcp::Listener::Load> Async::Promise<Tcp::Listener::Load>
......
...@@ -530,6 +530,9 @@ public: ...@@ -530,6 +530,9 @@ public:
void setHandler(const std::shared_ptr<Handler>& handler); void setHandler(const std::shared_ptr<Handler>& handler);
void serve(); void serve();
void serveThreaded();
void shutdown();
bool isBound() const { bool isBound() const {
return listener.isBound(); return listener.isBound();
...@@ -540,6 +543,24 @@ public: ...@@ -540,6 +543,24 @@ public:
static Options options(); static Options options();
private: private:
template<typename Method>
void serveImpl(Method method)
{
#define CALL_MEMBER_FN(obj, pmf) ((obj).*(pmf))
if (!handler_)
throw std::runtime_error("Must call setHandler() prior to serve()");
listener.setHandler(handler_);
if (listener.bind()) {
const auto& addr = listener.address();
std::cout << "Now listening on " << "http://" + addr.host() << ":"
<< addr.port() << std::endl;
CALL_MEMBER_FN(listener, method)();
}
#undef CALL_MEMBER_FN
}
std::shared_ptr<Handler> handler_; std::shared_ptr<Handler> handler_;
Net::Tcp::Listener listener; Net::Tcp::Listener listener;
}; };
......
...@@ -38,6 +38,8 @@ To *message_cast(const std::unique_ptr<Message>& from) ...@@ -38,6 +38,8 @@ To *message_cast(const std::unique_ptr<Message>& from)
IoWorker::IoWorker() { IoWorker::IoWorker() {
timerFd = TRY_RET(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)); timerFd = TRY_RET(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
poller.addFd(timerFd, Polling::NotifyOn::Read, Polling::Tag(timerFd)); poller.addFd(timerFd, Polling::NotifyOn::Read, Polling::Tag(timerFd));
notifier.bind(poller);
} }
IoWorker::~IoWorker() { IoWorker::~IoWorker() {
...@@ -234,9 +236,6 @@ IoWorker::run() { ...@@ -234,9 +236,6 @@ IoWorker::run() {
mailbox.bind(poller); mailbox.bind(poller);
writesQueue.bind(poller); writesQueue.bind(poller);
auto n = notifier.tag();
poller.addFd(n.value(), NotifyOn::Read, n, Polling::Mode::Edge);
std::chrono::milliseconds timeout(-1); std::chrono::milliseconds timeout(-1);
for (;;) { for (;;) {
......
...@@ -29,12 +29,17 @@ namespace Tcp { ...@@ -29,12 +29,17 @@ namespace Tcp {
namespace { namespace {
volatile sig_atomic_t g_listen_fd = -1; volatile sig_atomic_t g_listen_fd = -1;
void handle_sigint(int) { void closeListener() {
if (g_listen_fd != -1) { if (g_listen_fd != -1) {
close(g_listen_fd); ::close(g_listen_fd);
g_listen_fd = -1; g_listen_fd = -1;
} }
} }
void handle_sigint(int) {
std::cout << "Received C-c, closing listen fd!" << std::endl;
closeListener();
}
} }
using Polling::NotifyOn; using Polling::NotifyOn;
...@@ -76,6 +81,11 @@ Listener::Listener(const Address& address) ...@@ -76,6 +81,11 @@ Listener::Listener(const Address& address)
{ {
} }
Listener::~Listener() {
shutdown();
if (acceptThread) acceptThread->join();
}
void void
Listener::init(size_t workers, Flags<Options> options, int backlog) Listener::init(size_t workers, Flags<Options> options, int backlog)
{ {
...@@ -168,7 +178,8 @@ Listener::bind(const Address& address) { ...@@ -168,7 +178,8 @@ Listener::bind(const Address& address) {
TRY(::listen(fd, backlog_)); TRY(::listen(fd, backlog_));
} }
make_non_blocking(fd);
poller.addFd(fd, Polling::NotifyOn::Write, Polling::Tag(fd), Polling::Mode::Edge);
listen_fd = fd; listen_fd = fd;
g_listen_fd = fd; g_listen_fd = fd;
...@@ -187,31 +198,43 @@ Listener::isBound() const { ...@@ -187,31 +198,43 @@ Listener::isBound() const {
void void
Listener::run() { Listener::run() {
for (;;) { for (;;) {
struct sockaddr_in peer_addr; std::vector<Polling::Event> events;
socklen_t peer_addr_len = sizeof(peer_addr);
int client_fd = ::accept(listen_fd, (struct sockaddr *)&peer_addr, &peer_addr_len); int ready_fds = poller.poll(events, 128, std::chrono::milliseconds(-1));
if (client_fd < 0) { if (ready_fds == -1) {
if (g_listen_fd == -1) { if (errno == EINTR && g_listen_fd == -1) return;
cout << "SIGINT Signal received, shutdowning !" << endl; throw Error::system("Polling");
shutdown(); }
break; else if (ready_fds > 0) {
for (const auto& event: events) {
} else { if (event.tag == shutdownFd.tag())
throw std::runtime_error(strerror(errno)); return;
else {
if (event.flags.hasFlag(Polling::NotifyOn::Write)) {
auto fd = event.tag.value();
if (fd == listen_fd)
handleNewConnection();
}
}
} }
} }
make_non_blocking(client_fd);
auto peer = make_shared<Peer>(Address::fromUnix((struct sockaddr *)&peer_addr));
peer->associateFd(client_fd);
dispatchPeer(peer);
} }
} }
void
Listener::runThreaded() {
shutdownFd.bind(poller);
acceptThread.reset(new std::thread([=]() { this->run(); }));
}
void void
Listener::shutdown() { Listener::shutdown() {
if (shutdownFd.isBound()) shutdownFd.notify();
shutdownIo();
}
void
Listener::shutdownIo() {
for (auto &worker: ioGroup) { for (auto &worker: ioGroup) {
worker->shutdown(); worker->shutdown();
} }
...@@ -277,6 +300,23 @@ Listener::options() const { ...@@ -277,6 +300,23 @@ Listener::options() const {
return options_; return options_;
} }
void
Listener::handleNewConnection() {
struct sockaddr_in peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
int client_fd = ::accept(listen_fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
if (client_fd < 0) {
throw std::runtime_error(strerror(errno));
}
make_non_blocking(client_fd);
auto peer = make_shared<Peer>(Address::fromUnix((struct sockaddr *)&peer_addr));
peer->associateFd(client_fd);
dispatchPeer(peer);
}
void void
Listener::dispatchPeer(const std::shared_ptr<Peer>& peer) { Listener::dispatchPeer(const std::shared_ptr<Peer>& peer) {
const size_t workers = ioGroup.size(); const size_t workers = ioGroup.size();
......
...@@ -36,6 +36,7 @@ public: ...@@ -36,6 +36,7 @@ public:
}; };
Listener(); Listener();
~Listener();
Listener(const Address& address); Listener(const Address& address);
void init( void init(
...@@ -49,6 +50,8 @@ public: ...@@ -49,6 +50,8 @@ public:
bool isBound() const; bool isBound() const;
void run(); void run();
void runThreaded();
void shutdown(); void shutdown();
Async::Promise<Load> requestLoad(const Load& old); Async::Promise<Load> requestLoad(const Load& old);
...@@ -62,12 +65,18 @@ private: ...@@ -62,12 +65,18 @@ private:
Address addr_; Address addr_;
int listen_fd; int listen_fd;
int backlog_; int backlog_;
NotifyFd shutdownFd;
Polling::Epoll poller;
std::vector<std::unique_ptr<IoWorker>> ioGroup; std::vector<std::unique_ptr<IoWorker>> ioGroup;
Flags<Options> options_; Flags<Options> options_;
std::shared_ptr<Handler> handler_; std::shared_ptr<Handler> handler_;
std::unique_ptr<std::thread> acceptThread;
void shutdownIo();
void handleNewConnection();
void dispatchPeer(const std::shared_ptr<Peer>& peer); void dispatchPeer(const std::shared_ptr<Peer>& peer);
void runLoadThread();
}; };
} // namespace Tcp } // namespace Tcp
......
...@@ -119,7 +119,7 @@ Error::system(const char* message) { ...@@ -119,7 +119,7 @@ Error::system(const char* message) {
const char *err = strerror(errno); const char *err = strerror(errno);
std::string str(message); std::string str(message);
str += ':'; str += ": ";
str += err; str += err;
return Error(std::move(str)); return Error(std::move(str));
......
...@@ -238,8 +238,18 @@ namespace Polling { ...@@ -238,8 +238,18 @@ namespace Polling {
} // namespace Poller } // namespace Poller
NotifyFd::NotifyFd() { Polling::Tag
NotifyFd::bind(Polling::Epoll& poller) {
event_fd = TRY_RET(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)); event_fd = TRY_RET(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
Polling::Tag tag(event_fd);
poller.addFd(event_fd, Polling::NotifyOn::Read, tag, Polling::Mode::Edge);
return Polling::Tag(event_fd);
}
bool
NotifyFd::isBound() const {
return event_fd != -1;
} }
Polling::Tag Polling::Tag
...@@ -249,12 +259,16 @@ NotifyFd::tag() const { ...@@ -249,12 +259,16 @@ NotifyFd::tag() const {
void void
NotifyFd::notify() const { NotifyFd::notify() const {
if (!isBound())
throw std::runtime_error("Can not notify an unbound fd");
eventfd_t val = 1; eventfd_t val = 1;
TRY(eventfd_write(event_fd, val)); TRY(eventfd_write(event_fd, val));
} }
void void
NotifyFd::read() const { NotifyFd::read() const {
if (!isBound())
throw std::runtime_error("Can not read an unbound fd");
eventfd_t val; eventfd_t val;
TRY(eventfd_read(event_fd, &val)); TRY(eventfd_read(event_fd, &val));
} }
......
...@@ -115,7 +115,12 @@ private: ...@@ -115,7 +115,12 @@ private:
class NotifyFd { class NotifyFd {
public: public:
NotifyFd(); NotifyFd()
: event_fd(-1)
{ }
Polling::Tag bind(Polling::Epoll& poller);
bool isBound() const;
Polling::Tag tag() const; Polling::Tag tag() const;
......
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