diff options
| -rw-r--r-- | src/core/hle/kernel/object.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/readable_event.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/readable_event.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 15 |
6 files changed, 101 insertions, 11 deletions
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index bb1b68778..0ea851a74 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp | |||
| @@ -15,6 +15,7 @@ bool Object::IsWaitable() const { | |||
| 15 | switch (GetHandleType()) { | 15 | switch (GetHandleType()) { |
| 16 | case HandleType::ReadableEvent: | 16 | case HandleType::ReadableEvent: |
| 17 | case HandleType::Thread: | 17 | case HandleType::Thread: |
| 18 | case HandleType::Process: | ||
| 18 | case HandleType::Timer: | 19 | case HandleType::Timer: |
| 19 | case HandleType::ServerPort: | 20 | case HandleType::ServerPort: |
| 20 | case HandleType::ServerSession: | 21 | case HandleType::ServerSession: |
| @@ -23,7 +24,6 @@ bool Object::IsWaitable() const { | |||
| 23 | case HandleType::Unknown: | 24 | case HandleType::Unknown: |
| 24 | case HandleType::WritableEvent: | 25 | case HandleType::WritableEvent: |
| 25 | case HandleType::SharedMemory: | 26 | case HandleType::SharedMemory: |
| 26 | case HandleType::Process: | ||
| 27 | case HandleType::AddressArbiter: | 27 | case HandleType::AddressArbiter: |
| 28 | case HandleType::ResourceLimit: | 28 | case HandleType::ResourceLimit: |
| 29 | case HandleType::ClientPort: | 29 | case HandleType::ClientPort: |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 4ecb8c926..211bf6686 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/file_sys/program_metadata.h" | 11 | #include "core/file_sys/program_metadata.h" |
| 12 | #include "core/hle/kernel/errors.h" | ||
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 14 | #include "core/hle/kernel/resource_limit.h" | 15 | #include "core/hle/kernel/resource_limit.h" |
| @@ -48,6 +49,21 @@ SharedPtr<ResourceLimit> Process::GetResourceLimit() const { | |||
| 48 | return resource_limit; | 49 | return resource_limit; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 52 | ResultCode Process::ClearSignalState() { | ||
| 53 | if (status == ProcessStatus::Exited) { | ||
| 54 | LOG_ERROR(Kernel, "called on a terminated process instance."); | ||
| 55 | return ERR_INVALID_STATE; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (!is_signaled) { | ||
| 59 | LOG_ERROR(Kernel, "called on a process instance that isn't signaled."); | ||
| 60 | return ERR_INVALID_STATE; | ||
| 61 | } | ||
| 62 | |||
| 63 | is_signaled = false; | ||
| 64 | return RESULT_SUCCESS; | ||
| 65 | } | ||
| 66 | |||
| 51 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | 67 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { |
| 52 | program_id = metadata.GetTitleID(); | 68 | program_id = metadata.GetTitleID(); |
| 53 | is_64bit_process = metadata.Is64BitProgram(); | 69 | is_64bit_process = metadata.Is64BitProgram(); |
| @@ -137,13 +153,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | |||
| 137 | .Unwrap(); | 153 | .Unwrap(); |
| 138 | 154 | ||
| 139 | vm_manager.LogLayout(); | 155 | vm_manager.LogLayout(); |
| 140 | status = ProcessStatus::Running; | 156 | ChangeStatus(ProcessStatus::Running); |
| 141 | 157 | ||
| 142 | Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this); | 158 | Kernel::SetupMainThread(kernel, entry_point, main_thread_priority, *this); |
| 143 | } | 159 | } |
| 144 | 160 | ||
| 145 | void Process::PrepareForTermination() { | 161 | void Process::PrepareForTermination() { |
| 146 | status = ProcessStatus::Exited; | 162 | ChangeStatus(ProcessStatus::Exiting); |
| 147 | 163 | ||
| 148 | const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) { | 164 | const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) { |
| 149 | for (auto& thread : thread_list) { | 165 | for (auto& thread : thread_list) { |
| @@ -167,6 +183,8 @@ void Process::PrepareForTermination() { | |||
| 167 | stop_threads(system.Scheduler(1).GetThreadList()); | 183 | stop_threads(system.Scheduler(1).GetThreadList()); |
| 168 | stop_threads(system.Scheduler(2).GetThreadList()); | 184 | stop_threads(system.Scheduler(2).GetThreadList()); |
| 169 | stop_threads(system.Scheduler(3).GetThreadList()); | 185 | stop_threads(system.Scheduler(3).GetThreadList()); |
| 186 | |||
| 187 | ChangeStatus(ProcessStatus::Exited); | ||
| 170 | } | 188 | } |
| 171 | 189 | ||
| 172 | /** | 190 | /** |
| @@ -265,7 +283,25 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { | |||
| 265 | return vm_manager.UnmapRange(dst_addr, size); | 283 | return vm_manager.UnmapRange(dst_addr, size); |
| 266 | } | 284 | } |
| 267 | 285 | ||
| 268 | Kernel::Process::Process(KernelCore& kernel) : Object{kernel} {} | 286 | Kernel::Process::Process(KernelCore& kernel) : WaitObject{kernel} {} |
| 269 | Kernel::Process::~Process() {} | 287 | Kernel::Process::~Process() {} |
| 270 | 288 | ||
| 289 | void Process::Acquire(Thread* thread) { | ||
| 290 | ASSERT_MSG(!ShouldWait(thread), "Object unavailable!"); | ||
| 291 | } | ||
| 292 | |||
| 293 | bool Process::ShouldWait(Thread* thread) const { | ||
| 294 | return !is_signaled; | ||
| 295 | } | ||
| 296 | |||
| 297 | void Process::ChangeStatus(ProcessStatus new_status) { | ||
| 298 | if (status == new_status) { | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | |||
| 302 | status = new_status; | ||
| 303 | is_signaled = true; | ||
| 304 | WakeupAllWaitingThreads(); | ||
| 305 | } | ||
| 306 | |||
| 271 | } // namespace Kernel | 307 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 49345aa66..bcb9ac4b8 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -14,9 +14,10 @@ | |||
| 14 | #include "common/bit_field.h" | 14 | #include "common/bit_field.h" |
| 15 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| 16 | #include "core/hle/kernel/handle_table.h" | 16 | #include "core/hle/kernel/handle_table.h" |
| 17 | #include "core/hle/kernel/object.h" | ||
| 18 | #include "core/hle/kernel/thread.h" | 17 | #include "core/hle/kernel/thread.h" |
| 19 | #include "core/hle/kernel/vm_manager.h" | 18 | #include "core/hle/kernel/vm_manager.h" |
| 19 | #include "core/hle/kernel/wait_object.h" | ||
| 20 | #include "core/hle/result.h" | ||
| 20 | 21 | ||
| 21 | namespace FileSys { | 22 | namespace FileSys { |
| 22 | class ProgramMetadata; | 23 | class ProgramMetadata; |
| @@ -117,7 +118,7 @@ struct CodeSet final { | |||
| 117 | VAddr entrypoint = 0; | 118 | VAddr entrypoint = 0; |
| 118 | }; | 119 | }; |
| 119 | 120 | ||
| 120 | class Process final : public Object { | 121 | class Process final : public WaitObject { |
| 121 | public: | 122 | public: |
| 122 | static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; | 123 | static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; |
| 123 | 124 | ||
| @@ -212,6 +213,16 @@ public: | |||
| 212 | return random_entropy.at(index); | 213 | return random_entropy.at(index); |
| 213 | } | 214 | } |
| 214 | 215 | ||
| 216 | /// Clears the signaled state of the process if and only if it's signaled. | ||
| 217 | /// | ||
| 218 | /// @pre The process must not be already terminated. If this is called on a | ||
| 219 | /// terminated process, then ERR_INVALID_STATE will be returned. | ||
| 220 | /// | ||
| 221 | /// @pre The process must be in a signaled state. If this is called on a | ||
| 222 | /// process instance that is not signaled, ERR_INVALID_STATE will be | ||
| 223 | /// returned. | ||
| 224 | ResultCode ClearSignalState(); | ||
| 225 | |||
| 215 | /** | 226 | /** |
| 216 | * Loads process-specifics configuration info with metadata provided | 227 | * Loads process-specifics configuration info with metadata provided |
| 217 | * by an executable. | 228 | * by an executable. |
| @@ -260,6 +271,17 @@ private: | |||
| 260 | explicit Process(KernelCore& kernel); | 271 | explicit Process(KernelCore& kernel); |
| 261 | ~Process() override; | 272 | ~Process() override; |
| 262 | 273 | ||
| 274 | /// Checks if the specified thread should wait until this process is available. | ||
| 275 | bool ShouldWait(Thread* thread) const override; | ||
| 276 | |||
| 277 | /// Acquires/locks this process for the specified thread if it's available. | ||
| 278 | void Acquire(Thread* thread) override; | ||
| 279 | |||
| 280 | /// Changes the process status. If the status is different | ||
| 281 | /// from the current process status, then this will trigger | ||
| 282 | /// a process signal. | ||
| 283 | void ChangeStatus(ProcessStatus new_status); | ||
| 284 | |||
| 263 | /// Memory manager for this process. | 285 | /// Memory manager for this process. |
| 264 | Kernel::VMManager vm_manager; | 286 | Kernel::VMManager vm_manager; |
| 265 | 287 | ||
| @@ -305,6 +327,10 @@ private: | |||
| 305 | /// specified by metadata provided to the process during loading. | 327 | /// specified by metadata provided to the process during loading. |
| 306 | bool is_64bit_process = true; | 328 | bool is_64bit_process = true; |
| 307 | 329 | ||
| 330 | /// Whether or not this process is signaled. This occurs | ||
| 331 | /// upon the process changing to a different state. | ||
| 332 | bool is_signaled = false; | ||
| 333 | |||
| 308 | /// Total running time for the process in ticks. | 334 | /// Total running time for the process in ticks. |
| 309 | u64 total_process_running_time_ticks = 0; | 335 | u64 total_process_running_time_ticks = 0; |
| 310 | 336 | ||
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index 92e16b4e6..ba01f495c 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp | |||
| @@ -4,10 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/hle/kernel/errors.h" | ||
| 7 | #include "core/hle/kernel/object.h" | 8 | #include "core/hle/kernel/object.h" |
| 8 | #include "core/hle/kernel/readable_event.h" | 9 | #include "core/hle/kernel/readable_event.h" |
| 9 | #include "core/hle/kernel/thread.h" | 10 | #include "core/hle/kernel/thread.h" |
| 10 | #include "core/hle/kernel/writable_event.h" | ||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| @@ -34,6 +34,16 @@ void ReadableEvent::Clear() { | |||
| 34 | signaled = false; | 34 | signaled = false; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | ResultCode ReadableEvent::Reset() { | ||
| 38 | if (!signaled) { | ||
| 39 | return ERR_INVALID_STATE; | ||
| 40 | } | ||
| 41 | |||
| 42 | Clear(); | ||
| 43 | |||
| 44 | return RESULT_SUCCESS; | ||
| 45 | } | ||
| 46 | |||
| 37 | void ReadableEvent::WakeupAllWaitingThreads() { | 47 | void ReadableEvent::WakeupAllWaitingThreads() { |
| 38 | WaitObject::WakeupAllWaitingThreads(); | 48 | WaitObject::WakeupAllWaitingThreads(); |
| 39 | 49 | ||
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h index 867ff3051..80b3b0aba 100644 --- a/src/core/hle/kernel/readable_event.h +++ b/src/core/hle/kernel/readable_event.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include "core/hle/kernel/object.h" | 7 | #include "core/hle/kernel/object.h" |
| 8 | #include "core/hle/kernel/wait_object.h" | 8 | #include "core/hle/kernel/wait_object.h" |
| 9 | 9 | ||
| 10 | union ResultCode; | ||
| 11 | |||
| 10 | namespace Kernel { | 12 | namespace Kernel { |
| 11 | 13 | ||
| 12 | class KernelCore; | 14 | class KernelCore; |
| @@ -39,8 +41,17 @@ public: | |||
| 39 | 41 | ||
| 40 | void WakeupAllWaitingThreads() override; | 42 | void WakeupAllWaitingThreads() override; |
| 41 | 43 | ||
| 44 | /// Unconditionally clears the readable event's state. | ||
| 42 | void Clear(); | 45 | void Clear(); |
| 43 | 46 | ||
| 47 | /// Clears the readable event's state if and only if it | ||
| 48 | /// has already been signaled. | ||
| 49 | /// | ||
| 50 | /// @pre The event must be in a signaled state. If this event | ||
| 51 | /// is in an unsignaled state and this function is called, | ||
| 52 | /// then ERR_INVALID_STATE will be returned. | ||
| 53 | ResultCode Reset(); | ||
| 54 | |||
| 44 | private: | 55 | private: |
| 45 | explicit ReadableEvent(KernelCore& kernel); | 56 | explicit ReadableEvent(KernelCore& kernel); |
| 46 | 57 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e6c77f9db..84df2040e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1433,17 +1433,24 @@ static ResultCode CloseHandle(Handle handle) { | |||
| 1433 | return handle_table.Close(handle); | 1433 | return handle_table.Close(handle); |
| 1434 | } | 1434 | } |
| 1435 | 1435 | ||
| 1436 | /// Reset an event | 1436 | /// Clears the signaled state of an event or process. |
| 1437 | static ResultCode ResetSignal(Handle handle) { | 1437 | static ResultCode ResetSignal(Handle handle) { |
| 1438 | LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); | 1438 | LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); |
| 1439 | 1439 | ||
| 1440 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1440 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1441 | |||
| 1441 | auto event = handle_table.Get<ReadableEvent>(handle); | 1442 | auto event = handle_table.Get<ReadableEvent>(handle); |
| 1443 | if (event) { | ||
| 1444 | return event->Reset(); | ||
| 1445 | } | ||
| 1442 | 1446 | ||
| 1443 | ASSERT(event != nullptr); | 1447 | auto process = handle_table.Get<Process>(handle); |
| 1448 | if (process) { | ||
| 1449 | return process->ClearSignalState(); | ||
| 1450 | } | ||
| 1444 | 1451 | ||
| 1445 | event->Clear(); | 1452 | LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle); |
| 1446 | return RESULT_SUCCESS; | 1453 | return ERR_INVALID_HANDLE; |
| 1447 | } | 1454 | } |
| 1448 | 1455 | ||
| 1449 | /// Creates a TransferMemory object | 1456 | /// Creates a TransferMemory object |