mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-09-07 12:39:09 +01:00
SVC: Correct SendSyncRequest.
This commit is contained in:
parent
203e706302
commit
15a79eb0d7
8 changed files with 116 additions and 54 deletions
|
@ -81,8 +81,7 @@ void CpuManager::RunGuestThread() {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto& physical_core = kernel.CurrentPhysicalCore();
|
auto& physical_core = kernel.CurrentPhysicalCore();
|
||||||
if (!physical_core.IsInterrupted()) {
|
if (!physical_core.IsInterrupted()) {
|
||||||
physical_core.Idle();
|
physical_core.Run();
|
||||||
// physical_core.Run();
|
|
||||||
}
|
}
|
||||||
auto& scheduler = physical_core.Scheduler();
|
auto& scheduler = physical_core.Scheduler();
|
||||||
scheduler.TryDoContextSwitch();
|
scheduler.TryDoContextSwitch();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
@ -21,7 +22,9 @@
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
@ -46,11 +49,10 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||||
const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
const std::string& reason, u64 timeout, WakeupCallback&& callback,
|
||||||
std::shared_ptr<WritableEvent> writable_event) {
|
std::shared_ptr<WritableEvent> writable_event) {
|
||||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||||
thread->SetWakeupCallback(
|
thread->SetHLECallback(
|
||||||
[context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
[context = *this, callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<SynchronizationObject> object,
|
std::shared_ptr<SynchronizationObject> object,
|
||||||
std::size_t index) mutable -> bool {
|
std::size_t index) mutable -> bool {
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent);
|
|
||||||
callback(thread, context, reason);
|
callback(thread, context, reason);
|
||||||
context.WriteToOutgoingCommandBuffer(*thread);
|
context.WriteToOutgoingCommandBuffer(*thread);
|
||||||
return true;
|
return true;
|
||||||
|
@ -62,14 +64,16 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||||
writable_event = pair.writable;
|
writable_event = pair.writable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Handle event_handle = InvalidHandle;
|
||||||
|
SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout);
|
||||||
const auto readable_event{writable_event->GetReadableEvent()};
|
const auto readable_event{writable_event->GetReadableEvent()};
|
||||||
writable_event->Clear();
|
writable_event->Clear();
|
||||||
thread->SetStatus(ThreadStatus::WaitHLEEvent);
|
thread->SetStatus(ThreadStatus::WaitHLEEvent);
|
||||||
thread->SetSynchronizationObjects({readable_event});
|
thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
|
||||||
readable_event->AddWaitingThread(thread);
|
readable_event->AddWaitingThread(thread);
|
||||||
|
lock.Release();
|
||||||
if (timeout > 0) {
|
thread->SetHLETimeEvent(event_handle);
|
||||||
thread->WakeAfterDelay(timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_thread_waiting = true;
|
is_thread_waiting = true;
|
||||||
|
|
|
@ -715,4 +715,13 @@ SchedulerLockAndSleep::~SchedulerLockAndSleep() {
|
||||||
time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
|
time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SchedulerLockAndSleep::Release() {
|
||||||
|
if (sleep_cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& time_manager = kernel.TimeManager();
|
||||||
|
time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
|
||||||
|
sleep_cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -279,6 +279,8 @@ public:
|
||||||
sleep_cancelled = true;
|
sleep_cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Release();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Handle& event_handle;
|
Handle& event_handle;
|
||||||
Thread* time_task;
|
Thread* time_task;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
#include "core/hle/kernel/session.h"
|
#include "core/hle/kernel/session.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
@ -168,9 +169,12 @@ ResultCode ServerSession::CompleteSyncRequest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some service requests require the thread to block
|
// Some service requests require the thread to block
|
||||||
|
{
|
||||||
|
SchedulerLock lock(kernel);
|
||||||
if (!context.IsThreadWaiting()) {
|
if (!context.IsThreadWaiting()) {
|
||||||
context.GetThread().ResumeFromWait();
|
context.GetThread().ResumeFromWait();
|
||||||
context.GetThread().SetWaitSynchronizationResult(result);
|
context.GetThread().SetSynchronizationResults(nullptr, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request_queue.Pop();
|
request_queue.Pop();
|
||||||
|
@ -180,8 +184,9 @@ ResultCode ServerSession::CompleteSyncRequest() {
|
||||||
|
|
||||||
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
Core::Memory::Memory& memory) {
|
Core::Memory::Memory& memory) {
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {});
|
ResultCode result = QueueSyncRequest(std::move(thread), memory);
|
||||||
return QueueSyncRequest(std::move(thread), memory);
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(0, request_event, {});
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "core/hle/kernel/svc_wrap.h"
|
#include "core/hle/kernel/svc_wrap.h"
|
||||||
#include "core/hle/kernel/synchronization.h"
|
#include "core/hle/kernel/synchronization.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/hle/kernel/time_manager.h"
|
||||||
#include "core/hle/kernel/transfer_memory.h"
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
|
@ -318,11 +319,23 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
|
||||||
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
|
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
|
||||||
|
|
||||||
auto thread = system.CurrentScheduler().GetCurrentThread();
|
auto thread = system.CurrentScheduler().GetCurrentThread();
|
||||||
thread->InvalidateWakeupCallback();
|
{
|
||||||
|
SchedulerLock lock(system.Kernel());
|
||||||
|
thread->InvalidateHLECallback();
|
||||||
thread->SetStatus(ThreadStatus::WaitIPC);
|
thread->SetStatus(ThreadStatus::WaitIPC);
|
||||||
system.PrepareReschedule(thread->GetProcessorID());
|
session->SendSyncRequest(SharedFrom(thread), system.Memory());
|
||||||
|
}
|
||||||
|
ResultCode result = thread->GetSignalingResult();
|
||||||
|
if (thread->HasHLECallback()) {
|
||||||
|
Handle event_handle = thread->GetHLETimeEvent();
|
||||||
|
if (event_handle != InvalidHandle) {
|
||||||
|
auto& time_manager = system.Kernel().TimeManager();
|
||||||
|
time_manager.UnscheduleTimeEvent(event_handle);
|
||||||
|
}
|
||||||
|
thread->InvokeHLECallback(ThreadWakeupReason::Timeout, SharedFrom(thread), nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return session->SendSyncRequest(SharedFrom(thread), system.Memory());
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ void Thread::ResumeFromWait() {
|
||||||
case ThreadStatus::Ready:
|
case ThreadStatus::Ready:
|
||||||
// The thread's wakeup callback must have already been cleared when the thread was first
|
// The thread's wakeup callback must have already been cleared when the thread was first
|
||||||
// awoken.
|
// awoken.
|
||||||
ASSERT(wakeup_callback == nullptr);
|
ASSERT(hle_callback == nullptr);
|
||||||
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
// If the thread is waiting on multiple wait objects, it might be awoken more than once
|
||||||
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
// before actually resuming. We can ignore subsequent wakeups if the thread status has
|
||||||
// already been set to ThreadStatus::Ready.
|
// already been set to ThreadStatus::Ready.
|
||||||
|
@ -112,7 +112,7 @@ void Thread::ResumeFromWait() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wakeup_callback = nullptr;
|
hle_callback = nullptr;
|
||||||
|
|
||||||
if (activity == ThreadActivity::Paused) {
|
if (activity == ThreadActivity::Paused) {
|
||||||
SetStatus(ThreadStatus::Paused);
|
SetStatus(ThreadStatus::Paused);
|
||||||
|
@ -398,8 +398,14 @@ bool Thread::AllSynchronizationObjectsReady() const {
|
||||||
bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<SynchronizationObject> object,
|
std::shared_ptr<SynchronizationObject> object,
|
||||||
std::size_t index) {
|
std::size_t index) {
|
||||||
ASSERT(wakeup_callback);
|
ASSERT(hle_callback);
|
||||||
return wakeup_callback(reason, std::move(thread), std::move(object), index);
|
return hle_callback(reason, std::move(thread), std::move(object), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<SynchronizationObject> object, std::size_t index) {
|
||||||
|
ASSERT(hle_callback);
|
||||||
|
return hle_callback(reason, std::move(thread), std::move(object), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::SetActivity(ThreadActivity value) {
|
void Thread::SetActivity(ThreadActivity value) {
|
||||||
|
|
|
@ -129,6 +129,7 @@ public:
|
||||||
using WakeupCallback =
|
using WakeupCallback =
|
||||||
std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
|
std::shared_ptr<SynchronizationObject> object, std::size_t index)>;
|
||||||
|
using HLECallback = std::function<bool(std::shared_ptr<Thread> thread)>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||||
|
@ -142,10 +143,10 @@ public:
|
||||||
* @param owner_process The parent process for the thread, if null, it's a kernel thread
|
* @param owner_process The parent process for the thread, if null, it's a kernel thread
|
||||||
* @return A shared pointer to the newly created thread
|
* @return A shared pointer to the newly created thread
|
||||||
*/
|
*/
|
||||||
static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags, std::string name,
|
static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags,
|
||||||
VAddr entry_point, u32 priority, u64 arg,
|
std::string name, VAddr entry_point,
|
||||||
s32 processor_id, VAddr stack_top,
|
u32 priority, u64 arg, s32 processor_id,
|
||||||
Process* owner_process);
|
VAddr stack_top, Process* owner_process);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a new thread. The new thread is immediately scheduled
|
* Creates and returns a new thread. The new thread is immediately scheduled
|
||||||
|
@ -161,10 +162,10 @@ public:
|
||||||
* @param thread_start_parameter The parameter which will passed to host context on init
|
* @param thread_start_parameter The parameter which will passed to host context on init
|
||||||
* @return A shared pointer to the newly created thread
|
* @return A shared pointer to the newly created thread
|
||||||
*/
|
*/
|
||||||
static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags, std::string name,
|
static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags,
|
||||||
VAddr entry_point, u32 priority, u64 arg,
|
std::string name, VAddr entry_point,
|
||||||
s32 processor_id, VAddr stack_top,
|
u32 priority, u64 arg, s32 processor_id,
|
||||||
Process* owner_process,
|
VAddr stack_top, Process* owner_process,
|
||||||
std::function<void(void*)>&& thread_start_func,
|
std::function<void(void*)>&& thread_start_func,
|
||||||
void* thread_start_parameter);
|
void* thread_start_parameter);
|
||||||
|
|
||||||
|
@ -447,17 +448,37 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasWakeupCallback() const {
|
bool HasWakeupCallback() const {
|
||||||
return wakeup_callback != nullptr;
|
return hle_callback != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasHLECallback() const {
|
||||||
|
return hle_callback != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetWakeupCallback(WakeupCallback callback) {
|
void SetWakeupCallback(WakeupCallback callback) {
|
||||||
wakeup_callback = std::move(callback);
|
hle_callback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHLECallback(WakeupCallback callback) {
|
||||||
|
hle_callback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHLETimeEvent(Handle time_event) {
|
||||||
|
hle_time_event = time_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle GetHLETimeEvent() const {
|
||||||
|
return hle_time_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateWakeupCallback() {
|
void InvalidateWakeupCallback() {
|
||||||
SetWakeupCallback(nullptr);
|
SetWakeupCallback(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InvalidateHLECallback() {
|
||||||
|
SetHLECallback(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes the thread's wakeup callback.
|
* Invokes the thread's wakeup callback.
|
||||||
*
|
*
|
||||||
|
@ -466,6 +487,8 @@ public:
|
||||||
*/
|
*/
|
||||||
bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
std::shared_ptr<SynchronizationObject> object, std::size_t index);
|
std::shared_ptr<SynchronizationObject> object, std::size_t index);
|
||||||
|
bool InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||||
|
std::shared_ptr<SynchronizationObject> object, std::size_t index);
|
||||||
|
|
||||||
u32 GetIdealCore() const {
|
u32 GetIdealCore() const {
|
||||||
return ideal_core;
|
return ideal_core;
|
||||||
|
@ -600,7 +623,8 @@ private:
|
||||||
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||||
/// was waiting via WaitSynchronization then the object will be the last object that became
|
/// was waiting via WaitSynchronization then the object will be the last object that became
|
||||||
/// available. In case of a timeout, the object will be nullptr.
|
/// available. In case of a timeout, the object will be nullptr.
|
||||||
WakeupCallback wakeup_callback;
|
WakeupCallback hle_callback;
|
||||||
|
Handle hle_time_event;
|
||||||
|
|
||||||
Scheduler* scheduler = nullptr;
|
Scheduler* scheduler = nullptr;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue