mutex.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. ResultVal<bool> SyncRequest() override {
  23. // TODO(bunnei): ImplementMe
  24. locked = true;
  25. return MakeResult<bool>(false);
  26. }
  27. ResultVal<bool> WaitSynchronization() override {
  28. // TODO(bunnei): ImplementMe
  29. bool wait = locked;
  30. if (locked) {
  31. Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
  32. }
  33. return MakeResult<bool>(wait);
  34. }
  35. };
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////
  37. typedef std::multimap<Handle, Handle> MutexMap;
  38. static MutexMap g_mutex_held_locks;
  39. void MutexAcquireLock(Mutex* mutex, Handle thread) {
  40. g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
  41. mutex->lock_thread = thread;
  42. }
  43. void MutexAcquireLock(Mutex* mutex) {
  44. Handle thread = GetCurrentThreadHandle();
  45. MutexAcquireLock(mutex, thread);
  46. }
  47. void MutexEraseLock(Mutex* mutex) {
  48. Handle handle = mutex->GetHandle();
  49. auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
  50. for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
  51. if ((*iter).second == handle) {
  52. g_mutex_held_locks.erase(iter);
  53. break;
  54. }
  55. }
  56. mutex->lock_thread = -1;
  57. }
  58. bool LockMutex(Mutex* mutex) {
  59. // Mutex alread locked?
  60. if (mutex->locked) {
  61. return false;
  62. }
  63. MutexAcquireLock(mutex);
  64. return true;
  65. }
  66. bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
  67. MutexAcquireLock(mutex, thread);
  68. Kernel::ResumeThreadFromWait(thread);
  69. return true;
  70. }
  71. bool ReleaseMutex(Mutex* mutex) {
  72. MutexEraseLock(mutex);
  73. bool woke_threads = false;
  74. // Find the next waiting thread for the mutex...
  75. while (!woke_threads && !mutex->waiting_threads.empty()) {
  76. std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
  77. woke_threads |= ReleaseMutexForThread(mutex, *iter);
  78. mutex->waiting_threads.erase(iter);
  79. }
  80. // Reset mutex lock thread handle, nothing is waiting
  81. if (!woke_threads) {
  82. mutex->locked = false;
  83. mutex->lock_thread = -1;
  84. }
  85. return woke_threads;
  86. }
  87. /**
  88. * Releases a mutex
  89. * @param handle Handle to mutex to release
  90. */
  91. ResultCode ReleaseMutex(Handle handle) {
  92. Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
  93. if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
  94. if (!ReleaseMutex(mutex)) {
  95. // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
  96. // what error condition this is supposed to be signaling.
  97. return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
  98. ErrorSummary::NothingHappened, ErrorLevel::Temporary);
  99. }
  100. return RESULT_SUCCESS;
  101. }
  102. /**
  103. * Creates a mutex
  104. * @param handle Reference to handle for the newly created mutex
  105. * @param initial_locked Specifies if the mutex should be locked initially
  106. * @param name Optional name of mutex
  107. * @return Pointer to new Mutex object
  108. */
  109. Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
  110. Mutex* mutex = new Mutex;
  111. handle = Kernel::g_object_pool.Create(mutex);
  112. mutex->locked = mutex->initial_locked = initial_locked;
  113. mutex->name = name;
  114. // Acquire mutex with current thread if initialized as locked...
  115. if (mutex->locked) {
  116. MutexAcquireLock(mutex);
  117. // Otherwise, reset lock thread handle
  118. } else {
  119. mutex->lock_thread = -1;
  120. }
  121. return mutex;
  122. }
  123. /**
  124. * Creates a mutex
  125. * @param initial_locked Specifies if the mutex should be locked initially
  126. * @param name Optional name of mutex
  127. * @return Handle to newly created object
  128. */
  129. Handle CreateMutex(bool initial_locked, const std::string& name) {
  130. Handle handle;
  131. Mutex* mutex = CreateMutex(handle, initial_locked, name);
  132. return handle;
  133. }
  134. } // namespace