Refactor out custom wesnothd_connection_ptr class again
I originally did this in699047766a
and then reverted it in08a866dc20
due to @gfgtdf pointing out the object was never actually destroyed since io_service::stop was never called (issue #1927). This new method foregoes the custom wrapper class and instead waits for the worker thread to terminate in the wesnothd_connection dtor. The use of the wrapper class is also why using thread::detach alone worked (@jyrkive) and using join did not. Additionally, the ptr alias is now of a unique_ptr instead of a shared_ptr. I have verified that the connection dtor is actually called. This new method makes it clearer what's actually going on.
This commit is contained in:
parent
533c7e9822
commit
acc3fe8906
3 changed files with 11 additions and 105 deletions
|
@ -54,7 +54,7 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
|
||||||
{
|
{
|
||||||
DBG_MP << "opening connection" << std::endl;
|
DBG_MP << "opening connection" << std::endl;
|
||||||
|
|
||||||
wesnothd_connection_ptr sock;
|
wesnothd_connection_ptr sock(nullptr);
|
||||||
if(host.empty()) {
|
if(host.empty()) {
|
||||||
return std::make_pair(std::move(sock), config());
|
return std::make_pair(std::move(sock), config());
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
|
||||||
shown_hosts.emplace(host, port);
|
shown_hosts.emplace(host, port);
|
||||||
|
|
||||||
// Initializes the connection to the server.
|
// Initializes the connection to the server.
|
||||||
sock = wesnothd_connection::create(host, std::to_string(port));
|
sock = std::make_unique<wesnothd_connection>(host, std::to_string(port));
|
||||||
if(!sock) {
|
if(!sock) {
|
||||||
return std::make_pair(std::move(sock), config());
|
return std::make_pair(std::move(sock), config());
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,8 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
|
||||||
gui2::dialogs::loading_screen::progress(loading_stage::redirect);
|
gui2::dialogs::loading_screen::progress(loading_stage::redirect);
|
||||||
|
|
||||||
// Open a new connection with the new host and port.
|
// Open a new connection with the new host and port.
|
||||||
sock = wesnothd_connection_ptr();
|
sock.reset();
|
||||||
sock = wesnothd_connection::create(host, std::to_string(port));
|
sock = std::make_unique<wesnothd_connection>(host, std::to_string(port));
|
||||||
|
|
||||||
// Wait for new handshake.
|
// Wait for new handshake.
|
||||||
while(!sock->handshake_finished()) {
|
while(!sock->handshake_finished()) {
|
||||||
|
|
|
@ -80,8 +80,11 @@ wesnothd_connection::wesnothd_connection(const std::string& host, const std::str
|
||||||
|
|
||||||
wesnothd_connection::~wesnothd_connection()
|
wesnothd_connection::~wesnothd_connection()
|
||||||
{
|
{
|
||||||
worker_thread_->detach();
|
|
||||||
MPTEST_LOG;
|
MPTEST_LOG;
|
||||||
|
|
||||||
|
// Stop the io_service and wait for the worker thread to terminate.
|
||||||
|
stop();
|
||||||
|
worker_thread_->join();
|
||||||
}
|
}
|
||||||
|
|
||||||
// main thread
|
// main thread
|
||||||
|
@ -150,9 +153,6 @@ void wesnothd_connection::handle_handshake(const error_code& ec)
|
||||||
recv();
|
recv();
|
||||||
|
|
||||||
worker_thread_.reset(new std::thread([this]() {
|
worker_thread_.reset(new std::thread([this]() {
|
||||||
// worker thread
|
|
||||||
std::shared_ptr<wesnothd_connection> this_ptr = this->shared_from_this();
|
|
||||||
|
|
||||||
io_service_.run();
|
io_service_.run();
|
||||||
LOG_NW << "wesnothd_connection::io_service::run() returned\n";
|
LOG_NW << "wesnothd_connection::io_service::run() returned\n";
|
||||||
}));
|
}));
|
||||||
|
@ -422,31 +422,3 @@ bool wesnothd_connection::fetch_data_with_loading_screen(config& cfg, loading_st
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wesnothd_connection_ptr
|
|
||||||
|
|
||||||
wesnothd_connection_ptr& wesnothd_connection_ptr::operator=(wesnothd_connection_ptr&& other)
|
|
||||||
{
|
|
||||||
MPTEST_LOG;
|
|
||||||
if(ptr_) {
|
|
||||||
ptr_->stop();
|
|
||||||
ptr_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_ = std::move(other.ptr_);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
wesnothd_connection_ptr wesnothd_connection::create(const std::string& host, const std::string& service)
|
|
||||||
{
|
|
||||||
// Can't use make_shared because the ctor is private
|
|
||||||
return wesnothd_connection_ptr(std::shared_ptr<wesnothd_connection>(new wesnothd_connection(host, service)));
|
|
||||||
}
|
|
||||||
|
|
||||||
wesnothd_connection_ptr::~wesnothd_connection_ptr()
|
|
||||||
{
|
|
||||||
MPTEST_LOG;
|
|
||||||
if(ptr_) {
|
|
||||||
ptr_->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
class config;
|
class config;
|
||||||
class wesnothd_connection_ptr;
|
|
||||||
enum class loading_stage;
|
enum class loading_stage;
|
||||||
|
|
||||||
union data_union {
|
union data_union {
|
||||||
|
@ -54,7 +53,7 @@ union data_union {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A class that represents a TCP/IP connection to the wesnothd server. */
|
/** A class that represents a TCP/IP connection to the wesnothd server. */
|
||||||
class wesnothd_connection : public std::enable_shared_from_this<wesnothd_connection>
|
class wesnothd_connection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using error = wesnothd_connection_error;
|
using error = wesnothd_connection_error;
|
||||||
|
@ -64,20 +63,15 @@ public:
|
||||||
|
|
||||||
~wesnothd_connection();
|
~wesnothd_connection();
|
||||||
|
|
||||||
private:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* May only be called via wesnothd_connection_ptr
|
|
||||||
*
|
|
||||||
* @param host Name of the host to connect to
|
* @param host Name of the host to connect to
|
||||||
* @param service Service identifier such as "80" or "http"
|
* @param service Service identifier such as "80" or "http"
|
||||||
*/
|
*/
|
||||||
wesnothd_connection(const std::string& host, const std::string& service);
|
wesnothd_connection(const std::string& host, const std::string& service);
|
||||||
|
|
||||||
public:
|
|
||||||
static wesnothd_connection_ptr create(const std::string& host, const std::string& service);
|
|
||||||
|
|
||||||
bool fetch_data_with_loading_screen(config& cfg, loading_stage stage);
|
bool fetch_data_with_loading_screen(config& cfg, loading_stage stage);
|
||||||
|
|
||||||
void send_data(const configr_of& request);
|
void send_data(const configr_of& request);
|
||||||
|
@ -186,64 +180,4 @@ private:
|
||||||
std::size_t bytes_read_;
|
std::size_t bytes_read_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
using wesnothd_connection_ptr = std::unique_ptr<wesnothd_connection>;
|
||||||
* This class acts like a unique_ptr<wesnothd_connection>, wesnothd_connection objects may only be owned though this
|
|
||||||
* pointer. The reason why we need this is that wesnothd_connection runs a workerthread so we use a shared_ptr to make
|
|
||||||
* sure the wesnothd_connection isn't destroyed before the worker thread has finished. When this object is destroyed, it
|
|
||||||
* calls wesnothd_connection::stop() which stops the worker thread which will then destroy the other
|
|
||||||
* shared_ptr<wesnothd_connection> which destroys the wesnothd_connection object.
|
|
||||||
*/
|
|
||||||
class wesnothd_connection_ptr
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
friend class wesnothd_connection;
|
|
||||||
|
|
||||||
wesnothd_connection_ptr(std::shared_ptr<wesnothd_connection>&& ptr)
|
|
||||||
: ptr_(std::move(ptr))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
wesnothd_connection_ptr() = default;
|
|
||||||
|
|
||||||
wesnothd_connection_ptr(const wesnothd_connection_ptr&) = delete;
|
|
||||||
wesnothd_connection_ptr& operator=(const wesnothd_connection_ptr&) = delete;
|
|
||||||
|
|
||||||
wesnothd_connection_ptr(wesnothd_connection_ptr&&) = default;
|
|
||||||
wesnothd_connection_ptr& operator=(wesnothd_connection_ptr&&);
|
|
||||||
|
|
||||||
~wesnothd_connection_ptr();
|
|
||||||
|
|
||||||
explicit operator bool() const
|
|
||||||
{
|
|
||||||
return !!ptr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
wesnothd_connection& operator*()
|
|
||||||
{
|
|
||||||
return *ptr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wesnothd_connection& operator*() const
|
|
||||||
{
|
|
||||||
return *ptr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
wesnothd_connection* operator->()
|
|
||||||
{
|
|
||||||
return ptr_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const wesnothd_connection* operator->() const
|
|
||||||
{
|
|
||||||
return ptr_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
wesnothd_connection* get() const
|
|
||||||
{
|
|
||||||
return ptr_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<wesnothd_connection> ptr_;
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue