Skip to content

Commit 8358c55

Browse files
committed
Fix a deadlock when loading/reloading scripts
1 parent 1b8da08 commit 8358c55

File tree

4 files changed

+39
-6
lines changed

4 files changed

+39
-6
lines changed

src/Mods.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ std::optional<std::string> Mods::on_initialize() const {
9696

9797

9898
std::optional<std::string> Mods::on_initialize_d3d_thread() const {
99-
std::scoped_lock _{g_framework->get_hook_monitor_mutex()};
99+
auto do_not_hook_d3d = g_framework->acquire_do_not_hook_d3d();
100100

101101
utility::Config cfg{ (REFramework::get_persistent_dir() / REFrameworkConfig::REFRAMEWORK_CONFIG_NAME).string() };
102102

src/REFramework.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,25 @@ using namespace std::literals;
4747
std::unique_ptr<REFramework> g_framework{};
4848

4949
void REFramework::hook_monitor() {
50+
if (m_do_not_hook_d3d_count.load() > 0) {
51+
// Wait until nothing important is happening
52+
m_last_present_time = std::chrono::steady_clock::now() + std::chrono::seconds(5);
53+
m_last_chance_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
54+
m_has_last_chance = true;
55+
return;
56+
}
57+
5058
if (!m_hook_monitor_mutex.try_lock()) {
5159
// If this happens then we can assume execution is going as planned
5260
// so we can just reset the times so we dont break something
5361
m_last_present_time = std::chrono::steady_clock::now() + std::chrono::seconds(5);
5462
m_last_chance_time = std::chrono::steady_clock::now() + std::chrono::seconds(1);
5563
m_has_last_chance = true;
56-
} else {
57-
m_hook_monitor_mutex.unlock();
64+
return;
5865
}
5966

60-
std::scoped_lock _{ m_hook_monitor_mutex };
67+
// Take ownership of the mutex with adopt_lock
68+
std::lock_guard _{ m_hook_monitor_mutex, std::adopt_lock };
6169

6270
if (g_framework == nullptr) {
6371
return;
@@ -2018,7 +2026,7 @@ bool REFramework::first_frame_initialize() {
20182026
return is_init_ok;
20192027
}
20202028

2021-
std::scoped_lock _{get_hook_monitor_mutex()};
2029+
auto do_not_hook_d3d = acquire_do_not_hook_d3d();
20222030

20232031
spdlog::info("Running first frame D3D initialization of mods...");
20242032

src/REFramework.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ class RETypes;
2424
class REFramework {
2525
private:
2626
void hook_monitor();
27+
std::atomic<uint32_t> m_do_not_hook_d3d_count{0};
28+
29+
public:
30+
struct DoNotHook {
31+
DoNotHook(std::atomic<uint32_t>& count) : m_count(count) {
32+
++m_count;
33+
}
34+
35+
~DoNotHook() {
36+
--m_count;
37+
}
38+
39+
private:
40+
std::atomic<uint32_t>& m_count;
41+
};
42+
43+
DoNotHook acquire_do_not_hook_d3d() {
44+
return DoNotHook{m_do_not_hook_d3d_count};
45+
}
46+
2747

2848
public:
2949
REFramework(HMODULE reframework_module);
@@ -121,6 +141,10 @@ class REFramework {
121141
return m_hook_monitor_mutex;
122142
}
123143

144+
auto& get_startup_mutex() {
145+
return m_startup_mutex;
146+
}
147+
124148
void set_font_size(int size) {
125149
if (m_font_size != size) {
126150
m_font_size = size;

src/mods/ScriptRunner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,8 @@ void ScriptRunner::spew_error(const std::string& p) {
11681168

11691169

11701170
void ScriptRunner::reset_scripts() {
1171-
std::scoped_lock __{ g_framework->get_hook_monitor_mutex() }; // Stops D3D monitor from attempting to re-hook during long script startups
1171+
auto do_not_hook_d3d = g_framework->acquire_do_not_hook_d3d();
1172+
11721173
std::scoped_lock _{ m_access_mutex };
11731174

11741175
{

0 commit comments

Comments
 (0)