Merge pull request #4495 from unknownbrackets/multithread

Fix some issues in multithreading on Android
This commit is contained in:
Henrik Rydgård committed 2013-11-10 01:56:50 -08:00
commit cc23635843
11 files changed
+56 -33

No files matched your search

+22 -13
View File
@@ -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
View File
@@ -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
{
+1
View File
@@ -267,6 +267,7 @@ reswitch:
#endif
break;
case CORE_POWERUP:
case CORE_POWERDOWN:
case CORE_ERROR:
// Exit loop!!
+1 -1
View File
@@ -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));
}
}
+1 -1
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -78,6 +78,7 @@ enum CoreState
CORE_RUNNING = 0,
CORE_NEXTFRAME = 1,
CORE_STEPPING,
CORE_POWERUP,
CORE_POWERDOWN,
CORE_ERROR,
};
+19 -4
View File
@@ -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_;
-6
View File
@@ -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();
}
-5
View File
@@ -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();
}
+1
View File
@@ -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;