k_scheduler_lock.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <atomic>
  5. #include "common/assert.h"
  6. #include "core/hle/kernel/k_interrupt_manager.h"
  7. #include "core/hle/kernel/k_spin_lock.h"
  8. #include "core/hle/kernel/k_thread.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/kernel/physical_core.h"
  11. namespace Kernel {
  12. class KernelCore;
  13. class GlobalSchedulerContext;
  14. template <typename SchedulerType>
  15. class KAbstractSchedulerLock {
  16. public:
  17. explicit KAbstractSchedulerLock(KernelCore& kernel) : m_kernel{kernel} {}
  18. bool IsLockedByCurrentThread() const {
  19. return m_owner_thread == GetCurrentThreadPointer(m_kernel);
  20. }
  21. void Lock() {
  22. if (this->IsLockedByCurrentThread()) {
  23. // If we already own the lock, the lock count should be > 0.
  24. // For debug, ensure this is true.
  25. ASSERT(m_lock_count > 0);
  26. } else {
  27. // Otherwise, we want to disable scheduling and acquire the spinlock.
  28. SchedulerType::DisableScheduling(m_kernel);
  29. m_spin_lock.Lock();
  30. ASSERT(m_lock_count == 0);
  31. ASSERT(m_owner_thread == nullptr);
  32. // Take ownership of the lock.
  33. m_owner_thread = GetCurrentThreadPointer(m_kernel);
  34. }
  35. // Increment the lock count.
  36. m_lock_count++;
  37. }
  38. void Unlock() {
  39. ASSERT(this->IsLockedByCurrentThread());
  40. ASSERT(m_lock_count > 0);
  41. // Release an instance of the lock.
  42. if ((--m_lock_count) == 0) {
  43. // Perform a memory barrier here.
  44. std::atomic_thread_fence(std::memory_order_seq_cst);
  45. // We're no longer going to hold the lock. Take note of what cores need scheduling.
  46. const u64 cores_needing_scheduling =
  47. SchedulerType::UpdateHighestPriorityThreads(m_kernel);
  48. // Note that we no longer hold the lock, and unlock the spinlock.
  49. m_owner_thread = nullptr;
  50. m_spin_lock.Unlock();
  51. // Enable scheduling, and perform a rescheduling operation.
  52. SchedulerType::EnableScheduling(m_kernel, cores_needing_scheduling);
  53. }
  54. }
  55. private:
  56. friend class GlobalSchedulerContext;
  57. KernelCore& m_kernel;
  58. KAlignedSpinLock m_spin_lock{};
  59. s32 m_lock_count{};
  60. std::atomic<KThread*> m_owner_thread{};
  61. };
  62. } // namespace Kernel