k_scheduler_lock.h 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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. template <typename SchedulerType>
  14. class KAbstractSchedulerLock {
  15. public:
  16. explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
  17. bool IsLockedByCurrentThread() const {
  18. return owner_thread == GetCurrentThreadPointer(kernel);
  19. }
  20. void Lock() {
  21. // If we are shutting down the kernel, none of this is relevant anymore.
  22. if (kernel.IsShuttingDown()) {
  23. return;
  24. }
  25. if (IsLockedByCurrentThread()) {
  26. // If we already own the lock, we can just increment the count.
  27. ASSERT(lock_count > 0);
  28. lock_count++;
  29. } else {
  30. // Otherwise, we want to disable scheduling and acquire the spinlock.
  31. SchedulerType::DisableScheduling(kernel);
  32. spin_lock.Lock();
  33. // For debug, ensure that our state is valid.
  34. ASSERT(lock_count == 0);
  35. ASSERT(owner_thread == nullptr);
  36. // Increment count, take ownership.
  37. lock_count = 1;
  38. owner_thread = GetCurrentThreadPointer(kernel);
  39. }
  40. }
  41. void Unlock() {
  42. // If we are shutting down the kernel, none of this is relevant anymore.
  43. if (kernel.IsShuttingDown()) {
  44. return;
  45. }
  46. ASSERT(IsLockedByCurrentThread());
  47. ASSERT(lock_count > 0);
  48. // Release an instance of the lock.
  49. if ((--lock_count) == 0) {
  50. // Perform a memory barrier here.
  51. std::atomic_thread_fence(std::memory_order_seq_cst);
  52. // We're no longer going to hold the lock. Take note of what cores need scheduling.
  53. const u64 cores_needing_scheduling =
  54. SchedulerType::UpdateHighestPriorityThreads(kernel);
  55. // Note that we no longer hold the lock, and unlock the spinlock.
  56. owner_thread = nullptr;
  57. spin_lock.Unlock();
  58. // Enable scheduling, and perform a rescheduling operation.
  59. SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
  60. }
  61. }
  62. private:
  63. KernelCore& kernel;
  64. KAlignedSpinLock spin_lock{};
  65. s32 lock_count{};
  66. std::atomic<KThread*> owner_thread{};
  67. };
  68. } // namespace Kernel