mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-23 11:15:34 +08:00
refactor background thread into a separate .cpp file
This commit is contained in:
parent
ba1de0165d
commit
86eb8aa2d0
@ -64,6 +64,35 @@ enum Steam_Pipe {
|
||||
SERVER
|
||||
};
|
||||
|
||||
class Steam_Client;
|
||||
class Client_Background_Thread
|
||||
{
|
||||
private:
|
||||
// don't run immediately, give the game some time to initialize
|
||||
constexpr const static auto initial_delay = std::chrono::seconds(2);
|
||||
// max allowed time in which RunCallbacks() might not be called
|
||||
constexpr const static auto max_stall_ms = std::chrono::milliseconds(300);
|
||||
|
||||
std::thread background_keepalive{};
|
||||
std::mutex kill_background_thread_mutex{};
|
||||
std::condition_variable kill_background_thread_cv{};
|
||||
bool kill_background_thread{};
|
||||
|
||||
Steam_Client *client_instance{};
|
||||
|
||||
void thread_proc();
|
||||
|
||||
public:
|
||||
Client_Background_Thread();
|
||||
~Client_Background_Thread();
|
||||
|
||||
// spawn the thread if necessary, never call this inside the ctor of Steam_Client
|
||||
// since the thread will attempt to get the global client pointer during initialization (which will still be under construction)
|
||||
void start(Steam_Client *client_instance);
|
||||
// kill the thread if necessary
|
||||
void kill();
|
||||
};
|
||||
|
||||
class Steam_Client :
|
||||
public ISteamClient007,
|
||||
public ISteamClient008,
|
||||
@ -144,14 +173,14 @@ public:
|
||||
Steam_Masterserver_Updater *steam_masterserver_updater{};
|
||||
Steam_AppTicket *steam_app_ticket{};
|
||||
|
||||
Client_Background_Thread *background_thread{};
|
||||
|
||||
Steam_Overlay* steam_overlay{};
|
||||
|
||||
bool steamclient_server_inited = false;
|
||||
|
||||
bool gameserver_has_ipv6_functions{};
|
||||
|
||||
std::thread background_keepalive{};
|
||||
|
||||
unsigned steam_pipe_counter = 1;
|
||||
std::map<HSteamPipe, enum Steam_Pipe> steam_pipes{};
|
||||
|
||||
|
@ -19,60 +19,13 @@
|
||||
#include "dll/settings_parser.h"
|
||||
|
||||
|
||||
static std::mutex kill_background_thread_mutex{};
|
||||
static std::condition_variable kill_background_thread_cv{};
|
||||
static bool kill_background_thread{};
|
||||
static void background_thread(Steam_Client *client)
|
||||
{
|
||||
// max allowed time in which RunCallbacks() might not be called
|
||||
constexpr const static auto max_stall_ms = std::chrono::milliseconds(300);
|
||||
|
||||
// wait 1 sec
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(kill_background_thread_mutex);
|
||||
if (kill_background_thread || kill_background_thread_cv.wait_for(lck, std::chrono::seconds(1)) != std::cv_status::timeout) {
|
||||
if (kill_background_thread) {
|
||||
PRINT_DEBUG("early exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("starting");
|
||||
|
||||
while (1) {
|
||||
{
|
||||
std::unique_lock lck(kill_background_thread_mutex);
|
||||
if (kill_background_thread || kill_background_thread_cv.wait_for(lck, max_stall_ms) != std::cv_status::timeout) {
|
||||
if (kill_background_thread) {
|
||||
PRINT_DEBUG("exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto now_ms = (unsigned long long)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
|
||||
// if our time exceeds last run time of callbacks and it wasn't processing already
|
||||
if (!client->cb_run_active && (now_ms >= (client->last_cb_run + max_stall_ms.count()))) {
|
||||
global_mutex.lock();
|
||||
PRINT_DEBUG("run @@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
client->last_cb_run = now_ms; // update the time counter just to avoid overlap
|
||||
client->network->Run(); // networking must run first since it receives messages used by each run_callback()
|
||||
client->run_every_runcb->run(); // call each run_callback()
|
||||
global_mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Steam_Client::Steam_Client()
|
||||
{
|
||||
PRINT_DEBUG("start ----------");
|
||||
uint32 appid = create_localstorage_settings(&settings_client, &settings_server, &local_storage);
|
||||
local_storage->update_save_filenames(Local_Storage::remote_storage_folder);
|
||||
|
||||
background_thread = new Client_Background_Thread();
|
||||
network = new Networking(settings_server->get_local_steam_id(), appid, settings_server->get_port(), &(settings_server->custom_broadcasts), settings_server->disable_networking);
|
||||
|
||||
run_every_runcb = new RunEveryRunCB();
|
||||
@ -333,17 +286,14 @@ HSteamUser Steam_Client::ConnectToGlobalUser( HSteamPipe hSteamPipe )
|
||||
|
||||
userLogIn();
|
||||
|
||||
|
||||
// games like appid 1740720 and 2379780 do not call SteamAPI_RunCallbacks() or SteamAPI_ManualDispatch_RunFrame() or Steam_BGetCallback()
|
||||
// hence all run_callbacks() will never run, which might break the assumption that these callbacks are always run
|
||||
// also networking callbacks won't run
|
||||
// hence we spawn the background thread here which trigger all run_callbacks() and run networking callbacks
|
||||
if (!background_keepalive.joinable()) {
|
||||
background_keepalive = std::thread(background_thread, this);
|
||||
PRINT_DEBUG("spawned background thread *********");
|
||||
}
|
||||
background_thread->start(this);
|
||||
|
||||
steam_overlay->SetupOverlay();
|
||||
|
||||
steam_pipes[hSteamPipe] = Steam_Pipe::CLIENT;
|
||||
return CLIENT_HSTEAMUSER;
|
||||
}
|
||||
@ -427,21 +377,8 @@ bool Steam_Client::BShutdownIfAllPipesClosed()
|
||||
PRINT_DEBUG_ENTRY();
|
||||
if (steam_pipes.size()) return false; // not all pipes are released via BReleaseSteamPipe() yet
|
||||
|
||||
bool joinable = background_keepalive.joinable();
|
||||
if (joinable) {
|
||||
{
|
||||
std::lock_guard lk(kill_background_thread_mutex);
|
||||
kill_background_thread = true;
|
||||
}
|
||||
kill_background_thread_cv.notify_one();
|
||||
}
|
||||
|
||||
background_thread->kill();
|
||||
steam_controller->Shutdown();
|
||||
|
||||
|
||||
if (joinable) {
|
||||
background_keepalive.join();
|
||||
}
|
||||
steam_overlay->UnSetupOverlay();
|
||||
|
||||
PRINT_DEBUG("all pipes closed");
|
||||
|
90
dll/steam_client_background_thread.cpp
Normal file
90
dll/steam_client_background_thread.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* Copyright (C) 2019 Mr Goldberg
|
||||
This file is part of the Goldberg Emulator
|
||||
|
||||
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the Goldberg Emulator; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "dll/steam_client.h"
|
||||
#include "dll/dll.h"
|
||||
|
||||
void Client_Background_Thread::thread_proc()
|
||||
{
|
||||
// wait for some time
|
||||
{
|
||||
|
||||
std::unique_lock lck(kill_background_thread_mutex);
|
||||
if (kill_background_thread_cv.wait_for(lck, initial_delay, [&] { return kill_background_thread; })) {
|
||||
PRINT_DEBUG("early exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("starting");
|
||||
|
||||
while (1) {
|
||||
{
|
||||
std::unique_lock lck(kill_background_thread_mutex);
|
||||
if (kill_background_thread_cv.wait_for(lck, max_stall_ms, [&] { return kill_background_thread; })) {
|
||||
PRINT_DEBUG("exit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto now_ms = (unsigned long long)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
|
||||
// if our time exceeds last run time of callbacks and it wasn't processing already
|
||||
const auto runcallbacks_timeout_ms = client_instance->get_last_runcallbacks_time() + max_stall_ms.count();
|
||||
if (!client_instance->runcallbacks_active() && (now_ms >= runcallbacks_timeout_ms)) {
|
||||
std::lock_guard lock(global_mutex);
|
||||
PRINT_DEBUG("run @@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
client_instance->set_last_runcallbacks_time(now_ms); // update the time counter just to avoid overlap
|
||||
client_instance->network->Run(); // networking must run first since it receives messages used by each run_callback()
|
||||
client_instance->run_every_runcb->run(); // call each run_callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Client_Background_Thread::Client_Background_Thread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Client_Background_Thread::~Client_Background_Thread()
|
||||
{
|
||||
kill();
|
||||
}
|
||||
|
||||
void Client_Background_Thread::start(Steam_Client *client_instance)
|
||||
{
|
||||
if (background_keepalive.joinable()) return; // alrady spawned
|
||||
|
||||
this->client_instance = client_instance;
|
||||
background_keepalive = std::thread([this] { thread_proc(); });
|
||||
PRINT_DEBUG("spawned background thread *********");
|
||||
}
|
||||
|
||||
void Client_Background_Thread::kill()
|
||||
{
|
||||
if (!background_keepalive.joinable()) return; // already killed
|
||||
|
||||
{
|
||||
std::lock_guard lk(kill_background_thread_mutex);
|
||||
kill_background_thread = true;
|
||||
}
|
||||
kill_background_thread_cv.notify_one();
|
||||
PRINT_DEBUG("joining worker thread");
|
||||
background_keepalive.join();
|
||||
PRINT_DEBUG("worker thread killed");
|
||||
}
|
Loading…
Reference in New Issue
Block a user