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;