mutex.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <map>
  5. #include <vector>
  6. #include "common/common.h"
  7. #include "core/hle/kernel/kernel.h"
  8. #include "core/hle/kernel/mutex.h"
  9. #include "core/hle/kernel/thread.h"
  10. namespace Kernel {
  11. class Mutex : public Object {
  12. public:
  13. std::string GetTypeName() const override { return "Mutex"; }
  14. std::string GetName() const override { return name; }
  15. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
  16. Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; }
  17. bool initial_locked; ///< Initial lock state when mutex was created
  18. bool locked; ///< Current locked state
  19. Handle lock_thread; ///< Handle to thread that currently has mutex
  20. std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
  21. std::string name; ///< Name of mutex (optional)
  22. /**
  23. * Synchronize kernel object
  24. * @param wait Boolean wait set if current thread should wait as a result of sync operation
  25. * @return Result of operation, 0 on success, otherwise error code
  26. */
  27. Result SyncRequest(bool* wait) override {
  28. // TODO(bunnei): ImplementMe
  29. locked = true;
  30. return 0;
  31. }
  32. /**
  33. * Wait for kernel object to synchronize
  34. * @param wait Boolean wait set if current thread should wait as a result of sync operation
  35. * @return Result of operation, 0 on success, otherwise error code
  36. */
  37. Result WaitSynchronization(bool* wait) override {
  38. // TODO(bunnei): ImplementMe
  39. *wait = locked;
  40. if (locked) {
  41. Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
  42. }
  43. return 0;
  44. }
  45. };
  46. ////////////////////////////////////////////////////////////////////////////////////////////////////
  47. typedef std::multimap<Handle, Handle> MutexMap;
  48. static MutexMap g_mutex_held_locks;
  49. void MutexAcquireLock(Mutex* mutex, Handle thread) {
  50. g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
  51. mutex->lock_thread = thread;
  52. }
  53. void MutexAcquireLock(Mutex* mutex) {
  54. Handle thread = GetCurrentThreadHandle();
  55. MutexAcquireLock(mutex, thread);
  56. }
  57. void MutexEraseLock(Mutex* mutex) {
  58. Handle handle = mutex->GetHandle();
  59. auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
  60. for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
  61. if ((*iter).second == handle) {
  62. g_mutex_held_locks.erase(iter);
  63. break;
  64. }
  65. }
  66. mutex->lock_thread = -1;
  67. }
  68. bool LockMutex(Mutex* mutex) {
  69. // Mutex alread locked?
  70. if (mutex->locked) {
  71. return false;
  72. }
  73. MutexAcquireLock(mutex);
  74. return true;
  75. }
  76. bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
  77. MutexAcquireLock(mutex, thread);
  78. Kernel::ResumeThreadFromWait(thread);
  79. return true;
  80. }
  81. bool ReleaseMutex(Mutex* mutex) {
  82. MutexEraseLock(mutex);
  83. bool woke_threads = false;
  84. // Find the next waiting thread for the mutex...
  85. while (!woke_threads && !mutex->waiting_threads.empty()) {
  86. std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
  87. woke_threads |= ReleaseMutexForThread(mutex, *iter);
  88. mutex->waiting_threads.erase(iter);
  89. }
  90. // Reset mutex lock thread handle, nothing is waiting
  91. if (!woke_threads) {
  92. mutex->locked = false;
  93. mutex->lock_thread = -1;
  94. }
  95. return woke_threads;
  96. }
  97. /**
  98. * Releases a mutex
  99. * @param handle Handle to mutex to release
  100. */
  101. Result ReleaseMutex(Handle handle) {
  102. Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
  103. _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
  104. if (!ReleaseMutex(mutex)) {
  105. return -1;
  106. }
  107. return 0;
  108. }
  109. /**
  110. * Creates a mutex
  111. * @param handle Reference to handle for the newly created mutex
  112. * @param initial_locked Specifies if the mutex should be locked initially
  113. * @param name Optional name of mutex
  114. * @return Pointer to new Mutex object
  115. */
  116. Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
  117. Mutex* mutex = new Mutex;
  118. handle = Kernel::g_object_pool.Create(mutex);
  119. mutex->locked = mutex->initial_locked = initial_locked;
  120. mutex->name = name;
  121. // Acquire mutex with current thread if initialized as locked...
  122. if (mutex->locked) {
  123. MutexAcquireLock(mutex);
  124. // Otherwise, reset lock thread handle
  125. } else {
  126. mutex->lock_thread = -1;
  127. }
  128. return mutex;
  129. }
  130. /**
  131. * Creates a mutex
  132. * @param initial_locked Specifies if the mutex should be locked initially
  133. * @param name Optional name of mutex
  134. * @return Handle to newly created object
  135. */
  136. Handle CreateMutex(bool initial_locked, const std::string& name) {
  137. Handle handle;
  138. Mutex* mutex = CreateMutex(handle, initial_locked, name);
  139. return handle;
  140. }
  141. } // namespace