Skip to content

Commit

Permalink
Prevent deadlock on exit by keeping replay and puzzle threads around
Browse files Browse the repository at this point in the history
Don't detach those threads, instead keep them referenced and manually join them on program termination, prevents deadlocks on linux where on program termination the destructor of the mutexes would lock because a random thread was still holding onto them.
  • Loading branch information
edo9300 committed Mar 6, 2022
1 parent 3d7b042 commit 8552775
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 14 deletions.
17 changes: 9 additions & 8 deletions gframe/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1905,16 +1905,17 @@ bool Game::MainLoop() {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
discord.UpdatePresence(DiscordWrapper::TERMINATE);
replaySignal.SetNoWait(true);
actionSignal.SetNoWait(true);
closeDoneSignal.SetNoWait(true);
{
std::lock_guard<std::mutex> lk(gMutex);
replaySignal.SetNoWait(true);
actionSignal.SetNoWait(true);
closeDoneSignal.SetNoWait(true);
frameSignal.SetNoWait(true);
}
DuelClient::StopClient(true);
SingleMode::StopPlay(true);
ReplayMode::StopReplay(true);
ClearTextures();
if(dInfo.isSingleMode)
SingleMode::StopPlay(true);
if(dInfo.isReplay)
ReplayMode::StopReplay(true);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
SaveConfig();
#ifdef YGOPRO_BUILD_DLL
if(ocgcore)
Expand Down
2 changes: 1 addition & 1 deletion gframe/mysignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class Signal {
public:
Signal():_nowait(false){}
~Signal() {}
~Signal() { SetNoWait(true); }
void Set() {
val.notify_all();
}
Expand Down
9 changes: 7 additions & 2 deletions gframe/replay_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bool ReplayMode::exit_pending = false;
int ReplayMode::skip_turn = 0;
int ReplayMode::current_step = 0;
int ReplayMode::skip_step = 0;
std::thread ReplayMode::replay_thread;

bool ReplayMode::StartReplay(int skipturn, bool is_yrp) {
if(mainGame->dInfo.isReplay)
Expand All @@ -35,16 +36,18 @@ bool ReplayMode::StartReplay(int skipturn, bool is_yrp) {
is_pausing = false;
is_paused = false;
is_restarting = false;
if(replay_thread.joinable())
replay_thread.join();
if(is_yrp) {
if(cur_replay.pheader.id == REPLAY_YRP1)
cur_yrp = &cur_replay;
else
cur_yrp = cur_replay.yrp.get();
if(!cur_yrp)
return false;
std::thread(OldReplayThread).detach();
replay_thread = std::thread(OldReplayThread);
} else
std::thread(ReplayThread).detach();
replay_thread = std::thread(ReplayThread);
return true;
}
void ReplayMode::StopReplay(bool is_exiting) {
Expand All @@ -53,6 +56,8 @@ void ReplayMode::StopReplay(bool is_exiting) {
is_closing = is_exiting;
exit_pending = true;
mainGame->actionSignal.Set();
if(is_exiting && replay_thread.joinable())
replay_thread.join();
}
void ReplayMode::SwapField() {
if(is_paused)
Expand Down
2 changes: 2 additions & 0 deletions gframe/replay_mode.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef REPLAY_MODE_H
#define REPLAY_MODE_H

#include <thread>
#include "dllinterface.h"
#include "config.h"
#include "data_manager.h"
Expand All @@ -26,6 +27,7 @@ class ReplayMode {
static int skip_turn;
static int current_step;
static int skip_step;
static std::thread replay_thread;

public:
static Replay cur_replay;
Expand Down
11 changes: 8 additions & 3 deletions gframe/single_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,26 @@ Replay SingleMode::last_replay;
Replay SingleMode::new_replay;
ReplayStream SingleMode::replay_stream;
Signal SingleMode::singleSignal;
std::thread SingleMode::single_mode_thread;

bool SingleMode::StartPlay(DuelOptions&& duelOptions) {
if(mainGame->dInfo.isSingleMode)
return false;
std::thread(SinglePlayThread, std::move(duelOptions)).detach();
if(single_mode_thread.joinable())
single_mode_thread.join();
single_mode_thread = std::thread(SinglePlayThread, std::move(duelOptions));
return true;
}
void SingleMode::StopPlay(bool is_exiting) {
is_closing = is_exiting;
is_continuing = false;
is_restarting = false;
mainGame->actionSignal.Set();
if(is_closing)
if(is_closing) {
singleSignal.SetNoWait(true);
else
if(single_mode_thread.joinable())
single_mode_thread.join();
} else
singleSignal.Set();
}
void SingleMode::Restart() {
Expand Down
2 changes: 2 additions & 0 deletions gframe/single_mode.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef SINGLE_MODE_H
#define SINGLE_MODE_H

#include <thread>
#include "dllinterface.h"
#include "replay.h"
#include "mysignal.h"
Expand All @@ -15,6 +16,7 @@ class SingleMode {
static bool is_closing;
static bool is_continuing;
static bool is_restarting;
static std::thread single_mode_thread;

public:
struct DuelOptions {
Expand Down

0 comments on commit 8552775

Please sign in to comment.