SVC: Correct SendSyncRequest.

This commit is contained in:
Fernando Sahmkow 2020-02-25 19:43:28 -04:00
parent 203e706302
commit 15a79eb0d7
8 changed files with 116 additions and 54 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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) {

View File

@ -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;