mutex.cpp 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <map>
  5. #include <vector>
  6. #include <boost/range/algorithm_ext/erase.hpp>
  7. #include "common/assert.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/mutex.h"
  10. #include "core/hle/kernel/thread.h"
  11. namespace Kernel {
  12. /**
  13. * Resumes a thread waiting for the specified mutex
  14. * @param mutex The mutex that some thread is waiting on
  15. */
  16. static void ResumeWaitingThread(Mutex* mutex) {
  17. // Reset mutex lock thread handle, nothing is waiting
  18. mutex->lock_count = 0;
  19. mutex->holding_thread = nullptr;
  20. mutex->WakeupAllWaitingThreads();
  21. }
  22. void ReleaseThreadMutexes(Thread* thread) {
  23. for (auto& mtx : thread->held_mutexes) {
  24. ResumeWaitingThread(mtx.get());
  25. }
  26. thread->held_mutexes.clear();
  27. }
  28. Mutex::Mutex() {}
  29. Mutex::~Mutex() {}
  30. SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
  31. SharedPtr<Mutex> mutex(new Mutex);
  32. mutex->lock_count = 0;
  33. mutex->name = std::move(name);
  34. mutex->holding_thread = nullptr;
  35. // Acquire mutex with current thread if initialized as locked...
  36. if (initial_locked)
  37. mutex->Acquire();
  38. return mutex;
  39. }
  40. bool Mutex::ShouldWait() {
  41. auto thread = GetCurrentThread();
  42. bool wait = lock_count > 0 && holding_thread != thread;
  43. // If the holding thread of the mutex is lower priority than this thread, that thread should
  44. // temporarily inherit this thread's priority
  45. if (wait && thread->current_priority < holding_thread->current_priority)
  46. holding_thread->BoostPriority(thread->current_priority);
  47. return wait;
  48. }
  49. void Mutex::Acquire() {
  50. Acquire(GetCurrentThread());
  51. }
  52. void Mutex::Acquire(SharedPtr<Thread> thread) {
  53. ASSERT_MSG(!ShouldWait(), "object unavailable!");
  54. // Actually "acquire" the mutex only if we don't already have it...
  55. if (lock_count == 0) {
  56. thread->held_mutexes.insert(this);
  57. holding_thread = std::move(thread);
  58. }
  59. lock_count++;
  60. }
  61. void Mutex::Release() {
  62. // Only release if the mutex is held...
  63. if (lock_count > 0) {
  64. lock_count--;
  65. // Yield to the next thread only if we've fully released the mutex...
  66. if (lock_count == 0) {
  67. holding_thread->held_mutexes.erase(this);
  68. ResumeWaitingThread(this);
  69. Core::System::GetInstance().PrepareReschedule();
  70. }
  71. }
  72. }
  73. } // namespace