Skip to content

Commit 0532161

Browse files
committed
Use prototype mutex and condvar implementation of synchronization primitives
Fixes synchronization issues observed only in iOS
1 parent 73b6130 commit 0532161

13 files changed

Lines changed: 1518 additions & 943 deletions

File tree

UnleashedRecomp/CMakeLists.txt

Lines changed: 763 additions & 743 deletions
Large diffs are not rendered by default.

UnleashedRecomp/cpu/guest_thread.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <kernel/memory.h>
44
#include <kernel/heap.h>
55
#include <kernel/function.h>
6+
#include <os/logger.h>
7+
#include <unordered_map>
68
#include "ppc_context.h"
79

810
constexpr size_t PCR_SIZE = 0xAB0;
@@ -13,6 +15,29 @@ constexpr size_t TOTAL_SIZE = PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE;
1315

1416
constexpr size_t TEB_OFFSET = PCR_SIZE + TLS_SIZE;
1517

18+
static std::mutex g_guestThreadRegistryMutex;
19+
static std::unordered_map<uint32_t, uint32_t> g_guestThreadRegistry;
20+
21+
static void RegisterGuestThread(uint32_t guestThreadId)
22+
{
23+
std::lock_guard lock(g_guestThreadRegistryMutex);
24+
const auto [it, inserted] = g_guestThreadRegistry.emplace(
25+
guestThreadId, GuestThread::GetCurrentThreadId());
26+
if (!inserted)
27+
{
28+
LOGFN_ERROR(
29+
"SYNC-THREAD-DUPLICATE guestThread=0x{:08X} oldHostThread=0x{:08X} newHostThread=0x{:08X}",
30+
guestThreadId, it->second, GuestThread::GetCurrentThreadId());
31+
it->second = GuestThread::GetCurrentThreadId();
32+
}
33+
}
34+
35+
static void UnregisterGuestThread(uint32_t guestThreadId)
36+
{
37+
std::lock_guard lock(g_guestThreadRegistryMutex);
38+
g_guestThreadRegistry.erase(guestThreadId);
39+
}
40+
1641
GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
1742
{
1843
assert(thread == nullptr);
@@ -33,10 +58,13 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
3358

3459
assert(GetPPCContext() == nullptr);
3560
SetPPCContext(ppcContext);
61+
RegisterGuestThread(ppcContext.r13.u32);
3662
}
3763

3864
GuestThreadContext::~GuestThreadContext()
3965
{
66+
UnregisterGuestThread(ppcContext.r13.u32);
67+
ClearPPCContext();
4068
g_userHeap.Free(thread);
4169
}
4270

@@ -71,7 +99,7 @@ static void* GuestThreadFunc(void* arg)
7199
static void GuestThreadFunc(GuestThreadHandle* hThread)
72100
{
73101
#endif
74-
hThread->suspended.wait(true);
102+
hThread->WaitWhileSuspended();
75103
GuestThread::Start(hThread->params);
76104
#ifdef USE_PTHREAD
77105
return nullptr;
@@ -125,6 +153,35 @@ uint32_t GuestThreadHandle::GetThreadId() const
125153
#endif
126154
}
127155

156+
void GuestThreadHandle::SetSuspended(bool value)
157+
{
158+
#if defined(UNLEASHED_RECOMP_IOS_LAUNCHER)
159+
{
160+
std::lock_guard lock(suspendMutex);
161+
suspended.store(value, std::memory_order_release);
162+
}
163+
if (!value)
164+
suspendCondition.notify_all();
165+
#else
166+
suspended.store(value, std::memory_order_release);
167+
if (!value)
168+
suspended.notify_all();
169+
#endif
170+
}
171+
172+
void GuestThreadHandle::WaitWhileSuspended()
173+
{
174+
#if defined(UNLEASHED_RECOMP_IOS_LAUNCHER)
175+
std::unique_lock lock(suspendMutex);
176+
suspendCondition.wait(lock, [&]
177+
{
178+
return !suspended.load(std::memory_order_acquire);
179+
});
180+
#else
181+
suspended.wait(true, std::memory_order_acquire);
182+
#endif
183+
}
184+
128185
uint32_t GuestThreadHandle::Wait(uint32_t timeout)
129186
{
130187
assert(timeout == INFINITE);
@@ -173,6 +230,13 @@ uint32_t GuestThread::GetCurrentThreadId()
173230
#endif
174231
}
175232

233+
uint32_t GuestThread::FindHostThreadId(uint32_t guestThreadId)
234+
{
235+
std::lock_guard lock(g_guestThreadRegistryMutex);
236+
const auto it = g_guestThreadRegistry.find(guestThreadId);
237+
return it != g_guestThreadRegistry.end() ? it->second : 0;
238+
}
239+
176240
void GuestThread::SetLastError(uint32_t error)
177241
{
178242
auto* thread = (char*)g_memory.Translate(GetPPCContext()->r13.u32);

UnleashedRecomp/cpu/guest_thread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <condition_variable>
34
#include <kernel/xdm.h>
45

56
// Use pthreads directly on macOS to be able to increase default stack size.
@@ -33,6 +34,10 @@ struct GuestThreadHandle : KernelObject
3334
{
3435
GuestThreadParams params;
3536
std::atomic<bool> suspended;
37+
#if defined(UNLEASHED_RECOMP_IOS_LAUNCHER)
38+
std::mutex suspendMutex;
39+
std::condition_variable suspendCondition;
40+
#endif
3641
#ifdef USE_PTHREAD
3742
pthread_t thread;
3843
#else
@@ -43,6 +48,8 @@ struct GuestThreadHandle : KernelObject
4348
~GuestThreadHandle() override;
4449

4550
uint32_t GetThreadId() const;
51+
void SetSuspended(bool value);
52+
void WaitWhileSuspended();
4653

4754
uint32_t Wait(uint32_t timeout) override;
4855
};
@@ -53,6 +60,7 @@ struct GuestThread
5360
static GuestThreadHandle* Start(const GuestThreadParams& params, uint32_t* threadId);
5461

5562
static uint32_t GetCurrentThreadId();
63+
static uint32_t FindHostThreadId(uint32_t guestThreadId);
5664
static void SetLastError(uint32_t error);
5765

5866
#ifdef _WIN32

UnleashedRecomp/cpu/ppc_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ inline void SetPPCContext(PPCContext& ctx)
1111
{
1212
g_ppcContext = &ctx;
1313
}
14+
15+
inline void ClearPPCContext()
16+
{
17+
g_ppcContext = nullptr;
18+
}

0 commit comments

Comments
 (0)