Fixed a bug in NtWaitForMultipleObjectsEx that caused the dashboard to deadlock + more review remarks
This commit is contained in:
parent
7589f0a94c
commit
6867907a3c
|
@ -998,9 +998,18 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
LOG_FUNC_ARG(bAlertable)
|
||||
LOG_FUNC_END;
|
||||
|
||||
LARGE_INTEGER ExpireTime, DueTime, NewTime;
|
||||
ExpireTime.QuadPart = DueTime.QuadPart = (dwMilliseconds == INFINITE) ? ~0ull : -dwMilliseconds;
|
||||
KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||
LARGE_INTEGER NewTime;
|
||||
PLARGE_INTEGER pNewTime;
|
||||
if (dwMilliseconds == INFINITE) {
|
||||
NewTime.QuadPart = ~0ull;
|
||||
pNewTime = &NewTime;
|
||||
}
|
||||
else {
|
||||
LARGE_INTEGER ExpireTime, DueTime;
|
||||
ExpireTime.QuadPart = DueTime.QuadPart = -dwMilliseconds;
|
||||
pNewTime = KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
}
|
||||
|
||||
xbox::dword_xt ret = WaitApc([hObjectToSignal, hObjectToWaitOn, bAlertable]() -> std::optional<DWORD> {
|
||||
DWORD dwRet = SignalObjectAndWait(hObjectToSignal, hObjectToWaitOn, 0, bAlertable);
|
||||
|
@ -1008,7 +1017,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(SignalObjectAndWait)
|
|||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional<DWORD>(dwRet);
|
||||
}, &NewTime, bAlertable, UserMode);
|
||||
}, pNewTime, bAlertable, UserMode);
|
||||
|
||||
RETURN((ret == X_STATUS_USER_APC) ? WAIT_IO_COMPLETION : (ret == X_STATUS_TIMEOUT) ? WAIT_TIMEOUT : ret);
|
||||
}
|
||||
|
|
|
@ -115,6 +115,11 @@ xbox::ntstatus_xt WaitApc(T &&Lambda, xbox::PLARGE_INTEGER AbsoluteExpireTime, x
|
|||
xbox::ulonglong_xt now = xbox::KeQueryInterruptTime();
|
||||
xbox::PETHREAD eThread = reinterpret_cast<xbox::PETHREAD>(EmuKeGetPcr()->Prcb->CurrentThread);
|
||||
|
||||
if (AbsoluteExpireTime->QuadPart == 0) {
|
||||
// This will only happen when the title specifies a zero timeout
|
||||
AbsoluteExpireTime->QuadPart = now;
|
||||
}
|
||||
|
||||
while (now <= static_cast<xbox::ulonglong_xt>(AbsoluteExpireTime->QuadPart)) {
|
||||
if (const auto ret = Lambda()) {
|
||||
return *ret;
|
||||
|
|
|
@ -567,13 +567,15 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
// We can't remove NtDll::NtDelayExecution until all APCs queued by Io are implemented by our kernel as well
|
||||
// Test case: Metal Slug 3
|
||||
LARGE_INTEGER NewTime;
|
||||
PLARGE_INTEGER pNewTime;
|
||||
if (Interval) {
|
||||
LARGE_INTEGER ExpireTime, DueTime;
|
||||
ExpireTime.QuadPart = DueTime.QuadPart = Interval->QuadPart;
|
||||
KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
pNewTime = KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
}
|
||||
else {
|
||||
NewTime.QuadPart = ~0ull;
|
||||
pNewTime = &NewTime;
|
||||
}
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc([Alertable]() -> std::optional<ntstatus_xt> {
|
||||
|
@ -584,7 +586,7 @@ XBSYSAPI EXPORTNUM(99) xbox::ntstatus_xt NTAPI xbox::KeDelayExecutionThread
|
|||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional<ntstatus_xt>(Status);
|
||||
}, &NewTime, Alertable, WaitMode);
|
||||
}, pNewTime, Alertable, WaitMode);
|
||||
|
||||
RETURN(ret);
|
||||
}
|
||||
|
|
|
@ -2201,13 +2201,15 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
|
||||
// Because user APCs from NtQueueApcThread are now handled by the kernel, we need to wait for them ourselves
|
||||
LARGE_INTEGER NewTime;
|
||||
PLARGE_INTEGER pNewTime;
|
||||
if (Timeout) {
|
||||
LARGE_INTEGER ExpireTime, DueTime;
|
||||
ExpireTime.QuadPart = DueTime.QuadPart = Timeout->QuadPart;
|
||||
KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
pNewTime = KiComputeWaitInterval(&ExpireTime, &DueTime, &NewTime);
|
||||
}
|
||||
else {
|
||||
NewTime.QuadPart = ~0ull;
|
||||
pNewTime = &NewTime;
|
||||
}
|
||||
|
||||
xbox::ntstatus_xt ret = WaitApc([Count, Handles, WaitType, Alertable]() -> std::optional<ntstatus_xt> {
|
||||
|
@ -2223,7 +2225,7 @@ XBSYSAPI EXPORTNUM(235) xbox::ntstatus_xt NTAPI xbox::NtWaitForMultipleObjectsEx
|
|||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional<ntstatus_xt>(Status);
|
||||
}, &NewTime, Alertable, WaitMode);
|
||||
}, pNewTime, Alertable, WaitMode);
|
||||
|
||||
RETURN(ret);
|
||||
}
|
||||
|
|
|
@ -62,9 +62,9 @@ typedef struct _PCSTProxyParam
|
|||
}
|
||||
PCSTProxyParam;
|
||||
|
||||
xbox::PCREATE_THREAD_NOTIFY_ROUTINE g_pfnThreadNotification[PSP_MAX_CREATE_THREAD_NOTIFY] = { xbox::zeroptr };
|
||||
int g_iThreadNotificationCount = 0;
|
||||
static std::mutex PspThreadNotificationMtx;
|
||||
static xbox::PCREATE_THREAD_NOTIFY_ROUTINE g_pfnThreadNotification[PSP_MAX_CREATE_THREAD_NOTIFY] = { xbox::zeroptr };
|
||||
static std::atomic_int g_iThreadNotificationCount = 0;
|
||||
static std::mutex g_ThreadNotificationMtx;
|
||||
|
||||
// Separate function for logging, otherwise in PCSTProxy __try wont work (Compiler Error C2712)
|
||||
void LOG_PCSTProxy
|
||||
|
@ -142,7 +142,7 @@ xbox::PETHREAD xbox::PspGetCurrentThread()
|
|||
|
||||
static xbox::void_xt PspCallThreadNotificationRoutines(xbox::PETHREAD eThread, xbox::boolean_xt Create)
|
||||
{
|
||||
std::unique_lock lck(PspThreadNotificationMtx);
|
||||
std::unique_lock lck(g_ThreadNotificationMtx);
|
||||
for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
|
||||
if (g_pfnThreadNotification[i]) {
|
||||
EmuLog(LOG_LEVEL::DEBUG, "Calling pfnNotificationRoutine[%d] (0x%.8X)", i, g_pfnThreadNotification[i]);
|
||||
|
@ -251,7 +251,6 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
RETURN(result);
|
||||
}
|
||||
|
||||
// Call the thread notification routine(s)
|
||||
if (g_iThreadNotificationCount) {
|
||||
PspCallThreadNotificationRoutines(eThread, TRUE);
|
||||
}
|
||||
|
@ -269,7 +268,6 @@ XBSYSAPI EXPORTNUM(255) xbox::ntstatus_xt NTAPI xbox::PsCreateSystemThreadEx
|
|||
|
||||
// PCSTProxy is responsible for cleaning up this pointer
|
||||
PCSTProxyParam *iPCSTProxyParam = new PCSTProxyParam;
|
||||
|
||||
iPCSTProxyParam->StartRoutine = (PVOID)StartRoutine;
|
||||
iPCSTProxyParam->StartContext = StartContext;
|
||||
iPCSTProxyParam->SystemRoutine = (PVOID)SystemRoutine; // NULL, XapiThreadStartup or unknown?
|
||||
|
@ -344,6 +342,7 @@ XBSYSAPI EXPORTNUM(257) xbox::ntstatus_xt NTAPI xbox::PsSetCreateThreadNotifyRou
|
|||
{
|
||||
LOG_FUNC_ONE_ARG(NotifyRoutine);
|
||||
|
||||
std::unique_lock lck(g_ThreadNotificationMtx);
|
||||
for (int i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
|
||||
if (g_pfnThreadNotification[i] == zeroptr) {
|
||||
g_pfnThreadNotification[i] = NotifyRoutine;
|
||||
|
@ -368,7 +367,6 @@ XBSYSAPI EXPORTNUM(258) xbox::void_xt NTAPI xbox::PsTerminateSystemThread
|
|||
{
|
||||
LOG_FUNC_ONE_ARG(ExitStatus);
|
||||
|
||||
// Call the thread notification routine(s)
|
||||
xbox::PETHREAD eThread = xbox::PspGetCurrentThread();
|
||||
if (eThread->UniqueThread && g_iThreadNotificationCount) {
|
||||
PspCallThreadNotificationRoutines(eThread, FALSE);
|
||||
|
|
|
@ -41,7 +41,7 @@ std::shared_mutex g_MapMtx;
|
|||
void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lck(g_MapMtx);
|
||||
const auto &ret = g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
||||
auto ret = g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
||||
if (ret.second == false) {
|
||||
// This can happen when an ob handle has been destroyed, but then a thread switch happens before the first thread
|
||||
// got a chance to remove the old handle from g_RegisteredHandles with RemoveXboxHandle
|
||||
|
@ -52,7 +52,7 @@ void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle)
|
|||
lck.unlock();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
lck.lock();
|
||||
g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
||||
ret = g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
||||
if (ret.second) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue