Merge pull request #1861 from lioncash/reset

kernel/svc: Correct behavior of svcResetSignal()
master
bunnei 2018-12-06 13:42:46 +07:00 committed by GitHub
commit 8de6403a08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 11 deletions

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