web_service: stop using std::future + callback style async

This commit is contained in:
Weiyi Wang 2018-09-12 12:22:48 -04:00
parent 0a4d338ffa
commit 77c1f647cb
23 changed files with 329 additions and 457 deletions

View file

@ -42,6 +42,8 @@ add_library(common STATIC
alignment.h
announce_multiplayer_room.h
assert.h
detached_tasks.cpp
detached_tasks.h
bit_field.h
bit_set.h
chunk_file.h

View file

@ -6,7 +6,6 @@
#include <array>
#include <functional>
#include <future>
#include <string>
#include <vector>
#include "common/common_types.h"
@ -90,7 +89,7 @@ public:
* Send the data to the announce service
* @result The result of the announce attempt
*/
virtual std::future<Common::WebResult> Announce() = 0;
virtual Common::WebResult Announce() = 0;
/**
* Empties the stored players
@ -99,11 +98,9 @@ public:
/**
* Get the room information from the announce service
* @param func a function that gets exectued when the get finished.
* Can be used as a callback
* @result A list of all rooms the announce service has
*/
virtual std::future<RoomList> GetRoomList(std::function<void()> func) = 0;
virtual RoomList GetRoomList() = 0;
/**
* Sends a delete message to the announce service
@ -124,18 +121,12 @@ public:
const u64 /*preferred_game_id*/) override {}
void AddPlayer(const std::string& /*nickname*/, const MacAddress& /*mac_address*/,
const u64 /*game_id*/, const std::string& /*game_name*/) override {}
std::future<Common::WebResult> Announce() override {
return std::async(std::launch::deferred, []() {
return Common::WebResult{Common::WebResult::Code::NoWebservice,
"WebService is missing"};
});
Common::WebResult Announce() override {
return Common::WebResult{Common::WebResult::Code::NoWebservice, "WebService is missing"};
}
void ClearPlayers() override {}
std::future<RoomList> GetRoomList(std::function<void()> func) override {
return std::async(std::launch::deferred, [func]() {
func();
return RoomList{};
});
RoomList GetRoomList() override {
return RoomList{};
}
void Delete() override {}

View file

@ -0,0 +1,41 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <thread>
#include "common/assert.h"
#include "common/detached_tasks.h"
namespace Common {
DetachedTasks* DetachedTasks::instance = nullptr;
DetachedTasks::DetachedTasks() {
ASSERT(instance == nullptr);
instance = this;
}
void DetachedTasks::WaitForAllTasks() {
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [this]() { return count == 0; });
}
DetachedTasks::~DetachedTasks() {
std::unique_lock<std::mutex> lock(mutex);
ASSERT(count == 0);
instance = nullptr;
}
void DetachedTasks::AddTask(std::function<void()> task) {
std::unique_lock<std::mutex> lock(instance->mutex);
++instance->count;
std::thread([task{std::move(task)}]() {
task();
std::unique_lock<std::mutex> lock(instance->mutex);
--instance->count;
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
})
.detach();
}
} // namespace Common

View file

@ -0,0 +1,39 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <condition_variable>
#include <functional>
namespace Common {
/**
* A background manager which ensures that all detached task is finished before program exits.
*
* Some tasks, telemetry submission for example, prefer executing asynchronously and don't care
* about the result. These tasks are suitable for std::thread::detach(). However, this is unsafe if
* the task is launched just before the program exits (which is a common case for telemetry), so we
* need to block on these tasks on program exit.
*
* To make detached task safe, a single DetachedTasks object should be placed in the main(), and
* call WaitForAllTasks() after all program execution but before global/static variable destruction.
* Any potentially unsafe detached task should be executed via DetachedTasks::AddTask.
*/
class DetachedTasks {
public:
DetachedTasks();
~DetachedTasks();
void WaitForAllTasks();
static void AddTask(std::function<void()> task);
private:
static DetachedTasks* instance;
std::condition_variable cv;
std::mutex mutex;
int count = 0;
};
} // namespace Common