Merge pull request #1861 from lioncash/reset
kernel/svc: Correct behavior of svcResetSignal()
This commit is contained in:
commit
8de6403a08
|
@ -15,6 +15,7 @@ bool Object::IsWaitable() const {
|
||||||
switch (GetHandleType()) {
|
switch (GetHandleType()) {
|
||||||
case HandleType::ReadableEvent:
|
case HandleType::ReadableEvent:
|
||||||
case HandleType::Thread:
|
case HandleType::Thread:
|
||||||
|
case HandleType::Process:
|
||||||
case HandleType::Timer:
|
case HandleType::Timer:
|
||||||
case HandleType::ServerPort:
|
case HandleType::ServerPort:
|
||||||
case HandleType::ServerSession:
|
case HandleType::ServerSession:
|
||||||
|
@ -23,7 +24,6 @@ bool Object::IsWaitable() const {
|
||||||
case HandleType::Unknown:
|
case HandleType::Unknown:
|
||||||
case HandleType::WritableEvent:
|
case HandleType::WritableEvent:
|
||||||
case HandleType::SharedMemory:
|
case HandleType::SharedMemory:
|
||||||
case HandleType::Process:
|
|
||||||
case HandleType::AddressArbiter:
|
case HandleType::AddressArbiter:
|
||||||
case HandleType::ResourceLimit:
|
case HandleType::ResourceLimit:
|
||||||
case HandleType::ClientPort:
|
case HandleType::ClientPort:
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/file_sys/program_metadata.h"
|
#include "core/file_sys/program_metadata.h"
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
|
@ -48,6 +49,21 @@ SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
|
||||||
return resource_limit;
|
return resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode Process::ClearSignalState() {
|
||||||
|
if (status == ProcessStatus::Exited) {
|
||||||
|
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
||||||
|
return ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_signaled) {
|
||||||
|
LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
|
||||||
|
return ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_signaled = false;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||||
program_id = metadata.GetTitleID();
|
program_id = metadata.GetTitleID();
|
||||||
is_64bit_process = metadata.Is64BitProgram();
|
is_64bit_process = metadata.Is64BitProgram();
|
||||||
|
@ -137,13 +153,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
|
||||||
.Unwrap();
|
.Unwrap();
|
||||||
|
|
||||||
vm_manager.LogLayout();
|
vm_manager.LogLayout();
|
||||||
status = ProcessStatus::Running;
|
ChangeStatus(ProcessStatus::Running);
|
||||||
|
|
||||||
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
|
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::PrepareForTermination() {
|
void Process::PrepareForTermination() {
|
||||||
status = ProcessStatus::Exited;
|
ChangeStatus(ProcessStatus::Exiting);
|
||||||
|
|
||||||
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
|
const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) {
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
|
@ -167,6 +183,8 @@ void Process::PrepareForTermination() {
|
||||||
stop_threads(system.Scheduler(1).GetThreadList());
|
stop_threads(system.Scheduler(1).GetThreadList());
|
||||||
stop_threads(system.Scheduler(2).GetThreadList());
|
stop_threads(system.Scheduler(2).GetThreadList());
|
||||||
stop_threads(system.Scheduler(3).GetThreadList());
|
stop_threads(system.Scheduler(3).GetThreadList());
|
||||||
|
|
||||||
|
ChangeStatus(ProcessStatus::Exited);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,7 +283,25 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
|
||||||
return vm_manager.UnmapRange(dst_addr, size);
|
return vm_manager.UnmapRange(dst_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
|
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
|
||||||
Kernel::Process::~Process() {}
|
Kernel::Process::~Process() {}
|
||||||
|
|
||||||
|
void Process::Acquire(Thread* thread) {
|
||||||
|
ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::ShouldWait(Thread* thread) const {
|
||||||
|
return !is_signaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::ChangeStatus(ProcessStatus new_status) {
|
||||||
|
if (status == new_status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = new_status;
|
||||||
|
is_signaled = true;
|
||||||
|
WakeupAllWaitingThreads();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -14,9 +14,10 @@
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/object.h"
|
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/vm_manager.h"
|
#include "core/hle/kernel/vm_manager.h"
|
||||||
|
#include "core/hle/kernel/wait_object.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
class ProgramMetadata;
|
class ProgramMetadata;
|
||||||
|
@ -117,7 +118,7 @@ struct CodeSet final {
|
||||||
VAddr entrypoint = 0;
|
VAddr entrypoint = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Process final : public Object {
|
class Process final : public WaitObject {
|
||||||
public:
|
public:
|
||||||
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
||||||
|
|
||||||
|
@ -212,6 +213,16 @@ public:
|
||||||
return random_entropy.at(index);
|
return random_entropy.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears the signaled state of the process if and only if it's signaled.
|
||||||
|
///
|
||||||
|
/// @pre The process must not be already terminated. If this is called on a
|
||||||
|
/// terminated process, then ERR_INVALID_STATE will be returned.
|
||||||
|
///
|
||||||
|
/// @pre The process must be in a signaled state. If this is called on a
|
||||||
|
/// process instance that is not signaled, ERR_INVALID_STATE will be
|
||||||
|
/// returned.
|
||||||
|
ResultCode ClearSignalState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads process-specifics configuration info with metadata provided
|
* Loads process-specifics configuration info with metadata provided
|
||||||
* by an executable.
|
* by an executable.
|
||||||
|
@ -260,6 +271,17 @@ private:
|
||||||
explicit Process(KernelCore& kernel);
|
explicit Process(KernelCore& kernel);
|
||||||
~Process() override;
|
~Process() override;
|
||||||
|
|
||||||
|
/// Checks if the specified thread should wait until this process is available.
|
||||||
|
bool ShouldWait(Thread* thread) const override;
|
||||||
|
|
||||||
|
/// Acquires/locks this process for the specified thread if it's available.
|
||||||
|
void Acquire(Thread* thread) override;
|
||||||
|
|
||||||
|
/// Changes the process status. If the status is different
|
||||||
|
/// from the current process status, then this will trigger
|
||||||
|
/// a process signal.
|
||||||
|
void ChangeStatus(ProcessStatus new_status);
|
||||||
|
|
||||||
/// Memory manager for this process.
|
/// Memory manager for this process.
|
||||||
Kernel::VMManager vm_manager;
|
Kernel::VMManager vm_manager;
|
||||||
|
|
||||||
|
@ -305,6 +327,10 @@ private:
|
||||||
/// specified by metadata provided to the process during loading.
|
/// specified by metadata provided to the process during loading.
|
||||||
bool is_64bit_process = true;
|
bool is_64bit_process = true;
|
||||||
|
|
||||||
|
/// Whether or not this process is signaled. This occurs
|
||||||
|
/// upon the process changing to a different state.
|
||||||
|
bool is_signaled = false;
|
||||||
|
|
||||||
/// Total running time for the process in ticks.
|
/// Total running time for the process in ticks.
|
||||||
u64 total_process_running_time_ticks = 0;
|
u64 total_process_running_time_ticks = 0;
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/readable_event.h"
|
#include "core/hle/kernel/readable_event.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -34,6 +34,16 @@ void ReadableEvent::Clear() {
|
||||||
signaled = false;
|
signaled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode ReadableEvent::Reset() {
|
||||||
|
if (!signaled) {
|
||||||
|
return ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void ReadableEvent::WakeupAllWaitingThreads() {
|
void ReadableEvent::WakeupAllWaitingThreads() {
|
||||||
WaitObject::WakeupAllWaitingThreads();
|
WaitObject::WakeupAllWaitingThreads();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/wait_object.h"
|
||||||
|
|
||||||
|
union ResultCode;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KernelCore;
|
class KernelCore;
|
||||||
|
@ -39,8 +41,17 @@ public:
|
||||||
|
|
||||||
void WakeupAllWaitingThreads() override;
|
void WakeupAllWaitingThreads() override;
|
||||||
|
|
||||||
|
/// Unconditionally clears the readable event's state.
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
/// Clears the readable event's state if and only if it
|
||||||
|
/// has already been signaled.
|
||||||
|
///
|
||||||
|
/// @pre The event must be in a signaled state. If this event
|
||||||
|
/// is in an unsignaled state and this function is called,
|
||||||
|
/// then ERR_INVALID_STATE will be returned.
|
||||||
|
ResultCode Reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ReadableEvent(KernelCore& kernel);
|
explicit ReadableEvent(KernelCore& kernel);
|
||||||
|
|
||||||
|
|
|
@ -1433,17 +1433,24 @@ static ResultCode CloseHandle(Handle handle) {
|
||||||
return handle_table.Close(handle);
|
return handle_table.Close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset an event
|
/// Clears the signaled state of an event or process.
|
||||||
static ResultCode ResetSignal(Handle handle) {
|
static ResultCode ResetSignal(Handle handle) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
|
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
|
||||||
|
|
||||||
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
|
||||||
|
|
||||||
auto event = handle_table.Get<ReadableEvent>(handle);
|
auto event = handle_table.Get<ReadableEvent>(handle);
|
||||||
|
if (event) {
|
||||||
|
return event->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(event != nullptr);
|
auto process = handle_table.Get<Process>(handle);
|
||||||
|
if (process) {
|
||||||
|
return process->ClearSignalState();
|
||||||
|
}
|
||||||
|
|
||||||
event->Clear();
|
LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle);
|
||||||
return RESULT_SUCCESS;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a TransferMemory object
|
/// Creates a TransferMemory object
|
||||||
|
|
Reference in New Issue