From 5c5f6a51ad3e7edcdc4c02ad6de4d8a79b99b4be Mon Sep 17 00:00:00 2001
From: Mr-Wiseguy <mrwiseguyromhacking@gmail.com>
Date: Wed, 15 Feb 2023 23:41:46 -0500
Subject: [PATCH] Fixed an occasional startup crash caused by the game running
 before the events thread was finished initializing

---
 test/portultra/events.cpp | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/test/portultra/events.cpp b/test/portultra/events.cpp
index a82be86..de337bd 100644
--- a/test/portultra/events.cpp
+++ b/test/portultra/events.cpp
@@ -243,7 +243,7 @@ void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_f
     sp_complete();
 }
 
-void event_thread_func(uint8_t* rdram, uint8_t* rom) {
+void event_thread_func(uint8_t* rdram, uint8_t* rom, std::atomic_flag* events_thread_ready) {
     using namespace std::chrono_literals;
     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
         fprintf(stderr, "Failed to initialize SDL2: %s\n", SDL_GetError());
@@ -258,6 +258,10 @@ void event_thread_func(uint8_t* rdram, uint8_t* rom) {
 
     rsp_constants_init();
 
+    // Notify the caller thread that this thread is ready.
+    events_thread_ready->test_and_set();
+    events_thread_ready->notify_all();
+
     while (true) {
         // Try to pull an action from the queue
         Action action;
@@ -319,7 +323,13 @@ void Multilibultra::send_si_message() {
 }
 
 void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
+    std::atomic_flag events_thread_ready;
     events_context.rdram = rdram;
+    events_context.sp.thread = std::thread{ event_thread_func, rdram, rom, &events_thread_ready };
+    
+    // Wait for the event thread to be ready before continuing to prevent the game from
+    // running before we're able to handle RSP tasks.
+    events_thread_ready.wait(false);
+
     events_context.vi.thread = std::thread{ vi_thread_func };
-    events_context.sp.thread = std::thread{ event_thread_func, rdram, rom };
 }