Skip to content

Commit

Permalink
GUI2/Network Transmission: delegate connection polling to a worker th…
Browse files Browse the repository at this point in the history
…read
  • Loading branch information
Vultraz committed Aug 1, 2019
1 parent 86f430c commit 21d21b0
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 28 deletions.
88 changes: 66 additions & 22 deletions src/gui/dialogs/network_transmission.cpp
Expand Up @@ -27,36 +27,69 @@
#include "serialization/string_utils.hpp"
#include "wesnothd_connection.hpp"

#include <chrono>

namespace gui2
{
namespace dialogs
{
using namespace std::chrono_literals;

REGISTER_DIALOG(network_transmission)

network_transmission::pump_monitor::pump_monitor(connection_data*& connection)
: connection_(connection)
, window_()
, completed_(0)
, total_(0)
, poller_(std::async(std::launch::async, [this]() {
while(true) {
// connection_ will be null if we reset the ptr in the main thread before canceling the dialog
if(!connection_) {
return false;
}

// Check for updates
connection_->poll();

if(connection_->finished()) {
return true;
}

completed_ = connection_->current();
total_ = connection_->total();

std::this_thread::sleep_for(10ms);
}
}))
{
}

void network_transmission::pump_monitor::process(events::pump_info&)
{
if(!window_)
if(!window_) {
return;
connection_->poll();
if(connection_->finished()) {
}

// Check if the thread is complete. If it is, loading is done.
if(poller_.wait_for(0ms) == std::future_status::ready && poller_.get()) {
window_.get().set_retval(retval::OK);
} else {
std::size_t completed, total;
completed = connection_->current();
total = connection_->total();
if(total) {
find_widget<progress_bar>(&(window_.get()), "progress", false)
.set_percentage((completed * 100.) / total);

std::stringstream ss;
ss << utils::si_string(completed, true, _("unit_byte^B")) << "/"
<< utils::si_string(total, true, _("unit_byte^B"));

find_widget<label>(&(window_.get()), "numeric_progress", false)
.set_label(ss.str());
window_->invalidate_layout();
}
return;
}

if(total_) {
find_widget<progress_bar>(&(window_.get()), "progress", false)
.set_percentage((completed_ * 100.) / total_);

std::ostringstream ss;
ss
<< utils::si_string(completed_, true, _("unit_byte^B")) << "/"
<< utils::si_string(total_, true, _("unit_byte^B"));

find_widget<label>(&(window_.get()), "numeric_progress", false)
.set_label(ss.str());

window_->invalidate_layout();
}
}

Expand All @@ -76,8 +109,8 @@ void network_transmission::pre_show(window& window)
{
// ***** ***** ***** ***** Set up the widgets ***** ***** ***** *****
if(!subtitle_.empty()) {
label& subtitle_label
= find_widget<label>(&window, "subtitle", false);
label& subtitle_label = find_widget<label>(&window, "subtitle", false);

subtitle_label.set_label(subtitle_);
subtitle_label.set_use_markup(true);
}
Expand All @@ -90,7 +123,18 @@ void network_transmission::post_show(window& /*window*/)
pump_monitor_.window_.reset();

if(get_retval() == retval::CANCEL) {
connection_->cancel();
// The worker thread holds a reference to connection_ and checks whether it's null before polling.
// The actual object to which connection_ is pointing will be destroyed by cancel(), so we're
// setting connection_ to null here before that so the worker thread will exit next run.
connection_data* const connection_ptr_copy = connection_;
connection_ = nullptr;

// Wait for the current polling loop to conclude before exiting so we don't invalidate the pointer
// mid-loop. The thread should return false if connection_ is null.
pump_monitor_.poller_.wait();
assert(pump_monitor_.poller_.get() == false);

connection_ptr_copy->cancel();
}
}

Expand Down
17 changes: 11 additions & 6 deletions src/gui/dialogs/network_transmission.hpp
Expand Up @@ -21,6 +21,9 @@

#include <boost/optional.hpp>

#include <atomic>
#include <future>

namespace gui2
{
namespace dialogs
Expand Down Expand Up @@ -53,15 +56,17 @@ class network_transmission : public modal_dialog
class pump_monitor : public events::pump_monitor
{
public:
connection_data*& connection_;
virtual void process(events::pump_info&);
virtual void process(events::pump_info&) override;

pump_monitor(connection_data*& connection);

pump_monitor(connection_data*& connection)
: connection_(connection), window_()
{
}
connection_data*& connection_;

boost::optional<window&> window_;

std::atomic_size_t completed_, total_;

std::future<bool> poller_;
} pump_monitor_;

public:
Expand Down

0 comments on commit 21d21b0

Please sign in to comment.