summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
new file mode 100644
index 000000000..019efbc78
--- /dev/null
+++ b/src/core/hle/kernel/mutex.cpp
@@ -0,0 +1,132 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <map>
6#include <vector>
7
8#include "common/common.h"
9
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h"
12
13namespace Kernel {
14
15class Mutex : public Object {
16public:
17 const char* GetTypeName() { return "Mutex"; }
18
19 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
20 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
21
22 bool initial_locked; ///< Initial lock state when mutex was created
23 bool locked; ///< Current locked state
24 Handle lock_thread; ///< Handle to thread that currently has mutex
25 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
26};
27
28////////////////////////////////////////////////////////////////////////////////////////////////////
29
30typedef std::multimap<Handle, Handle> MutexMap;
31static MutexMap g_mutex_held_locks;
32
33void MutexAcquireLock(Mutex* mutex, Handle thread) {
34 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
35 mutex->lock_thread = thread;
36}
37
38void MutexAcquireLock(Mutex* mutex) {
39 Handle thread = GetCurrentThreadHandle();
40 MutexAcquireLock(mutex, thread);
41}
42
43void MutexEraseLock(Mutex* mutex) {
44 Handle handle = mutex->GetHandle();
45 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
46 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
47 if ((*iter).second == handle) {
48 g_mutex_held_locks.erase(iter);
49 break;
50 }
51 }
52 mutex->lock_thread = -1;
53}
54
55bool LockMutex(Mutex* mutex) {
56 // Mutex alread locked?
57 if (mutex->locked) {
58 return false;
59 }
60 MutexAcquireLock(mutex);
61 return true;
62}
63
64bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
65 MutexAcquireLock(mutex, thread);
66 Kernel::ResumeThreadFromWait(thread);
67 return true;
68}
69
70bool ReleaseMutex(Mutex* mutex) {
71 MutexEraseLock(mutex);
72 bool woke_threads = false;
73 auto iter = mutex->waiting_threads.begin();
74
75 // Find the next waiting thread for the mutex...
76 while (!woke_threads && !mutex->waiting_threads.empty()) {
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/**
89 * Releases a mutex
90 * @param handle Handle to mutex to release
91 */
92Result ReleaseMutex(Handle handle) {
93 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
94 if (!ReleaseMutex(mutex)) {
95 return -1;
96 }
97 return 0;
98}
99
100/**
101 * Creates a mutex
102 * @param handle Reference to handle for the newly created mutex
103 * @param initial_locked Specifies if the mutex should be locked initially
104 */
105Mutex* CreateMutex(Handle& handle, bool initial_locked) {
106 Mutex* mutex = new Mutex;
107 handle = Kernel::g_object_pool.Create(mutex);
108
109 mutex->locked = mutex->initial_locked = initial_locked;
110
111 // Acquire mutex with current thread if initialized as locked...
112 if (mutex->locked) {
113 MutexAcquireLock(mutex);
114
115 // Otherwise, reset lock thread handle
116 } else {
117 mutex->lock_thread = -1;
118 }
119 return mutex;
120}
121
122/**
123 * Creates a mutex
124 * @param initial_locked Specifies if the mutex should be locked initially
125 */
126Handle CreateMutex(bool initial_locked) {
127 Handle handle;
128 Mutex* mutex = CreateMutex(handle, initial_locked);
129 return handle;
130}
131
132} // namespace