0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-25 21:38:18 +02:00

ircd: Break down client shutdown; improve various shutdown refusals.

This commit is contained in:
Jason Volk 2018-03-12 13:30:24 -07:00
parent cabeb4c128
commit a22e45a9f5
4 changed files with 116 additions and 52 deletions

View file

@ -19,8 +19,6 @@ namespace ircd
char *read(client &, char *&start, char *const &stop);
parse::read_closure read_closure(client &);
void close_all_clients();
std::shared_ptr<client> add_client(std::shared_ptr<socket>); // Creates a client.
}
@ -42,6 +40,10 @@ struct ircd::client
static struct conf default_conf;
static ctx::pool context;
static void interrupt_all();
static void close_all();
static void wait_all();
struct conf *conf {&default_conf};
unique_buffer<mutable_buffer> head_buffer;
unique_buffer<mutable_buffer> content_buffer;
@ -106,6 +108,8 @@ struct ircd::client::settings
struct ircd::client::init
{
void interrupt();
void close();
void wait();
init();
~init() noexcept;

View file

@ -12,6 +12,8 @@
namespace ircd
{
ctx::dock dock;
template<class... args> std::shared_ptr<client> make_client(args&&...);
}
@ -49,45 +51,110 @@ ircd::client::init::init()
context.add(settings.pool_size);
}
void
ircd::client::init::interrupt()
{
if(context.active() || !client::list.empty())
log::warning("Interrupting %zu requests; dropping %zu requests; closing %zu clients...",
context.active(),
context.pending(),
client::list.size());
context.interrupt();
close_all_clients();
}
ircd::client::init::~init()
noexcept
{
interrupt();
close();
wait();
assert(client::list.empty());
}
if(context.active())
log::warning("Joining %zu active of %zu remaining request contexts...",
context.active(),
context.size());
else
log::debug("Waiting for %zu request contexts to join...",
context.size());
void
ircd::client::init::interrupt()
{
interrupt_all();
}
context.join();
void
ircd::client::init::close()
{
close_all();
}
if(unlikely(!client::list.empty()))
{
log::error("%zu clients are unterminated...", client::list.size());
assert(client::list.empty());
}
void
ircd::client::init::wait()
{
wait_all();
}
//
// util
//
void
ircd::client::interrupt_all()
{
if(context.active())
log::warning
{
"Interrupting %zu requests; dropping %zu requests...",
context.active(),
context.pending()
};
context.interrupt();
}
void
ircd::client::close_all()
{
if(!client::list.empty())
log::debug
{
"Closing %zu clients", client::list.size()
};
auto it(begin(client::list));
while(it != end(client::list))
{
auto c(shared_from(**it)); ++it; try
{
c->close(net::dc::RST, [c](const auto &e)
{
dock.notify_one();
});
}
catch(const std::exception &e)
{
log::warning
{
"Error disconnecting client @%p: %s", c.get(), e.what()
};
}
}
}
void
ircd::client::wait_all()
{
if(context.active())
log::warning
{
"Joining %zu active of %zu remaining request contexts...",
context.active(),
context.size()
};
else
log::debug
{
"Waiting for %zu request contexts to join...",
context.size()
};
context.join();
while(!client::list.empty())
{
if(dock.wait_for(seconds(2)) == ctx::cv_status::no_timeout)
continue;
log::warning
{
"Waiting for %zu clients to close...", client::list.size()
};
}
}
ircd::parse::read_closure
ircd::read_closure(client &client)
{
@ -122,6 +189,17 @@ ircd::read(client &client,
std::shared_ptr<ircd::client>
ircd::add_client(std::shared_ptr<socket> s)
{
if(unlikely(ircd::runlevel != ircd::runlevel::RUN))
{
log::warning
{
"Refusing to add new client in runlevel %s", reflect(ircd::runlevel)
};
net::close(*s, net::dc::RST, net::close_ignore);
return {};
}
const auto client
{
make_client(std::move(s))
@ -138,24 +216,6 @@ ircd::make_client(args&&... a)
return std::make_shared<client>(std::forward<args>(a)...);
}
void
ircd::close_all_clients()
{
auto it(begin(client::list));
while(it != end(client::list))
{
auto *const client(*it);
++it; try
{
client->close(net::dc::RST, net::close_ignore);
}
catch(const std::exception &e)
{
log::warning("Error disconnecting client @%p: %s", client, e.what());
}
}
}
ircd::ipport
ircd::local(const client &client)
{

View file

@ -211,6 +211,9 @@ try
_server_.interrupt();
_client_.interrupt();
_server_.close();
_client_.close();
_server_.wait();
_client_.wait();
}};
// When the call to wait() below completes, IRCd exits from the RUN state

View file

@ -13,7 +13,6 @@
namespace ircd::server
{
// Internal state
bool ready; // like an /etc/nologin to prevent actions when false.
ctx::dock dock; // internal semaphore
// Internal util
@ -215,7 +214,6 @@ ircd::server::accumulate_peers(F&& closure)
ircd::server::init::init()
{
ready = true;
}
ircd::server::init::~init()
@ -235,7 +233,6 @@ ircd::server::init::wait()
void
ircd::server::init::close()
{
ready = false;
close_all();
}
@ -305,7 +302,7 @@ void
ircd::server::submit(const hostport &hostport,
request &request)
{
if(unlikely(!server::ready))
if(unlikely(ircd::runlevel != ircd::runlevel::RUN))
throw unavailable
{
"Unable to fulfill requests at this time."
@ -428,7 +425,7 @@ void
ircd::server::peer::submit(request &request)
try
{
if(!err_check() || unlikely(!server::ready))
if(!err_check() || unlikely(ircd::runlevel != ircd::runlevel::RUN))
throw unavailable
{
"Peer is unable to take any requests: %s", err_msg()
@ -1118,7 +1115,7 @@ ircd::server::link::cancel_uncommitted(std::exception_ptr eptr)
bool
ircd::server::link::open(const net::open_opts &open_opts)
{
assert(server::ready);
assert(ircd::runlevel == ircd::runlevel::RUN);
if(op_init)
return false;