mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 17:49:29 +01:00
Merge pull request #4495 from unknownbrackets/multithread
Fix some issues in multithreading on Android
This commit is contained in:
commit
cc23635843
11 files changed
+56
-33
No files matched your search
+22
-13
@@ -20,6 +20,8 @@
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#elif defined(ANDROID)
|
||||
#include <sys/syscall.h>
|
||||
#elif defined BSD4_4
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
@@ -48,14 +50,14 @@ int CurrentThreadId()
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
SetThreadAffinityMask(thread, mask);
|
||||
return SetThreadAffinityMask(thread, mask) != 0;
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
bool SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
SetThreadAffinityMask(GetCurrentThread(), mask);
|
||||
return SetThreadAffinityMask(GetCurrentThread(), mask) != 0;
|
||||
}
|
||||
|
||||
// Supporting functions
|
||||
@@ -127,29 +129,36 @@ void EnableCrashingOnCrashes()
|
||||
|
||||
#else // !WIN32, so must be POSIX threads
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
thread_policy_set(pthread_mach_thread_np(thread),
|
||||
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
|
||||
#elif (defined __linux__ || defined BSD4_4) && !defined(ANDROID)
|
||||
return thread_policy_set(pthread_mach_thread_np(thread),
|
||||
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1) == 0;
|
||||
#elif defined(ANDROID) || defined(BLACKBERRY)
|
||||
return false;
|
||||
#elif (defined __linux__ || defined BSD4_4)
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
||||
for (int i = 0; i != sizeof(mask) * 8; ++i)
|
||||
for (int i = 0; i != sizeof(mask) * 8; ++i) {
|
||||
if ((mask >> i) & 1)
|
||||
CPU_SET(i, &cpu_set);
|
||||
}
|
||||
|
||||
pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set);
|
||||
return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set) == 0;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
bool SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
#ifdef BLACKBERRY
|
||||
ThreadCtl(_NTO_TCTL_RUNMASK, &mask);
|
||||
return ThreadCtl(_NTO_TCTL_RUNMASK, &mask) != -1;
|
||||
#elif defined(ANDROID)
|
||||
return syscall(__NR_sched_setaffinity, gettid(), sizeof(mask), &mask) == 0;
|
||||
#else
|
||||
SetThreadAffinity(pthread_self(), mask);
|
||||
return SetThreadAffinity(pthread_self(), mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -50,8 +50,8 @@ int CurrentThreadId();
|
||||
// In Windows 7 SP1 or later, stops Windows from swallowing crashes in WndProcs and other callbacks.
|
||||
void EnableCrashingOnCrashes();
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
|
||||
void SetCurrentThreadAffinity(u32 mask);
|
||||
bool SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
|
||||
bool SetCurrentThreadAffinity(u32 mask);
|
||||
|
||||
class Event
|
||||
{
|
||||
|
||||
@@ -267,6 +267,7 @@ reswitch:
|
||||
#endif
|
||||
break;
|
||||
|
||||
case CORE_POWERUP:
|
||||
case CORE_POWERDOWN:
|
||||
case CORE_ERROR:
|
||||
// Exit loop!!
|
||||
|
||||
+1
-1
@@ -429,7 +429,7 @@ static DirectoryFileSystem *flash0System = NULL;
|
||||
|
||||
void __IoManagerThread() {
|
||||
setCurrentThreadName("IOThread");
|
||||
while (ioManagerThreadEnabled) {
|
||||
while (ioManagerThreadEnabled && coreState != CORE_ERROR && coreState != CORE_POWERDOWN) {
|
||||
ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ bool AsyncIOManager::PopResult(u32 handle, AsyncIOResult &result) {
|
||||
bool AsyncIOManager::WaitResult(u32 handle, AsyncIOResult &result) {
|
||||
lock_guard guard(resultsLock_);
|
||||
ScheduleEvent(IO_EVENT_SYNC);
|
||||
while (HasEvents() && resultsPending_.find(handle) != resultsPending_.end()) {
|
||||
while (HasEvents() && ThreadEnabled() && resultsPending_.find(handle) != resultsPending_.end()) {
|
||||
if (PopResult(handle, result)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+8
-1
@@ -147,6 +147,7 @@ void CPU_WaitStatus(condition_variable &cond, bool (*pred)()) {
|
||||
void CPU_Shutdown();
|
||||
|
||||
void CPU_Init() {
|
||||
coreState = CORE_POWERUP;
|
||||
currentCPU = &mipsr4k;
|
||||
numCPUs = 1;
|
||||
|
||||
@@ -335,12 +336,18 @@ void PSP_RunLoopUntil(u64 globalticks) {
|
||||
}
|
||||
|
||||
if (cpuThread != NULL) {
|
||||
// Tell the gpu a new frame is about to begin, before we start the CPU.
|
||||
gpu->SyncBeginFrame();
|
||||
|
||||
cpuThreadUntil = globalticks;
|
||||
if (CPU_NextState(CPU_THREAD_RUNNING, CPU_THREAD_EXECUTE)) {
|
||||
// The CPU doesn't actually respect cpuThreadUntil well, especially when skipping frames.
|
||||
// TODO: Something smarter? Or force CPU to bail periodically?
|
||||
while (!CPU_IsReady()) {
|
||||
gpu->RunEventsUntil(CoreTiming::GetTicks() + msToCycles(100));
|
||||
gpu->RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
|
||||
if (coreState != CORE_RUNNING) {
|
||||
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERROR_LOG(CPU, "Unable to execute CPU run loop, unexpected state: %d", cpuThreadState);
|
||||
|
||||
@@ -78,6 +78,7 @@ enum CoreState
|
||||
CORE_RUNNING = 0,
|
||||
CORE_NEXTFRAME = 1,
|
||||
CORE_STEPPING,
|
||||
CORE_POWERUP,
|
||||
CORE_POWERDOWN,
|
||||
CORE_ERROR,
|
||||
};
|
||||
|
||||
+19
-4
@@ -24,13 +24,17 @@
|
||||
|
||||
template <typename B, typename Event, typename EventType, EventType EVENT_INVALID, EventType EVENT_SYNC, EventType EVENT_FINISH>
|
||||
struct ThreadEventQueue : public B {
|
||||
ThreadEventQueue() : threadEnabled_(false), eventsRunning_(false) {
|
||||
ThreadEventQueue() : threadEnabled_(false), eventsRunning_(false), eventsHaveRun_(false) {
|
||||
}
|
||||
|
||||
void SetThreadEnabled(bool threadEnabled) {
|
||||
threadEnabled_ = threadEnabled;
|
||||
}
|
||||
|
||||
bool ThreadEnabled() {
|
||||
return threadEnabled_;
|
||||
}
|
||||
|
||||
void ScheduleEvent(Event ev) {
|
||||
{
|
||||
lock_guard guard(eventsLock_);
|
||||
@@ -68,6 +72,7 @@ struct ThreadEventQueue : public B {
|
||||
void RunEventsUntil(u64 globalticks) {
|
||||
lock_guard guard(eventsLock_);
|
||||
eventsRunning_ = true;
|
||||
eventsHaveRun_ = true;
|
||||
|
||||
do {
|
||||
for (Event ev = GetNextEvent(); EventType(ev) != EVENT_INVALID; ev = GetNextEvent()) {
|
||||
@@ -103,6 +108,11 @@ struct ThreadEventQueue : public B {
|
||||
eventsRunning_ = false;
|
||||
}
|
||||
|
||||
void SyncBeginFrame() {
|
||||
lock_guard guard(eventsLock_);
|
||||
eventsHaveRun_ = false;
|
||||
}
|
||||
|
||||
// Force ignores coreState.
|
||||
void SyncThread(bool force = false) {
|
||||
if (!threadEnabled_) {
|
||||
@@ -113,14 +123,18 @@ struct ThreadEventQueue : public B {
|
||||
// While processing the last event, HasEvents() will be false even while not done.
|
||||
// So we schedule a nothing event and wait for that to finish.
|
||||
ScheduleEvent(EVENT_SYNC);
|
||||
while (HasEvents() && eventsRunning_ && (force || coreState == CORE_RUNNING)) {
|
||||
eventsDrain_.wait_for(eventsLock_, 1);
|
||||
while (HasEvents() && (eventsRunning_ || !eventsHaveRun_) && (force || coreState == CORE_RUNNING)) {
|
||||
eventsDrain_.wait_for(eventsLock_, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void FinishEventLoop() {
|
||||
if (threadEnabled_) {
|
||||
ScheduleEvent(EVENT_FINISH);
|
||||
lock_guard guard(eventsLock_);
|
||||
// Don't schedule a finish if it's not even running.
|
||||
if (eventsRunning_) {
|
||||
ScheduleEvent(EVENT_FINISH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +145,7 @@ protected:
|
||||
private:
|
||||
bool threadEnabled_;
|
||||
bool eventsRunning_;
|
||||
bool eventsHaveRun_;
|
||||
std::deque<Event> events_;
|
||||
recursive_mutex eventsLock_;
|
||||
condition_variable eventsWait_;
|
||||
|
||||
@@ -539,10 +539,7 @@ void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo
|
||||
}
|
||||
|
||||
bool GLES_GPU::FramebufferDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
@@ -557,10 +554,7 @@ bool GLES_GPU::FramebufferDirty() {
|
||||
}
|
||||
|
||||
bool GLES_GPU::FramebufferReallyDirty() {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Allow it to process fully before deciding if it's dirty.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
@@ -60,10 +60,7 @@ bool GPUCommon::BusyDrawing() {
|
||||
}
|
||||
|
||||
u32 GPUCommon::DrawSync(int mode) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Sync first, because the CPU is usually faster than the emulated GPU.
|
||||
SyncThread();
|
||||
}
|
||||
@@ -119,8 +116,6 @@ void GPUCommon::CheckDrawSync() {
|
||||
|
||||
int GPUCommon::ListSync(int listid, int mode) {
|
||||
if (g_Config.bSeparateCPUThread) {
|
||||
// FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause.
|
||||
ScheduleEvent(GPU_EVENT_PROCESS_QUEUE);
|
||||
// Sync first, because the CPU is usually faster than the emulated GPU.
|
||||
SyncThread();
|
||||
}
|
||||
|
||||
@@ -231,6 +231,7 @@ public:
|
||||
virtual void DeviceLost() = 0;
|
||||
virtual void ReapplyGfxState() = 0;
|
||||
virtual void SyncThread(bool force = false) = 0;
|
||||
virtual void SyncBeginFrame() = 0;
|
||||
virtual u64 GetTickEstimate() = 0;
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
|
||||
|
||||
Reference in new issue
Block a user