Merge pull request #1861 from lioncash/reset

kernel/svc: Correct behavior of svcResetSignal()
This commit is contained in:
bunnei 2018-12-06 13:42:46 -05: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

View file

@ -15,6 +15,7 @@ bool Object::IsWaitable() const {
switch (GetHandleType()) {
case HandleType::ReadableEvent:
case HandleType::Thread:
case HandleType::Process:
case HandleType::Timer:
case HandleType::ServerPort:
case HandleType::ServerSession:
@ -23,7 +24,6 @@ bool Object::IsWaitable() const {
case HandleType::Unknown:
case HandleType::WritableEvent:
case HandleType::SharedMemory:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::ClientPort:

View file

@ -9,6 +9,7 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@ -48,6 +49,21 @@ SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
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) {
program_id = metadata.GetTitleID();
is_64bit_process = metadata.Is64BitProgram();
@ -137,13 +153,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
.Unwrap();
vm_manager.LogLayout();
status = ProcessStatus::Running;
ChangeStatus(ProcessStatus::Running);
Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this);
}
void Process::PrepareForTermination() {
status = ProcessStatus::Exited;
ChangeStatus(ProcessStatus::Exiting);
const auto stop_threads = [this](const std::vector<SharedPtr<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(2).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);
}
Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {}
Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {}
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

View file

@ -14,9 +14,10 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
namespace FileSys {
class ProgramMetadata;
@ -117,7 +118,7 @@ struct CodeSet final {
VAddr entrypoint = 0;
};
class Process final : public Object {
class Process final : public WaitObject {
public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
@ -212,6 +213,16 @@ public:
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
* by an executable.
@ -260,6 +271,17 @@ private:
explicit Process(KernelCore& kernel);
~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.
Kernel::VMManager vm_manager;
@ -305,6 +327,10 @@ private:
/// specified by metadata provided to the process during loading.
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.
u64 total_process_running_time_ticks = 0;

View file

@ -4,10 +4,10 @@
#include <algorithm>
#include "common/assert.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/writable_event.h"
namespace Kernel {
@ -34,6 +34,16 @@ void ReadableEvent::Clear() {
signaled = false;
}
ResultCode ReadableEvent::Reset() {
if (!signaled) {
return ERR_INVALID_STATE;
}
Clear();
return RESULT_SUCCESS;
}
void ReadableEvent::WakeupAllWaitingThreads() {
WaitObject::WakeupAllWaitingThreads();

View file

@ -7,6 +7,8 @@
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
union ResultCode;
namespace Kernel {
class KernelCore;
@ -39,8 +41,17 @@ public:
void WakeupAllWaitingThreads() override;
/// Unconditionally clears the readable event's state.
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:
explicit ReadableEvent(KernelCore& kernel);

View file

@ -1433,17 +1433,24 @@ static ResultCode CloseHandle(Handle handle) {
return handle_table.Close(handle);
}
/// Reset an event
/// Clears the signaled state of an event or process.
static ResultCode ResetSignal(Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
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();
return RESULT_SUCCESS;
LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle);
return ERR_INVALID_HANDLE;
}
/// Creates a TransferMemory object