diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ee61f22c05..5f6dce52a7 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -159,6 +159,7 @@ add_library(core STATIC
     hle/kernel/k_scheduler.cpp
     hle/kernel/k_scheduler.h
     hle/kernel/k_scheduler_lock.h
+    hle/kernel/k_scoped_scheduler_lock_and_sleep.h
     hle/kernel/kernel.cpp
     hle/kernel/kernel.h
     hle/kernel/memory/address_space_info.cpp
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index bc32be18b6..ac49131735 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -13,6 +13,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
@@ -157,7 +158,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
 
     Handle event_handle = InvalidHandle;
     {
-        SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
 
         if (current_thread->IsPendingTermination()) {
             lock.CancelSleep();
@@ -227,7 +228,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
 
     Handle event_handle = InvalidHandle;
     {
-        SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
 
         if (current_thread->IsPendingTermination()) {
             lock.CancelSleep();
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index 40e9adf478..a9cb48b38e 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -44,12 +44,4 @@ bool GlobalSchedulerContext::IsLocked() const {
     return scheduler_lock.IsLockedByCurrentThread();
 }
 
-void GlobalSchedulerContext::Lock() {
-    scheduler_lock.Lock();
-}
-
-void GlobalSchedulerContext::Unlock() {
-    scheduler_lock.Unlock();
-}
-
 } // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 40fe44cc0e..39c383746a 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -55,15 +55,7 @@ public:
 
 private:
     friend class SchedulerLock;
-
-    /// Lock the scheduler to the current thread.
-    void Lock();
-
-    /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
-    /// and reschedules current core if needed.
-    void Unlock();
-
-    using LockType = KAbstractSchedulerLock<KScheduler>;
+    friend class KScopedSchedulerLockAndSleep;
 
     KernelCore& kernel;
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 7eda89786e..e75e80ad00 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
@@ -56,9 +57,9 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
         writable_event = pair.writable;
     }
 
+    Handle event_handle = InvalidHandle;
     {
-        Handle event_handle = InvalidHandle;
-        SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout);
         thread->SetHLECallback(
             [context = *this, callback](std::shared_ptr<Thread> thread) mutable -> bool {
                 ThreadWakeupReason reason = thread->GetSignalingResult() == RESULT_TIMEOUT
@@ -74,9 +75,8 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
         thread->SetStatus(ThreadStatus::WaitHLEEvent);
         thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
         readable_event->AddWaitingThread(thread);
-        lock.Release();
-        thread->SetHLETimeEvent(event_handle);
     }
+    thread->SetHLETimeEvent(event_handle);
 
     is_thread_waiting = true;
 
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index c7e2eabd43..4661474989 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -14,6 +14,7 @@
 #include "core/core_timing.h"
 #include "core/cpu_manager.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
@@ -800,28 +801,4 @@ SchedulerLock::~SchedulerLock() {
     kernel.GlobalSchedulerContext().Unlock();
 }
 
-SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
-                                             Thread* time_task, s64 nanoseconds)
-    : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
-                                                                                   nanoseconds} {
-    event_handle = InvalidHandle;
-}
-
-SchedulerLockAndSleep::~SchedulerLockAndSleep() {
-    if (sleep_cancelled) {
-        return;
-    }
-    auto& time_manager = kernel.TimeManager();
-    time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
-}
-
-void SchedulerLockAndSleep::Release() {
-    if (sleep_cancelled) {
-        return;
-    }
-    auto& time_manager = kernel.TimeManager();
-    time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
-    sleep_cancelled = true;
-}
-
 } // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 7f020d96e2..5ba0f3c323 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -207,23 +207,4 @@ protected:
     KernelCore& kernel;
 };
 
-class SchedulerLockAndSleep : public SchedulerLock {
-public:
-    explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
-                                   s64 nanoseconds);
-    ~SchedulerLockAndSleep();
-
-    void CancelSleep() {
-        sleep_cancelled = true;
-    }
-
-    void Release();
-
-private:
-    Handle& event_handle;
-    Thread* time_task;
-    s64 nanoseconds;
-    bool sleep_cancelled{};
-};
-
 } // namespace Kernel
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
new file mode 100644
index 0000000000..f11a62216a
--- /dev/null
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -0,0 +1,56 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// This file references various implementation details from Atmosphere, an open-source firmware for
+// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/time_manager.h"
+
+namespace Kernel {
+
+class KScopedSchedulerLockAndSleep {
+private:
+    KernelCore& kernel;
+    s64 timeout_tick{};
+    Thread* thread{};
+    Handle* event_handle{};
+
+public:
+    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Thread* t, s64 timeout)
+        : kernel(kernel), timeout_tick(timeout), thread(t) {
+        /* Lock the scheduler. */
+        kernel.GlobalSchedulerContext().scheduler_lock.Lock();
+    }
+
+    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t,
+                                          s64 timeout)
+        : kernel(kernel), event_handle(&event_handle), timeout_tick(timeout), thread(t) {
+        /* Lock the scheduler. */
+        kernel.GlobalSchedulerContext().scheduler_lock.Lock();
+    }
+
+    ~KScopedSchedulerLockAndSleep() {
+        /* Register the sleep. */
+        if (this->timeout_tick > 0) {
+            auto& time_manager = kernel.TimeManager();
+            Handle handle{};
+            time_manager.ScheduleTimeEvent(event_handle ? *event_handle : handle, this->thread,
+                                           this->timeout_tick);
+        }
+
+        /* Unlock the scheduler. */
+        kernel.GlobalSchedulerContext().scheduler_lock.Unlock();
+    }
+
+    void CancelSleep() {
+        this->timeout_tick = 0;
+    }
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 2612a6b0d7..2760a307c4 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -25,6 +25,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_block.h"
 #include "core/hle/kernel/memory/page_table.h"
@@ -1654,7 +1655,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
     Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread();
     auto* const current_process = kernel.CurrentProcess();
     {
-        SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
         const auto& handle_table = current_process->GetHandleTable();
         std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
         ASSERT(thread);
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
index 342fb4516a..6651ad90cd 100644
--- a/src/core/hle/kernel/synchronization.cpp
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -6,6 +6,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/synchronization.h"
 #include "core/hle/kernel/synchronization_object.h"
@@ -40,7 +41,7 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(
     auto* const thread = kernel.CurrentScheduler()->GetCurrentThread();
     Handle event_handle = InvalidHandle;
     {
-        SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
         const auto itr =
             std::find_if(sync_objects.begin(), sync_objects.end(),
                          [thread](const std::shared_ptr<SynchronizationObject>& object) {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 804e07f2bd..6f89238caa 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
@@ -393,7 +394,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) {
 ResultCode Thread::Sleep(s64 nanoseconds) {
     Handle event_handle{};
     {
-        SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
+        KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
         SetStatus(ThreadStatus::WaitSleep);
     }