summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
authorbunnei <ericbunnie@gmail.com>2014-05-21 05:03:45 +0200
committerbunnei <ericbunnie@gmail.com>2014-05-21 05:03:45 +0200
commit978e1d4653cd12a68d6bfa05af57edb1645da0f5 (patch)
tree75b5c4bbf272453cc9c37b381ef67e5746df0ea8 /src/core/hle
parentsvc: added some comments (diff)
downloadyuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar.gz
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar.bz2
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar.lz
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar.xz
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.tar.zst
yuzu-978e1d4653cd12a68d6bfa05af57edb1645da0f5.zip
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/mutex.cpp122
-rw-r--r--src/core/hle/kernel/mutex.h26
-rw-r--r--src/core/hle/service/apt.cpp10
-rw-r--r--src/core/hle/svc.cpp9
4 files changed, 157 insertions, 10 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
new file mode 100644
index 000000000..2b2cff4ea
--- /dev/null
+++ b/src/core/hle/kernel/mutex.cpp
@@ -0,0 +1,122 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <map>
+#include <vector>
+
+#include "common/common.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+class Mutex : public Object {
+public:
+ const char* GetTypeName() { return "Mutex"; }
+
+ static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
+ Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
+
+ bool initial_locked; ///< Initial lock state when mutex was created
+ bool locked; ///< Current locked state
+ Handle lock_thread; ///< Handle to thread that currently has mutex
+ std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef std::multimap<Handle, Handle> MutexMap;
+static MutexMap g_mutex_held_locks;
+
+void __MutexAcquireLock(Mutex* mutex, Handle thread) {
+ g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
+ mutex->lock_thread = thread;
+}
+
+void __MutexAcquireLock(Mutex* mutex) {
+ Handle thread = GetCurrentThread();
+ __MutexAcquireLock(mutex, thread);
+}
+
+void __MutexEraseLock(Mutex* mutex) {
+ Handle handle = mutex->GetHandle();
+ auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
+ for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
+ if ((*iter).second == handle) {
+ g_mutex_held_locks.erase(iter);
+ break;
+ }
+ }
+ mutex->lock_thread = -1;
+}
+
+bool __LockMutex(Mutex* mutex) {
+ // Mutex alread locked?
+ if (mutex->locked) {
+ return false;
+ }
+ __MutexAcquireLock(mutex);
+ return true;
+}
+
+bool __ReleaseMutexForThread(Mutex* mutex, Handle thread) {
+ __MutexAcquireLock(mutex, thread);
+ Kernel::ResumeThreadFromWait(thread);
+ return true;
+}
+
+bool __ReleaseMutex(Mutex* mutex) {
+ __MutexEraseLock(mutex);
+ bool woke_threads = false;
+ auto iter = mutex->waiting_threads.begin();
+
+ // Find the next waiting thread for the mutex...
+ while (!woke_threads && !mutex->waiting_threads.empty()) {
+ woke_threads |= __ReleaseMutexForThread(mutex, *iter);
+ mutex->waiting_threads.erase(iter);
+ }
+ // Reset mutex lock thread handle, nothing is waiting
+ if (!woke_threads) {
+ mutex->locked = false;
+ mutex->lock_thread = -1;
+ }
+ return woke_threads;
+}
+
+/**
+ * Releases a mutex
+ * @param handle Handle to mutex to release
+ */
+Result ReleaseMutex(Handle handle) {
+ Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
+ if (!__ReleaseMutex(mutex)) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Creates a mutex
+ * @param handle Reference to handle for the newly created mutex
+ * @param initial_locked Specifies if the mutex should be locked initially
+ */
+Result CreateMutex(Handle& handle, bool initial_locked) {
+ Mutex* mutex = new Mutex;
+ handle = Kernel::g_object_pool.Create(mutex);
+
+ mutex->locked = mutex->initial_locked = initial_locked;
+
+ // Acquire mutex with current thread if initialized as locked...
+ if (mutex->locked) {
+ __MutexAcquireLock(mutex);
+
+ // Otherwise, reset lock thread handle
+ } else {
+ mutex->lock_thread = -1;
+ }
+ return 0;
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
new file mode 100644
index 000000000..1f843e979
--- /dev/null
+++ b/src/core/hle/kernel/mutex.h
@@ -0,0 +1,26 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+/**
+ * Releases a mutex
+ * @param handle Handle to mutex to release
+ */
+Result ReleaseMutex(Handle handle);
+
+/**
+ * Creates a mutex
+ * @param handle Reference to handle for the newly created mutex
+ * @param initial_locked Specifies if the mutex should be locked initially
+ */
+Result CreateMutex(Handle& handle, bool initial_locked);
+
+} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index 1f6a70eab..ecec4da00 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -3,9 +3,10 @@
// Refer to the license.txt file included.
-#include "common/log.h"
+#include "common/common.h"
#include "core/hle/hle.h"
+#include "core/hle/kernel/mutex.h"
#include "core/hle/service/apt.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -19,11 +20,8 @@ void Initialize(Service::Interface* self) {
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- u32 flags = cmd_buff[1];
-
- // TODO: This should be an actual mutex handle. Games will check that this is not non-zero
- // (NULL), and fail if such. A faked non-zero value will at least enable further booting.
- cmd_buff[5] = 0x12345678;
+ u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
+ cmd_buff[1] = Kernel::CreateMutex(cmd_buff[5], false);
}
const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 3674a08c5..73ab073f5 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -187,15 +187,16 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
/// Create a mutex
Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s",
- initial_locked ? "true" : "false");
- Core::g_app_core->SetReg(1, 0xF00D0BAD);
+ DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s", initial_locked ? "true" : "false");
+ Kernel::CreateMutex(*mutex, (bool)initial_locked);
+ Core::g_app_core->SetReg(1, *mutex);
return 0;
}
/// Release a mutex
Result ReleaseMutex(Handle handle) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle);
+ DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle);
+ Kernel::ReleaseMutex(handle);
return 0;
}