diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index bb1b687786256ed2a533fb5ee091b8e1308d1d01..0ea851a74a6ca0c7c1d511e80ed70b4958c0bc6c 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -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:
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 4ecb8c92633b3a6065c67810e411cda1736e2543..211bf66863be446aa94635aacee70c4e4b521f7b 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -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
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 49345aa664f615c5c4f5e949e762afdc6973c593..bcb9ac4b816ea1b26f0c55deb8a34a236d3323de 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -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;
 
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index 92e16b4e60b721fd4f7a71430f1d1c54ed855301..ba01f495c7fd3416dc0447f885271a93ca8efa68 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -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();
 
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 867ff3051de799b9da0d0de76f52ac1c324fb48e..80b3b0abaf12901dae10a7416e9382196871daf5 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -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);
 
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index e6c77f9db85952e51ab62a99203fbd12508d860d..84df2040e9439839d57898481e9b38af5829f369 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -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