mutex.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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. const char* GetTypeName() { return "Mutex"; }
  14. const char* GetName() { return name.c_str(); }
  15. static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
  16. Kernel::HandleType GetHandleType() const { 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) {
  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) {
  38. // TODO(bunnei): ImplementMe
  39. *wait = locked;
  40. if (locked) {
  41. Kernel::WaitCurrentThread(WAITTYPE_MUTEX);
  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. std::vector<Handle>::iterator iter;
  85. // Find the next waiting thread for the mutex...
  86. while (!woke_threads && !mutex->waiting_threads.empty()) {
  87. iter = mutex->waiting_threads.begin();
  88. woke_threads |= ReleaseMutexForThread(mutex, *iter);
  89. mutex->waiting_threads.erase(iter);
  90. }
  91. // Reset mutex lock thread handle, nothing is waiting
  92. if (!woke_threads) {
  93. mutex->locked = false;
  94. mutex->lock_thread = -1;
  95. }
  96. return woke_threads;
  97. }
  98. /**
  99. * Releases a mutex
  100. * @param handle Handle to mutex to release
  101. */
  102. Result ReleaseMutex(Handle handle) {
  103. Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
  104. _assert_msg_(KERNEL, mutex, "ReleaseMutex tried to release a NULL mutex!");
  105. if (!ReleaseMutex(mutex)) {
  106. return -1;
  107. }
  108. return 0;
  109. }
  110. /**
  111. * Creates a mutex
  112. * @param handle Reference to handle for the newly created mutex
  113. * @param initial_locked Specifies if the mutex should be locked initially
  114. * @param name Optional name of mutex
  115. * @return Pointer to new Mutex object
  116. */
  117. Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string name) {
  118. Mutex* mutex = new Mutex;
  119. handle = Kernel::g_object_pool.Create(mutex);
  120. mutex->locked = mutex->initial_locked = initial_locked;
  121. mutex->name = name;
  122. // Acquire mutex with current thread if initialized as locked...
  123. if (mutex->locked) {
  124. MutexAcquireLock(mutex);
  125. // Otherwise, reset lock thread handle
  126. } else {
  127. mutex->lock_thread = -1;
  128. }
  129. return mutex;
  130. }
  131. /**
  132. * Creates a mutex
  133. * @param initial_locked Specifies if the mutex should be locked initially
  134. * @param name Optional name of mutex
  135. * @return Handle to newly created object
  136. */
  137. Handle CreateMutex(bool initial_locked, std::string name) {
  138. Handle handle;
  139. Mutex* mutex = CreateMutex(handle, initial_locked, name);
  140. return handle;
  141. }
  142. } // namespace