From f37dd7fefe31d0cd2b12a5fdb7d1f3779bfb4046 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 12 Nov 2012 07:24:40 -0800 Subject: [PATCH] Fix $v0 on wrong thread in semaphore funcs. Need to RETURN() prior to switching threads or it will write to the wrong thread, oops. --- Core/HLE/FunctionWrappers.h | 4 +++ Core/HLE/sceKernel.cpp | 10 +++--- Core/HLE/sceKernelSemaphore.cpp | 57 +++++++++++++++++++-------------- Core/HLE/sceKernelSemaphore.h | 10 +++--- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 00fb54e3fe..d58a726029 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -142,6 +142,10 @@ template void WrapV_IUU() { func(PARAM(0), PARAM(1), PARAM(2)); } +template void WrapV_IIU() { + func(PARAM(0), PARAM(1), PARAM(2)); +} + template void WrapV_IUUUU() { func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index aadfb241c4..8f160946eb 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -327,14 +327,14 @@ const HLEFunction ThreadManForUser[] = {0xCD203292,&WrapU_V, "sceKernelCancelEventFlag"}, {0xA66B0120,&WrapU_IU, "sceKernelReferEventFlagStatus"}, - {0x8FFDF9A2,&WrapI_IIU, "sceKernelCancelSema"}, + {0x8FFDF9A2,&WrapV_IIU, "sceKernelCancelSema"}, {0xD6DA4BA1,sceKernelCreateSema, "sceKernelCreateSema"}, - {0x28b6489c,&WrapI_I, "sceKernelDeleteSema"}, + {0x28b6489c,&WrapV_I, "sceKernelDeleteSema"}, {0x58b1f937,&WrapI_II, "sceKernelPollSema"}, {0xBC6FEBC5,&WrapI_IU, "sceKernelReferSemaStatus"}, - {0x3F53E640,&WrapI_II, "sceKernelSignalSema"}, - {0x4E3A1105,&WrapI_IIU, "sceKernelWaitSema"}, - {0x6d212bac,&WrapI_IIU, "sceKernelWaitSemaCB"}, + {0x3F53E640,&WrapV_II, "sceKernelSignalSema"}, + {0x4E3A1105,&WrapV_IIU, "sceKernelWaitSema"}, + {0x6d212bac,&WrapV_IIU, "sceKernelWaitSemaCB"}, {0x60107536,0,"sceKernelDeleteLwMutex"}, {0x19CFF145,0,"sceKernelCreateLwMutex"}, diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 2b22f48c77..600c6e59ab 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -77,7 +77,9 @@ bool __KernelClearSemaThreads(Semaphore *s, int reason) return wokeThreads; } -int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) +// int sceKernelCancelSema(SceUID id, int newCount, int *numWaitThreads); +// void because it changes threads. +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { DEBUG_LOG(HLE,"sceKernelCancelSema(%i)", id); @@ -97,16 +99,17 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) s->ns.currentCount = newCount; s->ns.numWaitThreads = 0; + // We need to set the return value BEFORE rescheduling threads. + RETURN(0); + // TODO: Should this reschedule? if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL)) __KernelReSchedule("semaphore cancelled"); - - return 0; } else { ERROR_LOG(HLE, "sceKernelCancelSema : Trying to cancel invalid semaphore %i", id); - return error; + RETURN(error); } } @@ -132,7 +135,8 @@ void sceKernelCreateSema() } //int sceKernelDeleteSema(SceUID semaid); -int sceKernelDeleteSema(SceUID id) +// void because it changes threads. +void sceKernelDeleteSema(SceUID id) { DEBUG_LOG(HLE,"sceKernelDeleteSema(%i)", id); @@ -140,18 +144,18 @@ int sceKernelDeleteSema(SceUID id) Semaphore *s = kernelObjects.Get(id, error); if (s) { - // TODO: Should this reschedule? - // threads/semaphore doesn't get final threads if not, but gets wrong result if so. - // Probably it should and there's a bug with the registers? if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE)) + { + RETURN(kernelObjects.Destroy(id)); __KernelReSchedule("semaphore deleted"); - - return kernelObjects.Destroy(id); + } + else + RETURN(kernelObjects.Destroy(id)); } else { ERROR_LOG(HLE, "sceKernelDeleteSema : Trying to delete invalid semaphore %i", id); - return error; + RETURN(error); } } @@ -174,7 +178,8 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) } //int sceKernelSignalSema(SceUID semaid, int signal); -int sceKernelSignalSema(SceUID id, int signal) +// void because it changes threads. +void sceKernelSignalSema(SceUID id, int signal) { //TODO: check that this thing really works :) u32 error; @@ -188,7 +193,10 @@ int sceKernelSignalSema(SceUID id, int signal) else s->ns.currentCount += signal; DEBUG_LOG(HLE,"sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount); - + + // We need to set the return value BEFORE processing other threads. + RETURN(0); + bool wokeThreads = false; retry: //TODO: check for threads to wake up - wake them @@ -212,27 +220,28 @@ retry: break; } } - // RETURN(0); //pop the thread that were released from waiting // I don't think we should reschedule here //if (wokeThreads) // __KernelReSchedule("semaphore signalled"); - return 0; } else { ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id); - return error; + RETURN(error;) } } -int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) +void __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *badSemaMessage, bool processCallbacks) { u32 error; Semaphore *s = kernelObjects.Get(id, error); if (s) { + // We need to set the return value BEFORE processing callbacks / etc. + RETURN(0); + if (s->ns.currentCount >= wantedCount) //TODO fix s->ns.currentCount -= wantedCount; else @@ -244,30 +253,30 @@ int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, const char *bad if (processCallbacks) __KernelCheckCallbacks(); } - - return 0; } else { ERROR_LOG(HLE, badSemaMessage, id); - return error; + RETURN(error); } } //int sceKernelWaitSema(SceUID semaid, int signal, SceUInt *timeout); -int sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) +// void because it changes threads. +void sceKernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelWaitSema(%i, %i, %i)", id, wantedCount, timeoutPtr); - return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSema: Trying to wait for invalid semaphore %i", false); } //int sceKernelWaitSemaCB(SceUID semaid, int signal, SceUInt *timeout); -int sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) +// void because it changes threads. +void sceKernelWaitSemaCB(SceUID id, int wantedCount, u32 timeoutPtr) { DEBUG_LOG(HLE,"sceKernelWaitSemaCB(%i, %i, %i)", id, wantedCount, timeoutPtr); - return __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); + __KernelWaitSema(id, wantedCount, timeoutPtr, "sceKernelWaitSemaCB: Trying to wait for invalid semaphore %i", true); } // Should be same as WaitSema but without the wait, instead returning SCE_KERNEL_ERROR_SEMA_ZERO diff --git a/Core/HLE/sceKernelSemaphore.h b/Core/HLE/sceKernelSemaphore.h index 1a92cc40ba..185976f788 100644 --- a/Core/HLE/sceKernelSemaphore.h +++ b/Core/HLE/sceKernelSemaphore.h @@ -17,11 +17,11 @@ #pragma once -int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); +void sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr); void sceKernelCreateSema(); -int sceKernelDeleteSema(SceUID id); +void sceKernelDeleteSema(SceUID id); int sceKernelPollSema(SceUID id, int wantedCount); int sceKernelReferSemaStatus(SceUID id, u32 infoPtr); -int sceKernelSignalSema(SceUID id, int signal); -int sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); -int sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr); +void sceKernelSignalSema(SceUID id, int signal); +void sceKernelWaitSema(SceUID semaid, int signal, u32 timeoutPtr); +void sceKernelWaitSemaCB(SceUID semaid, int signal, u32 timeoutPtr);