summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar David Marcec2018-04-26 14:28:54 -0700
committerGravatar David Marcec2018-04-26 14:28:54 -0700
commit7391741a204d6f25a06132eda214b2199b60a084 (patch)
treeaeeb723744c4563ad608361b82dd938b062a3e09 /src/core/hle/kernel
parentAdded PREPO to logging backend, Removed comments from SaveReportWithUser (diff)
parentMerge pull request #403 from lioncash/common (diff)
downloadyuzu-7391741a204d6f25a06132eda214b2199b60a084.tar.gz
yuzu-7391741a204d6f25a06132eda214b2199b60a084.tar.xz
yuzu-7391741a204d6f25a06132eda214b2199b60a084.zip
Merge branch 'master' of https://github.com/yuzu-emu/yuzu into service-impl
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/condition_variable.cpp64
-rw-r--r--src/core/hle/kernel/condition_variable.h63
-rw-r--r--src/core/hle/kernel/errors.h1
-rw-r--r--src/core/hle/kernel/handle_table.cpp4
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp5
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/mutex.cpp179
-rw-r--r--src/core/hle/kernel/mutex.h88
-rw-r--r--src/core/hle/kernel/process.cpp8
-rw-r--r--src/core/hle/kernel/resource_limit.cpp6
-rw-r--r--src/core/hle/kernel/scheduler.cpp6
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/shared_memory.cpp17
-rw-r--r--src/core/hle/kernel/svc.cpp296
-rw-r--r--src/core/hle/kernel/thread.cpp81
-rw-r--r--src/core/hle/kernel/thread.h36
-rw-r--r--src/core/hle/kernel/timer.cpp4
-rw-r--r--src/core/hle/kernel/vm_manager.cpp8
18 files changed, 336 insertions, 540 deletions
diff --git a/src/core/hle/kernel/condition_variable.cpp b/src/core/hle/kernel/condition_variable.cpp
deleted file mode 100644
index a786d7f74..000000000
--- a/src/core/hle/kernel/condition_variable.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/condition_variable.h"
7#include "core/hle/kernel/errors.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/object_address_table.h"
10#include "core/hle/kernel/thread.h"
11
12namespace Kernel {
13
14ConditionVariable::ConditionVariable() {}
15ConditionVariable::~ConditionVariable() {}
16
17ResultVal<SharedPtr<ConditionVariable>> ConditionVariable::Create(VAddr guest_addr,
18 std::string name) {
19 SharedPtr<ConditionVariable> condition_variable(new ConditionVariable);
20
21 condition_variable->name = std::move(name);
22 condition_variable->guest_addr = guest_addr;
23 condition_variable->mutex_addr = 0;
24
25 // Condition variables are referenced by guest address, so track this in the kernel
26 g_object_address_table.Insert(guest_addr, condition_variable);
27
28 return MakeResult<SharedPtr<ConditionVariable>>(std::move(condition_variable));
29}
30
31bool ConditionVariable::ShouldWait(Thread* thread) const {
32 return GetAvailableCount() <= 0;
33}
34
35void ConditionVariable::Acquire(Thread* thread) {
36 if (GetAvailableCount() <= 0)
37 return;
38
39 SetAvailableCount(GetAvailableCount() - 1);
40}
41
42ResultCode ConditionVariable::Release(s32 target) {
43 if (target == -1) {
44 // When -1, wake up all waiting threads
45 SetAvailableCount(static_cast<s32>(GetWaitingThreads().size()));
46 WakeupAllWaitingThreads();
47 } else {
48 // Otherwise, wake up just a single thread
49 SetAvailableCount(target);
50 WakeupWaitingThread(GetHighestPriorityReadyThread());
51 }
52
53 return RESULT_SUCCESS;
54}
55
56s32 ConditionVariable::GetAvailableCount() const {
57 return Memory::Read32(guest_addr);
58}
59
60void ConditionVariable::SetAvailableCount(s32 value) const {
61 Memory::Write32(guest_addr, value);
62}
63
64} // namespace Kernel
diff --git a/src/core/hle/kernel/condition_variable.h b/src/core/hle/kernel/condition_variable.h
deleted file mode 100644
index 1c9f06769..000000000
--- a/src/core/hle/kernel/condition_variable.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include <queue>
9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/wait_object.h"
12#include "core/hle/result.h"
13
14namespace Kernel {
15
16class ConditionVariable final : public WaitObject {
17public:
18 /**
19 * Creates a condition variable.
20 * @param guest_addr Address of the object tracking the condition variable in guest memory. If
21 * specified, this condition variable will update the guest object when its state changes.
22 * @param name Optional name of condition variable.
23 * @return The created condition variable.
24 */
25 static ResultVal<SharedPtr<ConditionVariable>> Create(VAddr guest_addr,
26 std::string name = "Unknown");
27
28 std::string GetTypeName() const override {
29 return "ConditionVariable";
30 }
31 std::string GetName() const override {
32 return name;
33 }
34
35 static const HandleType HANDLE_TYPE = HandleType::ConditionVariable;
36 HandleType GetHandleType() const override {
37 return HANDLE_TYPE;
38 }
39
40 s32 GetAvailableCount() const;
41 void SetAvailableCount(s32 value) const;
42
43 std::string name; ///< Name of condition variable (optional)
44 VAddr guest_addr; ///< Address of the guest condition variable value
45 VAddr mutex_addr; ///< (optional) Address of guest mutex value associated with this condition
46 ///< variable, used for implementing events
47
48 bool ShouldWait(Thread* thread) const override;
49 void Acquire(Thread* thread) override;
50
51 /**
52 * Releases a slot from a condition variable.
53 * @param target The number of threads to wakeup, -1 is all.
54 * @return ResultCode indicating if the operation succeeded.
55 */
56 ResultCode Release(s32 target);
57
58private:
59 ConditionVariable();
60 ~ConditionVariable() override;
61};
62
63} // namespace Kernel
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 29d8dfdaa..5be20c878 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -20,6 +20,7 @@ enum {
20 MaxConnectionsReached = 52, 20 MaxConnectionsReached = 52,
21 21
22 // Confirmed Switch OS error codes 22 // Confirmed Switch OS error codes
23 MisalignedAddress = 102,
23 InvalidHandle = 114, 24 InvalidHandle = 114,
24 Timeout = 117, 25 Timeout = 117,
25 SynchronizationCanceled = 118, 26 SynchronizationCanceled = 118,
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 822449cd5..f7a9920d8 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -26,7 +26,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
26 26
27 u16 slot = next_free_slot; 27 u16 slot = next_free_slot;
28 if (slot >= generations.size()) { 28 if (slot >= generations.size()) {
29 LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); 29 NGLOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
30 return ERR_OUT_OF_HANDLES; 30 return ERR_OUT_OF_HANDLES;
31 } 31 }
32 next_free_slot = generations[slot]; 32 next_free_slot = generations[slot];
@@ -48,7 +48,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
48ResultVal<Handle> HandleTable::Duplicate(Handle handle) { 48ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
49 SharedPtr<Object> object = GetGeneric(handle); 49 SharedPtr<Object> object = GetGeneric(handle);
50 if (object == nullptr) { 50 if (object == nullptr) {
51 LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); 51 NGLOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
52 return ERR_INVALID_HANDLE; 52 return ERR_INVALID_HANDLE;
53 } 53 }
54 return Create(std::move(object)); 54 return Create(std::move(object));
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index bef4f15f5..aa6ca1026 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -118,7 +118,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
118 std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); 118 std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>());
119 } else { 119 } else {
120 if (Session()->IsDomain()) 120 if (Session()->IsDomain())
121 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); 121 NGLOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
122 } 122 }
123 } 123 }
124 124
@@ -270,7 +270,8 @@ size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const {
270 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()}; 270 const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()};
271 const size_t buffer_size{GetWriteBufferSize()}; 271 const size_t buffer_size{GetWriteBufferSize()};
272 if (size > buffer_size) { 272 if (size > buffer_size) {
273 LOG_CRITICAL(Core, "size (%016zx) is greater than buffer_size (%016zx)", size, buffer_size); 273 NGLOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size,
274 buffer_size);
274 size = buffer_size; // TODO(bunnei): This needs to be HW tested 275 size = buffer_size; // TODO(bunnei): This needs to be HW tested
275 } 276 }
276 277
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 053bf4e17..402ae900f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -18,12 +18,10 @@ using Handle = u32;
18enum class HandleType : u32 { 18enum class HandleType : u32 {
19 Unknown, 19 Unknown,
20 Event, 20 Event,
21 Mutex,
22 SharedMemory, 21 SharedMemory,
23 Thread, 22 Thread,
24 Process, 23 Process,
25 AddressArbiter, 24 AddressArbiter,
26 ConditionVariable,
27 Timer, 25 Timer,
28 ResourceLimit, 26 ResourceLimit,
29 CodeSet, 27 CodeSet,
@@ -63,9 +61,7 @@ public:
63 bool IsWaitable() const { 61 bool IsWaitable() const {
64 switch (GetHandleType()) { 62 switch (GetHandleType()) {
65 case HandleType::Event: 63 case HandleType::Event:
66 case HandleType::Mutex:
67 case HandleType::Thread: 64 case HandleType::Thread:
68 case HandleType::ConditionVariable:
69 case HandleType::Timer: 65 case HandleType::Timer:
70 case HandleType::ServerPort: 66 case HandleType::ServerPort:
71 case HandleType::ServerSession: 67 case HandleType::ServerSession:
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 0b9dc700c..63733ad79 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -7,6 +7,7 @@
7#include <boost/range/algorithm_ext/erase.hpp> 7#include <boost/range/algorithm_ext/erase.hpp>
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/handle_table.h" 11#include "core/hle/kernel/handle_table.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/mutex.h" 13#include "core/hle/kernel/mutex.h"
@@ -15,124 +16,120 @@
15 16
16namespace Kernel { 17namespace Kernel {
17 18
18void ReleaseThreadMutexes(Thread* thread) { 19/// Returns the number of threads that are waiting for a mutex, and the highest priority one among
19 for (auto& mtx : thread->held_mutexes) { 20/// those.
20 mtx->SetHasWaiters(false); 21static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread(
21 mtx->SetHoldingThread(nullptr); 22 SharedPtr<Thread> current_thread, VAddr mutex_addr) {
22 mtx->WakeupAllWaitingThreads();
23 }
24 thread->held_mutexes.clear();
25}
26 23
27Mutex::Mutex() {} 24 SharedPtr<Thread> highest_priority_thread;
28Mutex::~Mutex() {} 25 u32 num_waiters = 0;
29 26
30SharedPtr<Mutex> Mutex::Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr, 27 for (auto& thread : current_thread->wait_mutex_threads) {
31 std::string name) { 28 if (thread->mutex_wait_address != mutex_addr)
32 SharedPtr<Mutex> mutex(new Mutex); 29 continue;
33 30
34 mutex->guest_addr = guest_addr; 31 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
35 mutex->name = std::move(name);
36 32
37 // If mutex was initialized with a holding thread, acquire it by the holding thread 33 ++num_waiters;
38 if (holding_thread) { 34 if (highest_priority_thread == nullptr ||
39 mutex->Acquire(holding_thread.get()); 35 thread->GetPriority() < highest_priority_thread->GetPriority()) {
36 highest_priority_thread = thread;
37 }
40 } 38 }
41 39
42 // Mutexes are referenced by guest address, so track this in the kernel 40 return {highest_priority_thread, num_waiters};
43 g_object_address_table.Insert(guest_addr, mutex);
44
45 return mutex;
46} 41}
47 42
48bool Mutex::ShouldWait(Thread* thread) const { 43/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner.
49 auto holding_thread = GetHoldingThread(); 44static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread,
50 return holding_thread != nullptr && thread != holding_thread; 45 SharedPtr<Thread> new_owner) {
46 auto threads = current_thread->wait_mutex_threads;
47 for (auto& thread : threads) {
48 if (thread->mutex_wait_address != mutex_addr)
49 continue;
50
51 ASSERT(thread->lock_owner == current_thread);
52 current_thread->RemoveMutexWaiter(thread);
53 if (new_owner != thread)
54 new_owner->AddMutexWaiter(thread);
55 }
51} 56}
52 57
53void Mutex::Acquire(Thread* thread) { 58ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
54 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 59 Handle requesting_thread_handle) {
60 // The mutex address must be 4-byte aligned
61 if ((address % sizeof(u32)) != 0) {
62 return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
63 }
55 64
56 priority = thread->current_priority; 65 SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
57 thread->held_mutexes.insert(this); 66 SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle);
58 SetHoldingThread(thread);
59 thread->UpdatePriority();
60 Core::System::GetInstance().PrepareReschedule();
61}
62 67
63ResultCode Mutex::Release(Thread* thread) { 68 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
64 auto holding_thread = GetHoldingThread(); 69 // thread.
65 ASSERT(holding_thread); 70 ASSERT(requesting_thread == GetCurrentThread());
66 71
67 // We can only release the mutex if it's held by the calling thread. 72 u32 addr_value = Memory::Read32(address);
68 ASSERT(thread == holding_thread); 73
74 // If the mutex isn't being held, just return success.
75 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
76 return RESULT_SUCCESS;
77 }
78
79 if (holding_thread == nullptr)
80 return ERR_INVALID_HANDLE;
81
82 // Wait until the mutex is released
83 GetCurrentThread()->mutex_wait_address = address;
84 GetCurrentThread()->wait_handle = requesting_thread_handle;
85
86 GetCurrentThread()->status = THREADSTATUS_WAIT_MUTEX;
87 GetCurrentThread()->wakeup_callback = nullptr;
88
89 // Update the lock holder thread's priority to prevent priority inversion.
90 holding_thread->AddMutexWaiter(GetCurrentThread());
69 91
70 holding_thread->held_mutexes.erase(this);
71 holding_thread->UpdatePriority();
72 SetHoldingThread(nullptr);
73 SetHasWaiters(!GetWaitingThreads().empty());
74 WakeupAllWaitingThreads();
75 Core::System::GetInstance().PrepareReschedule(); 92 Core::System::GetInstance().PrepareReschedule();
76 93
77 return RESULT_SUCCESS; 94 return RESULT_SUCCESS;
78} 95}
79 96
80void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { 97ResultCode Mutex::Release(VAddr address) {
81 WaitObject::AddWaitingThread(thread); 98 // The mutex address must be 4-byte aligned
82 thread->pending_mutexes.insert(this); 99 if ((address % sizeof(u32)) != 0) {
83 SetHasWaiters(true); 100 return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
84 UpdatePriority(); 101 }
85}
86
87void Mutex::RemoveWaitingThread(Thread* thread) {
88 WaitObject::RemoveWaitingThread(thread);
89 thread->pending_mutexes.erase(this);
90 if (!GetHasWaiters())
91 SetHasWaiters(!GetWaitingThreads().empty());
92 UpdatePriority();
93}
94 102
95void Mutex::UpdatePriority() { 103 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
96 if (!GetHoldingThread())
97 return;
98 104
99 u32 best_priority = THREADPRIO_LOWEST; 105 // There are no more threads waiting for the mutex, release it completely.
100 for (auto& waiter : GetWaitingThreads()) { 106 if (thread == nullptr) {
101 if (waiter->current_priority < best_priority) 107 ASSERT(GetCurrentThread()->wait_mutex_threads.empty());
102 best_priority = waiter->current_priority; 108 Memory::Write32(address, 0);
109 return RESULT_SUCCESS;
103 } 110 }
104 111
105 if (best_priority != priority) { 112 // Transfer the ownership of the mutex from the previous owner to the new one.
106 priority = best_priority; 113 TransferMutexOwnership(address, GetCurrentThread(), thread);
107 GetHoldingThread()->UpdatePriority();
108 }
109}
110 114
111Handle Mutex::GetOwnerHandle() const { 115 u32 mutex_value = thread->wait_handle;
112 GuestState guest_state{Memory::Read32(guest_addr)};
113 return guest_state.holding_thread_handle;
114}
115 116
116SharedPtr<Thread> Mutex::GetHoldingThread() const { 117 if (num_waiters >= 2) {
117 GuestState guest_state{Memory::Read32(guest_addr)}; 118 // Notify the guest that there are still some threads waiting for the mutex
118 return g_handle_table.Get<Thread>(guest_state.holding_thread_handle); 119 mutex_value |= Mutex::MutexHasWaitersFlag;
119} 120 }
120 121
121void Mutex::SetHoldingThread(SharedPtr<Thread> thread) { 122 // Grant the mutex to the next waiting thread and resume it.
122 GuestState guest_state{Memory::Read32(guest_addr)}; 123 Memory::Write32(address, mutex_value);
123 guest_state.holding_thread_handle.Assign(thread ? thread->guest_handle : 0);
124 Memory::Write32(guest_addr, guest_state.raw);
125}
126 124
127bool Mutex::GetHasWaiters() const { 125 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
128 GuestState guest_state{Memory::Read32(guest_addr)}; 126 thread->ResumeFromWait();
129 return guest_state.has_waiters != 0;
130}
131 127
132void Mutex::SetHasWaiters(bool has_waiters) { 128 thread->lock_owner = nullptr;
133 GuestState guest_state{Memory::Read32(guest_addr)}; 129 thread->condvar_wait_address = 0;
134 guest_state.has_waiters.Assign(has_waiters ? 1 : 0); 130 thread->mutex_wait_address = 0;
135 Memory::Write32(guest_addr, guest_state.raw); 131 thread->wait_handle = 0;
136}
137 132
133 return RESULT_SUCCESS;
134}
138} // namespace Kernel 135} // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 38db21005..3117e7c70 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -15,87 +15,23 @@ namespace Kernel {
15 15
16class Thread; 16class Thread;
17 17
18class Mutex final : public WaitObject { 18class Mutex final {
19public: 19public:
20 /** 20 /// Flag that indicates that a mutex still has threads waiting for it.
21 * Creates a mutex. 21 static constexpr u32 MutexHasWaitersFlag = 0x40000000;
22 * @param holding_thread Specifies a thread already holding the mutex. If not nullptr, this 22 /// Mask of the bits in a mutex address value that contain the mutex owner.
23 * thread will acquire the mutex. 23 static constexpr u32 MutexOwnerMask = 0xBFFFFFFF;
24 * @param guest_addr Address of the object tracking the mutex in guest memory. If specified,
25 * this mutex will update the guest object when its state changes.
26 * @param name Optional name of mutex
27 * @return Pointer to new Mutex object
28 */
29 static SharedPtr<Mutex> Create(SharedPtr<Kernel::Thread> holding_thread, VAddr guest_addr = 0,
30 std::string name = "Unknown");
31 24
32 std::string GetTypeName() const override { 25 /// Attempts to acquire a mutex at the specified address.
33 return "Mutex"; 26 static ResultCode TryAcquire(VAddr address, Handle holding_thread_handle,
34 } 27 Handle requesting_thread_handle);
35 std::string GetName() const override {
36 return name;
37 }
38 28
39 static const HandleType HANDLE_TYPE = HandleType::Mutex; 29 /// Releases the mutex at the specified address.
40 HandleType GetHandleType() const override { 30 static ResultCode Release(VAddr address);
41 return HANDLE_TYPE;
42 }
43
44 u32 priority; ///< The priority of the mutex, used for priority inheritance.
45 std::string name; ///< Name of mutex (optional)
46 VAddr guest_addr; ///< Address of the guest mutex value
47
48 /**
49 * Elevate the mutex priority to the best priority
50 * among the priorities of all its waiting threads.
51 */
52 void UpdatePriority();
53
54 bool ShouldWait(Thread* thread) const override;
55 void Acquire(Thread* thread) override;
56
57 void AddWaitingThread(SharedPtr<Thread> thread) override;
58 void RemoveWaitingThread(Thread* thread) override;
59
60 /**
61 * Attempts to release the mutex from the specified thread.
62 * @param thread Thread that wants to release the mutex.
63 * @returns The result code of the operation.
64 */
65 ResultCode Release(Thread* thread);
66
67 /// Gets the handle to the holding process stored in the guest state.
68 Handle GetOwnerHandle() const;
69
70 /// Gets the Thread pointed to by the owner handle
71 SharedPtr<Thread> GetHoldingThread() const;
72 /// Sets the holding process handle in the guest state.
73 void SetHoldingThread(SharedPtr<Thread> thread);
74
75 /// Returns the has_waiters bit in the guest state.
76 bool GetHasWaiters() const;
77 /// Sets the has_waiters bit in the guest state.
78 void SetHasWaiters(bool has_waiters);
79 31
80private: 32private:
81 Mutex(); 33 Mutex() = default;
82 ~Mutex() override; 34 ~Mutex() = default;
83
84 /// Object in guest memory used to track the mutex state
85 union GuestState {
86 u32_le raw;
87 /// Handle of the thread that currently holds the mutex, 0 if available
88 BitField<0, 30, u32_le> holding_thread_handle;
89 /// 1 when there are threads waiting for this mutex, otherwise 0
90 BitField<30, 1, u32_le> has_waiters;
91 };
92 static_assert(sizeof(GuestState) == 4, "GuestState size is incorrect");
93}; 35};
94 36
95/**
96 * Releases all the mutexes held by the specified thread
97 * @param thread Thread that is holding the mutexes
98 */
99void ReleaseThreadMutexes(Thread* thread);
100
101} // namespace Kernel 37} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 2cffec198..751a0524d 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -54,7 +54,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
54 continue; 54 continue;
55 } else if ((type & 0xF00) == 0xE00) { // 0x0FFF 55 } else if ((type & 0xF00) == 0xE00) { // 0x0FFF
56 // Allowed interrupts list 56 // Allowed interrupts list
57 LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored"); 57 NGLOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
58 } else if ((type & 0xF80) == 0xF00) { // 0x07FF 58 } else if ((type & 0xF80) == 0xF00) { // 0x07FF
59 // Allowed syscalls mask 59 // Allowed syscalls mask
60 unsigned int index = ((descriptor >> 24) & 7) * 24; 60 unsigned int index = ((descriptor >> 24) & 7) * 24;
@@ -74,7 +74,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
74 } else if ((type & 0xFFE) == 0xFF8) { // 0x001F 74 } else if ((type & 0xFFE) == 0xFF8) { // 0x001F
75 // Mapped memory range 75 // Mapped memory range
76 if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { 76 if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
77 LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); 77 NGLOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
78 continue; 78 continue;
79 } 79 }
80 u32 end_desc = kernel_caps[i + 1]; 80 u32 end_desc = kernel_caps[i + 1];
@@ -109,9 +109,9 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
109 109
110 int minor = kernel_version & 0xFF; 110 int minor = kernel_version & 0xFF;
111 int major = (kernel_version >> 8) & 0xFF; 111 int major = (kernel_version >> 8) & 0xFF;
112 LOG_INFO(Loader, "ExHeader kernel version: %d.%d", major, minor); 112 NGLOG_INFO(Loader, "ExHeader kernel version: {}.{}", major, minor);
113 } else { 113 } else {
114 LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); 114 NGLOG_ERROR(Loader, "Unhandled kernel caps descriptor: {:#010X}", descriptor);
115 } 115 }
116 } 116 }
117} 117}
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 88ca8ad7e..0ef5fc57d 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -29,7 +29,7 @@ SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory cat
29 case ResourceLimitCategory::OTHER: 29 case ResourceLimitCategory::OTHER:
30 return resource_limits[static_cast<u8>(category)]; 30 return resource_limits[static_cast<u8>(category)];
31 default: 31 default:
32 LOG_CRITICAL(Kernel, "Unknown resource limit category"); 32 NGLOG_CRITICAL(Kernel, "Unknown resource limit category");
33 UNREACHABLE(); 33 UNREACHABLE();
34 } 34 }
35} 35}
@@ -55,7 +55,7 @@ s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
55 case ResourceType::CPUTime: 55 case ResourceType::CPUTime:
56 return current_cpu_time; 56 return current_cpu_time;
57 default: 57 default:
58 LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource)); 58 NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
59 UNIMPLEMENTED(); 59 UNIMPLEMENTED();
60 return 0; 60 return 0;
61 } 61 }
@@ -84,7 +84,7 @@ u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
84 case ResourceType::CPUTime: 84 case ResourceType::CPUTime:
85 return max_cpu_time; 85 return max_cpu_time;
86 default: 86 default:
87 LOG_ERROR(Kernel, "Unknown resource type=%08X", static_cast<u32>(resource)); 87 NGLOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
88 UNIMPLEMENTED(); 88 UNIMPLEMENTED();
89 return 0; 89 return 0;
90 } 90 }
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 921f27efb..ff6a0941a 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -94,11 +94,11 @@ void Scheduler::Reschedule() {
94 Thread* next = PopNextReadyThread(); 94 Thread* next = PopNextReadyThread();
95 95
96 if (cur && next) { 96 if (cur && next) {
97 LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); 97 NGLOG_TRACE(Kernel, "context switch {} -> {}", cur->GetObjectId(), next->GetObjectId());
98 } else if (cur) { 98 } else if (cur) {
99 LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); 99 NGLOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId());
100 } else if (next) { 100 } else if (next) {
101 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); 101 NGLOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId());
102 } 102 }
103 103
104 SwitchContext(next); 104 SwitchContext(next);
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 33397d84f..b1f8e771c 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -68,7 +68,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
68 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); 68 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
69 69
70 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { 70 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
71 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); 71 NGLOG_DEBUG(IPC, "CloseVirtualHandle, object_id={:#010X}", object_id);
72 72
73 domain_request_handlers[object_id - 1] = nullptr; 73 domain_request_handlers[object_id - 1] = nullptr;
74 74
@@ -78,8 +78,8 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
78 } 78 }
79 } 79 }
80 80
81 LOG_CRITICAL(IPC, "Unknown domain command=%d", 81 NGLOG_CRITICAL(IPC, "Unknown domain command={}",
82 static_cast<int>(domain_message_header->command.Value())); 82 static_cast<int>(domain_message_header->command.Value()));
83 ASSERT(false); 83 ASSERT(false);
84 } 84 }
85 85
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index bc99993c8..f0b65c73d 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -107,16 +107,16 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
107 107
108 // Error out if the requested permissions don't match what the creator process allows. 108 // Error out if the requested permissions don't match what the creator process allows.
109 if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { 109 if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
110 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%lx name=%s, permissions don't match", 110 NGLOG_ERROR(Kernel, "cannot map id={}, address={:#X} name={}, permissions don't match",
111 GetObjectId(), address, name.c_str()); 111 GetObjectId(), address, name);
112 return ERR_INVALID_COMBINATION; 112 return ERR_INVALID_COMBINATION;
113 } 113 }
114 114
115 // Error out if the provided permissions are not compatible with what the creator process needs. 115 // Error out if the provided permissions are not compatible with what the creator process needs.
116 if (other_permissions != MemoryPermission::DontCare && 116 if (other_permissions != MemoryPermission::DontCare &&
117 static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { 117 static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
118 LOG_ERROR(Kernel, "cannot map id=%u, address=0x%lx name=%s, permissions don't match", 118 NGLOG_ERROR(Kernel, "cannot map id={}, address={:#X} name={}, permissions don't match",
119 GetObjectId(), address, name.c_str()); 119 GetObjectId(), address, name);
120 return ERR_WRONG_PERMISSION; 120 return ERR_WRONG_PERMISSION;
121 } 121 }
122 122
@@ -131,9 +131,10 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
131 auto result = target_process->vm_manager.MapMemoryBlock( 131 auto result = target_process->vm_manager.MapMemoryBlock(
132 target_address, backing_block, backing_block_offset, size, MemoryState::Shared); 132 target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
133 if (result.Failed()) { 133 if (result.Failed()) {
134 LOG_ERROR(Kernel, 134 NGLOG_ERROR(
135 "cannot map id=%u, target_address=0x%lx name=%s, error mapping to virtual memory", 135 Kernel,
136 GetObjectId(), target_address, name.c_str()); 136 "cannot map id={}, target_address={:#X} name={}, error mapping to virtual memory",
137 GetObjectId(), target_address, name);
137 return result.Code(); 138 return result.Code();
138 } 139 }
139 140
@@ -151,7 +152,7 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
151 u32 masked_permissions = 152 u32 masked_permissions =
152 static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); 153 static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
153 return static_cast<VMAPermission>(masked_permissions); 154 return static_cast<VMAPermission>(masked_permissions);
154}; 155}
155 156
156u8* SharedMemory::GetPointer(u32 offset) { 157u8* SharedMemory::GetPointer(u32 offset) {
157 return backing_block->data() + backing_block_offset + offset; 158 return backing_block->data() + backing_block_offset + offset;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 633740992..cb19b1a69 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -13,7 +13,6 @@
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/hle/kernel/client_port.h" 14#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 15#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/condition_variable.h"
17#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
18#include "core/hle/kernel/handle_table.h" 17#include "core/hle/kernel/handle_table.h"
19#include "core/hle/kernel/mutex.h" 18#include "core/hle/kernel/mutex.h"
@@ -32,7 +31,7 @@ namespace Kernel {
32 31
33/// Set the process heap to a given Size. It can both extend and shrink the heap. 32/// Set the process heap to a given Size. It can both extend and shrink the heap.
34static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 33static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
35 LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); 34 NGLOG_TRACE(Kernel_SVC, "called, heap_size={:#X}", heap_size);
36 auto& process = *Core::CurrentProcess(); 35 auto& process = *Core::CurrentProcess();
37 CASCADE_RESULT(*heap_addr, 36 CASCADE_RESULT(*heap_addr,
38 process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); 37 process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
@@ -40,21 +39,21 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
40} 39}
41 40
42static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { 41static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
43 LOG_WARNING(Kernel_SVC, "(STUBBED) called, addr=0x%lx", addr); 42 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, addr={:#X}", addr);
44 return RESULT_SUCCESS; 43 return RESULT_SUCCESS;
45} 44}
46 45
47/// Maps a memory range into a different range. 46/// Maps a memory range into a different range.
48static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 47static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
49 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, 48 NGLOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr={:#X}, size={:#X}", dst_addr,
50 src_addr, size); 49 src_addr, size);
51 return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); 50 return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
52} 51}
53 52
54/// Unmaps a region that was previously mapped with svcMapMemory 53/// Unmaps a region that was previously mapped with svcMapMemory
55static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 54static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
56 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, 55 NGLOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr={:#X}, size={:#X}", dst_addr,
57 src_addr, size); 56 src_addr, size);
58 return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); 57 return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
59} 58}
60 59
@@ -69,11 +68,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
69 if (port_name.size() > PortNameMaxLength) 68 if (port_name.size() > PortNameMaxLength)
70 return ERR_PORT_NAME_TOO_LONG; 69 return ERR_PORT_NAME_TOO_LONG;
71 70
72 LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name.c_str()); 71 NGLOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
73 72
74 auto it = Service::g_kernel_named_ports.find(port_name); 73 auto it = Service::g_kernel_named_ports.find(port_name);
75 if (it == Service::g_kernel_named_ports.end()) { 74 if (it == Service::g_kernel_named_ports.end()) {
76 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str()); 75 NGLOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
77 return ERR_NOT_FOUND; 76 return ERR_NOT_FOUND;
78 } 77 }
79 78
@@ -91,11 +90,11 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
91static ResultCode SendSyncRequest(Handle handle) { 90static ResultCode SendSyncRequest(Handle handle) {
92 SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle); 91 SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);
93 if (!session) { 92 if (!session) {
94 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle); 93 NGLOG_ERROR(Kernel_SVC, "called with invalid handle={:#010X}", handle);
95 return ERR_INVALID_HANDLE; 94 return ERR_INVALID_HANDLE;
96 } 95 }
97 96
98 LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); 97 NGLOG_TRACE(Kernel_SVC, "called handle={:#010X}({})", handle, session->GetName());
99 98
100 Core::System::GetInstance().PrepareReschedule(); 99 Core::System::GetInstance().PrepareReschedule();
101 100
@@ -106,7 +105,7 @@ static ResultCode SendSyncRequest(Handle handle) {
106 105
107/// Get the ID for the specified thread. 106/// Get the ID for the specified thread.
108static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { 107static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
109 LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); 108 NGLOG_TRACE(Kernel_SVC, "called thread={:#010X}", thread_handle);
110 109
111 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); 110 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
112 if (!thread) { 111 if (!thread) {
@@ -119,7 +118,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
119 118
120/// Get the ID of the specified process 119/// Get the ID of the specified process
121static ResultCode GetProcessId(u32* process_id, Handle process_handle) { 120static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
122 LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); 121 NGLOG_TRACE(Kernel_SVC, "called process={:#010X}", process_handle);
123 122
124 const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle); 123 const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle);
125 if (!process) { 124 if (!process) {
@@ -179,8 +178,8 @@ static ResultCode WaitSynchronization1(
179/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 178/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
180static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, 179static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count,
181 s64 nano_seconds) { 180 s64 nano_seconds) {
182 LOG_TRACE(Kernel_SVC, "called handles_address=0x%llx, handle_count=%d, nano_seconds=%d", 181 NGLOG_TRACE(Kernel_SVC, "called handles_address={:#X}, handle_count={}, nano_seconds={}",
183 handles_address, handle_count, nano_seconds); 182 handles_address, handle_count, nano_seconds);
184 183
185 if (!Memory::IsValidVirtualAddress(handles_address)) 184 if (!Memory::IsValidVirtualAddress(handles_address))
186 return ERR_INVALID_POINTER; 185 return ERR_INVALID_POINTER;
@@ -240,7 +239,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
240 239
241/// Resumes a thread waiting on WaitSynchronization 240/// Resumes a thread waiting on WaitSynchronization
242static ResultCode CancelSynchronization(Handle thread_handle) { 241static ResultCode CancelSynchronization(Handle thread_handle) {
243 LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); 242 NGLOG_TRACE(Kernel_SVC, "called thread={:#X}", thread_handle);
244 243
245 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); 244 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
246 if (!thread) { 245 if (!thread) {
@@ -257,56 +256,38 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
257/// Attempts to locks a mutex, creating it if it does not already exist 256/// Attempts to locks a mutex, creating it if it does not already exist
258static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, 257static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
259 Handle requesting_thread_handle) { 258 Handle requesting_thread_handle) {
260 LOG_TRACE(Kernel_SVC, 259 NGLOG_TRACE(Kernel_SVC,
261 "called holding_thread_handle=0x%08X, mutex_addr=0x%llx, " 260 "called holding_thread_handle={:#010X}, mutex_addr={:#X}, "
262 "requesting_current_thread_handle=0x%08X", 261 "requesting_current_thread_handle={:#010X}",
263 holding_thread_handle, mutex_addr, requesting_thread_handle); 262 holding_thread_handle, mutex_addr, requesting_thread_handle);
264
265 SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
266 SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle);
267
268 ASSERT(requesting_thread);
269 ASSERT(requesting_thread == GetCurrentThread());
270
271 SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr);
272 if (!mutex) {
273 // Create a new mutex for the specified address if one does not already exist
274 mutex = Mutex::Create(holding_thread, mutex_addr);
275 mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr);
276 }
277
278 ASSERT(holding_thread == mutex->GetHoldingThread());
279 263
280 return WaitSynchronization1(mutex, requesting_thread.get()); 264 return Mutex::TryAcquire(mutex_addr, holding_thread_handle, requesting_thread_handle);
281} 265}
282 266
283/// Unlock a mutex 267/// Unlock a mutex
284static ResultCode ArbitrateUnlock(VAddr mutex_addr) { 268static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
285 LOG_TRACE(Kernel_SVC, "called mutex_addr=0x%llx", mutex_addr); 269 NGLOG_TRACE(Kernel_SVC, "called mutex_addr={:#X}", mutex_addr);
286 270
287 SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr); 271 return Mutex::Release(mutex_addr);
288 ASSERT(mutex);
289
290 return mutex->Release(GetCurrentThread());
291} 272}
292 273
293/// Break program execution 274/// Break program execution
294static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { 275static void Break(u64 unk_0, u64 unk_1, u64 unk_2) {
295 LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); 276 NGLOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!");
296 ASSERT(false); 277 ASSERT(false);
297} 278}
298 279
299/// Used to output a message on a debug hardware unit - does nothing on a retail unit 280/// Used to output a message on a debug hardware unit - does nothing on a retail unit
300static void OutputDebugString(VAddr address, s32 len) { 281static void OutputDebugString(VAddr address, s32 len) {
301 std::vector<char> string(len); 282 std::string str(len, '\0');
302 Memory::ReadBlock(address, string.data(), len); 283 Memory::ReadBlock(address, str.data(), str.size());
303 LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data()); 284 NGLOG_DEBUG(Debug_Emulated, "{}", str);
304} 285}
305 286
306/// Gets system/memory information for the current process 287/// Gets system/memory information for the current process
307static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { 288static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) {
308 LOG_TRACE(Kernel_SVC, "called info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, 289 NGLOG_TRACE(Kernel_SVC, "called info_id={:#X}, info_sub_id={:#X}, handle={:#010X}", info_id,
309 info_sub_id, handle); 290 info_sub_id, handle);
310 291
311 auto& vm_manager = Core::CurrentProcess()->vm_manager; 292 auto& vm_manager = Core::CurrentProcess()->vm_manager;
312 293
@@ -357,12 +338,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
357 *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; 338 *result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
358 break; 339 break;
359 case GetInfoType::TitleId: 340 case GetInfoType::TitleId:
360 LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); 341 NGLOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0");
361 *result = 0; 342 *result = 0;
362 break; 343 break;
363 case GetInfoType::PrivilegedProcessId: 344 case GetInfoType::PrivilegedProcessId:
364 LOG_WARNING(Kernel_SVC, 345 NGLOG_WARNING(Kernel_SVC,
365 "(STUBBED) Attempted to query priviledged process id bounds, returned 0"); 346 "(STUBBED) Attempted to query privileged process id bounds, returned 0");
366 *result = 0; 347 *result = 0;
367 break; 348 break;
368 default: 349 default:
@@ -374,13 +355,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
374 355
375/// Sets the thread activity 356/// Sets the thread activity
376static ResultCode SetThreadActivity(Handle handle, u32 unknown) { 357static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
377 LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X, unknown=0x%08X", handle, unknown); 358 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, unknown={:#010X}", handle,
359 unknown);
378 return RESULT_SUCCESS; 360 return RESULT_SUCCESS;
379} 361}
380 362
381/// Gets the thread context 363/// Gets the thread context
382static ResultCode GetThreadContext(Handle handle, VAddr addr) { 364static ResultCode GetThreadContext(Handle handle, VAddr addr) {
383 LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X, addr=0x%" PRIx64, handle, addr); 365 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, addr={:#X}", handle, addr);
384 return RESULT_SUCCESS; 366 return RESULT_SUCCESS;
385} 367}
386 368
@@ -412,11 +394,6 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
412 } 394 }
413 395
414 thread->SetPriority(priority); 396 thread->SetPriority(priority);
415 thread->UpdatePriority();
416
417 // Update the mutexes that this thread is waiting for
418 for (auto& mutex : thread->pending_mutexes)
419 mutex->UpdatePriority();
420 397
421 Core::System::GetInstance().PrepareReschedule(); 398 Core::System::GetInstance().PrepareReschedule();
422 return RESULT_SUCCESS; 399 return RESULT_SUCCESS;
@@ -424,15 +401,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
424 401
425/// Get which CPU core is executing the current thread 402/// Get which CPU core is executing the current thread
426static u32 GetCurrentProcessorNumber() { 403static u32 GetCurrentProcessorNumber() {
427 LOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0"); 404 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0");
428 return 0; 405 return 0;
429} 406}
430 407
431static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, 408static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
432 u32 permissions) { 409 u32 permissions) {
433 LOG_TRACE(Kernel_SVC, 410 NGLOG_TRACE(Kernel_SVC,
434 "called, shared_memory_handle=0x%08X, addr=0x%llx, size=0x%llx, permissions=0x%08X", 411 "called, shared_memory_handle={:#X}, addr={:#X}, size={:#X}, permissions={:#010X}",
435 shared_memory_handle, addr, size, permissions); 412 shared_memory_handle, addr, size, permissions);
436 413
437 SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); 414 SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
438 if (!shared_memory) { 415 if (!shared_memory) {
@@ -452,16 +429,15 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
452 return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, 429 return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type,
453 MemoryPermission::DontCare); 430 MemoryPermission::DontCare);
454 default: 431 default:
455 LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); 432 NGLOG_ERROR(Kernel_SVC, "unknown permissions={:#010X}", permissions);
456 } 433 }
457 434
458 return RESULT_SUCCESS; 435 return RESULT_SUCCESS;
459} 436}
460 437
461static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { 438static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
462 LOG_WARNING(Kernel_SVC, 439 NGLOG_WARNING(Kernel_SVC, "called, shared_memory_handle={:#010X}, addr={:#X}, size={:#X}",
463 "called, shared_memory_handle=0x%08X, addr=0x%" PRIx64 ", size=0x%" PRIx64 "", 440 shared_memory_handle, addr, size);
464 shared_memory_handle, addr, size);
465 441
466 SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); 442 SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle);
467 443
@@ -489,19 +465,19 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
489 memory_info->type = static_cast<u32>(vma->second.meminfo_state); 465 memory_info->type = static_cast<u32>(vma->second.meminfo_state);
490 } 466 }
491 467
492 LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=%llx", process_handle, addr); 468 NGLOG_TRACE(Kernel_SVC, "called process={:#010X} addr={:X}", process_handle, addr);
493 return RESULT_SUCCESS; 469 return RESULT_SUCCESS;
494} 470}
495 471
496/// Query memory 472/// Query memory
497static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { 473static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) {
498 LOG_TRACE(Kernel_SVC, "called, addr=%llx", addr); 474 NGLOG_TRACE(Kernel_SVC, "called, addr={:X}", addr);
499 return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr); 475 return QueryProcessMemory(memory_info, page_info, CurrentProcess, addr);
500} 476}
501 477
502/// Exits the current process 478/// Exits the current process
503static void ExitProcess() { 479static void ExitProcess() {
504 LOG_INFO(Kernel_SVC, "Process %u exiting", Core::CurrentProcess()->process_id); 480 NGLOG_INFO(Kernel_SVC, "Process {} exiting", Core::CurrentProcess()->process_id);
505 481
506 ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, 482 ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running,
507 "Process has already exited"); 483 "Process has already exited");
@@ -558,9 +534,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
558 case THREADPROCESSORID_2: 534 case THREADPROCESSORID_2:
559 case THREADPROCESSORID_3: 535 case THREADPROCESSORID_3:
560 // TODO(bunnei): Implement support for other processor IDs 536 // TODO(bunnei): Implement support for other processor IDs
561 LOG_ERROR(Kernel_SVC, 537 NGLOG_ERROR(Kernel_SVC,
562 "Newly created thread must run in another thread (%u), unimplemented.", 538 "Newly created thread must run in another thread ({}), unimplemented.",
563 processor_id); 539 processor_id);
564 break; 540 break;
565 default: 541 default:
566 ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id); 542 ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
@@ -575,17 +551,17 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
575 551
576 Core::System::GetInstance().PrepareReschedule(); 552 Core::System::GetInstance().PrepareReschedule();
577 553
578 LOG_TRACE(Kernel_SVC, 554 NGLOG_TRACE(Kernel_SVC,
579 "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " 555 "called entrypoint={:#010X} ({}), arg={:#010X}, stacktop={:#010X}, "
580 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", 556 "threadpriority={:#010X}, processorid={:#010X} : created handle={:#010X}",
581 entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle); 557 entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
582 558
583 return RESULT_SUCCESS; 559 return RESULT_SUCCESS;
584} 560}
585 561
586/// Starts the thread for the provided handle 562/// Starts the thread for the provided handle
587static ResultCode StartThread(Handle thread_handle) { 563static ResultCode StartThread(Handle thread_handle) {
588 LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); 564 NGLOG_TRACE(Kernel_SVC, "called thread={:#010X}", thread_handle);
589 565
590 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); 566 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
591 if (!thread) { 567 if (!thread) {
@@ -599,7 +575,7 @@ static ResultCode StartThread(Handle thread_handle) {
599 575
600/// Called when a thread exits 576/// Called when a thread exits
601static void ExitThread() { 577static void ExitThread() {
602 LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC()); 578 NGLOG_TRACE(Kernel_SVC, "called, pc={:#010X}", Core::CPU().GetPC());
603 579
604 ExitCurrentThread(); 580 ExitCurrentThread();
605 Core::System::GetInstance().PrepareReschedule(); 581 Core::System::GetInstance().PrepareReschedule();
@@ -607,7 +583,7 @@ static void ExitThread() {
607 583
608/// Sleep the current thread 584/// Sleep the current thread
609static void SleepThread(s64 nanoseconds) { 585static void SleepThread(s64 nanoseconds) {
610 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); 586 NGLOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
611 587
612 // Don't attempt to yield execution if there are no available threads to run, 588 // Don't attempt to yield execution if there are no available threads to run,
613 // this way we avoid a useless reschedule to the idle thread. 589 // this way we avoid a useless reschedule to the idle thread.
@@ -626,111 +602,83 @@ static void SleepThread(s64 nanoseconds) {
626/// Signal process wide key atomic 602/// Signal process wide key atomic
627static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, 603static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
628 Handle thread_handle, s64 nano_seconds) { 604 Handle thread_handle, s64 nano_seconds) {
629 LOG_TRACE( 605 NGLOG_TRACE(
630 Kernel_SVC, 606 Kernel_SVC,
631 "called mutex_addr=%llx, condition_variable_addr=%llx, thread_handle=0x%08X, timeout=%d", 607 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle={:#010X}, timeout={}",
632 mutex_addr, condition_variable_addr, thread_handle, nano_seconds); 608 mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
633 609
634 SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); 610 SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
635 ASSERT(thread); 611 ASSERT(thread);
636 612
637 SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(mutex_addr); 613 CASCADE_CODE(Mutex::Release(mutex_addr));
638 if (!mutex) {
639 // Create a new mutex for the specified address if one does not already exist
640 mutex = Mutex::Create(thread, mutex_addr);
641 mutex->name = Common::StringFromFormat("mutex-%llx", mutex_addr);
642 }
643 614
644 SharedPtr<ConditionVariable> condition_variable = 615 SharedPtr<Thread> current_thread = GetCurrentThread();
645 g_object_address_table.Get<ConditionVariable>(condition_variable_addr); 616 current_thread->condvar_wait_address = condition_variable_addr;
646 if (!condition_variable) { 617 current_thread->mutex_wait_address = mutex_addr;
647 // Create a new condition_variable for the specified address if one does not already exist 618 current_thread->wait_handle = thread_handle;
648 condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap(); 619 current_thread->status = THREADSTATUS_WAIT_MUTEX;
649 condition_variable->name = 620 current_thread->wakeup_callback = nullptr;
650 Common::StringFromFormat("condition-variable-%llx", condition_variable_addr);
651 }
652 621
653 if (condition_variable->mutex_addr) { 622 current_thread->WakeAfterDelay(nano_seconds);
654 // Previously created the ConditionVariable using WaitProcessWideKeyAtomic, verify
655 // everything is correct
656 ASSERT(condition_variable->mutex_addr == mutex_addr);
657 } else {
658 // Previously created the ConditionVariable using SignalProcessWideKey, set the mutex
659 // associated with it
660 condition_variable->mutex_addr = mutex_addr;
661 }
662 623
663 if (mutex->GetOwnerHandle()) { 624 // Note: Deliberately don't attempt to inherit the lock owner's priority.
664 // Release the mutex if the current thread is holding it
665 mutex->Release(thread.get());
666 }
667 625
668 auto wakeup_callback = [mutex, nano_seconds](ThreadWakeupReason reason, 626 Core::System::GetInstance().PrepareReschedule();
669 SharedPtr<Thread> thread, 627 return RESULT_SUCCESS;
670 SharedPtr<WaitObject> object, size_t index) { 628}
671 ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY);
672 629
673 if (reason == ThreadWakeupReason::Timeout) { 630/// Signal process wide key
674 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); 631static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
675 return true; 632 NGLOG_TRACE(Kernel_SVC, "called, condition_variable_addr={:#X}, target={:#010X}",
676 } 633 condition_variable_addr, target);
677 634
678 ASSERT(reason == ThreadWakeupReason::Signal); 635 u32 processed = 0;
636 auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList();
679 637
680 // Now try to acquire the mutex and don't resume if it's not available. 638 for (auto& thread : thread_list) {
681 if (!mutex->ShouldWait(thread.get())) { 639 if (thread->condvar_wait_address != condition_variable_addr)
682 mutex->Acquire(thread.get()); 640 continue;
683 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
684 return true;
685 }
686 641
687 if (nano_seconds == 0) { 642 // Only process up to 'target' threads, unless 'target' is -1, in which case process
688 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); 643 // them all.
689 return true; 644 if (target != -1 && processed >= target)
690 } 645 break;
691 646
692 thread->wait_objects = {mutex}; 647 // If the mutex is not yet acquired, acquire it.
693 mutex->AddWaitingThread(thread); 648 u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
694 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
695 649
696 // Create an event to wake the thread up after the 650 if (mutex_val == 0) {
697 // specified nanosecond delay has passed 651 // We were able to acquire the mutex, resume this thread.
698 thread->WakeAfterDelay(nano_seconds); 652 Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
699 thread->wakeup_callback = DefaultThreadWakeupCallback; 653 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
654 thread->ResumeFromWait();
700 655
701 Core::System::GetInstance().PrepareReschedule(); 656 auto lock_owner = thread->lock_owner;
657 if (lock_owner)
658 lock_owner->RemoveMutexWaiter(thread);
702 659
703 return false; 660 thread->lock_owner = nullptr;
704 }; 661 thread->mutex_wait_address = 0;
705 CASCADE_CODE( 662 thread->condvar_wait_address = 0;
706 WaitSynchronization1(condition_variable, thread.get(), nano_seconds, wakeup_callback)); 663 thread->wait_handle = 0;
664 } else {
665 // Couldn't acquire the mutex, block the thread.
666 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
667 auto owner = g_handle_table.Get<Thread>(owner_handle);
668 ASSERT(owner);
669 ASSERT(thread->status != THREADSTATUS_RUNNING);
670 thread->status = THREADSTATUS_WAIT_MUTEX;
671 thread->wakeup_callback = nullptr;
707 672
708 return RESULT_SUCCESS; 673 // Signal that the mutex now has a waiting thread.
709} 674 Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
710 675
711/// Signal process wide key 676 owner->AddMutexWaiter(thread);
712static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target) {
713 LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x%llx, target=0x%08x",
714 condition_variable_addr, target);
715
716 // Wakeup all or one thread - Any other value is unimplemented
717 ASSERT(target == -1 || target == 1);
718
719 SharedPtr<ConditionVariable> condition_variable =
720 g_object_address_table.Get<ConditionVariable>(condition_variable_addr);
721 if (!condition_variable) {
722 // Create a new condition_variable for the specified address if one does not already exist
723 condition_variable = ConditionVariable::Create(condition_variable_addr).Unwrap();
724 condition_variable->name =
725 Common::StringFromFormat("condition-variable-%llx", condition_variable_addr);
726 }
727 677
728 CASCADE_CODE(condition_variable->Release(target)); 678 Core::System::GetInstance().PrepareReschedule();
679 }
729 680
730 if (condition_variable->mutex_addr) { 681 ++processed;
731 // If a mutex was created for this condition_variable, wait the current thread on it
732 SharedPtr<Mutex> mutex = g_object_address_table.Get<Mutex>(condition_variable->mutex_addr);
733 return WaitSynchronization1(mutex, GetCurrentThread());
734 } 682 }
735 683
736 return RESULT_SUCCESS; 684 return RESULT_SUCCESS;
@@ -748,13 +696,13 @@ static u64 GetSystemTick() {
748 696
749/// Close a handle 697/// Close a handle
750static ResultCode CloseHandle(Handle handle) { 698static ResultCode CloseHandle(Handle handle) {
751 LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); 699 NGLOG_TRACE(Kernel_SVC, "Closing handle {:#010X}", handle);
752 return g_handle_table.Close(handle); 700 return g_handle_table.Close(handle);
753} 701}
754 702
755/// Reset an event 703/// Reset an event
756static ResultCode ResetSignal(Handle handle) { 704static ResultCode ResetSignal(Handle handle) {
757 LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x%08X", handle); 705 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called handle {:#010X}", handle);
758 auto event = g_handle_table.Get<Event>(handle); 706 auto event = g_handle_table.Get<Event>(handle);
759 ASSERT(event != nullptr); 707 ASSERT(event != nullptr);
760 event->Clear(); 708 event->Clear();
@@ -763,29 +711,29 @@ static ResultCode ResetSignal(Handle handle) {
763 711
764/// Creates a TransferMemory object 712/// Creates a TransferMemory object
765static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { 713static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
766 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%lx, size=0x%lx, perms=%08X", addr, size, 714 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called addr={:#X}, size={:#X}, perms={:010X}", addr, size,
767 permissions); 715 permissions);
768 *handle = 0; 716 *handle = 0;
769 return RESULT_SUCCESS; 717 return RESULT_SUCCESS;
770} 718}
771 719
772static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) { 720static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) {
773 LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X", handle); 721 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:010X}", handle);
774 *mask = 0x0; 722 *mask = 0x0;
775 *unknown = 0xf; 723 *unknown = 0xf;
776 return RESULT_SUCCESS; 724 return RESULT_SUCCESS;
777} 725}
778 726
779static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) { 727static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) {
780 LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X, mask=0x%08X, unknown=0x%lx", handle, 728 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle={:#010X}, mask={:#010X}, unknown={:#X}",
781 mask, unknown); 729 handle, mask, unknown);
782 return RESULT_SUCCESS; 730 return RESULT_SUCCESS;
783} 731}
784 732
785static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, 733static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions,
786 u32 remote_permissions) { 734 u32 remote_permissions) {
787 LOG_TRACE(Kernel_SVC, "called, size=0x%llx, localPerms=0x%08x, remotePerms=0x%08x", size, 735 NGLOG_TRACE(Kernel_SVC, "called, size={:#X}, localPerms={:#010X}, remotePerms={:#010X}", size,
788 local_permissions, remote_permissions); 736 local_permissions, remote_permissions);
789 auto sharedMemHandle = 737 auto sharedMemHandle =
790 SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size, 738 SharedMemory::Create(g_handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
791 static_cast<MemoryPermission>(local_permissions), 739 static_cast<MemoryPermission>(local_permissions),
@@ -796,7 +744,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
796} 744}
797 745
798static ResultCode ClearEvent(Handle handle) { 746static ResultCode ClearEvent(Handle handle) {
799 LOG_TRACE(Kernel_SVC, "called, event=0xX", handle); 747 NGLOG_TRACE(Kernel_SVC, "called, event={:010X}", handle);
800 748
801 SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); 749 SharedPtr<Event> evt = g_handle_table.Get<Event>(handle);
802 if (evt == nullptr) 750 if (evt == nullptr)
@@ -948,7 +896,7 @@ static const FunctionDef SVC_Table[] = {
948 896
949static const FunctionDef* GetSVCInfo(u32 func_num) { 897static const FunctionDef* GetSVCInfo(u32 func_num) {
950 if (func_num >= std::size(SVC_Table)) { 898 if (func_num >= std::size(SVC_Table)) {
951 LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); 899 NGLOG_ERROR(Kernel_SVC, "Unknown svc={:#04X}", func_num);
952 return nullptr; 900 return nullptr;
953 } 901 }
954 return &SVC_Table[func_num]; 902 return &SVC_Table[func_num];
@@ -967,10 +915,10 @@ void CallSVC(u32 immediate) {
967 if (info->func) { 915 if (info->func) {
968 info->func(); 916 info->func();
969 } else { 917 } else {
970 LOG_CRITICAL(Kernel_SVC, "unimplemented SVC function %s(..)", info->name); 918 NGLOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
971 } 919 }
972 } else { 920 } else {
973 LOG_CRITICAL(Kernel_SVC, "unknown SVC function 0x%x", immediate); 921 NGLOG_CRITICAL(Kernel_SVC, "Unknown SVC function {:#X}", immediate);
974 } 922 }
975} 923}
976 924
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index f3a8aa4aa..4cd57ab25 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -77,9 +77,6 @@ void Thread::Stop() {
77 } 77 }
78 wait_objects.clear(); 78 wait_objects.clear();
79 79
80 // Release all the mutexes that this thread holds
81 ReleaseThreadMutexes(this);
82
83 // Mark the TLS slot in the thread's page as free. 80 // Mark the TLS slot in the thread's page as free.
84 u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; 81 u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
85 u64 tls_slot = 82 u64 tls_slot =
@@ -104,9 +101,10 @@ void ExitCurrentThread() {
104 * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time 101 * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
105 */ 102 */
106static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { 103static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
107 SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle); 104 const auto proper_handle = static_cast<Handle>(thread_handle);
105 SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
108 if (thread == nullptr) { 106 if (thread == nullptr) {
109 LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", (Handle)thread_handle); 107 NGLOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
110 return; 108 return;
111 } 109 }
112 110
@@ -126,6 +124,19 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
126 resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0); 124 resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
127 } 125 }
128 126
127 if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
128 thread->wait_handle) {
129 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
130 thread->mutex_wait_address = 0;
131 thread->condvar_wait_address = 0;
132 thread->wait_handle = 0;
133
134 auto lock_owner = thread->lock_owner;
135 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
136 // and don't have a lock owner.
137 ASSERT(lock_owner == nullptr);
138 }
139
129 if (resume) 140 if (resume)
130 thread->ResumeFromWait(); 141 thread->ResumeFromWait();
131} 142}
@@ -151,6 +162,7 @@ void Thread::ResumeFromWait() {
151 case THREADSTATUS_WAIT_HLE_EVENT: 162 case THREADSTATUS_WAIT_HLE_EVENT:
152 case THREADSTATUS_WAIT_SLEEP: 163 case THREADSTATUS_WAIT_SLEEP:
153 case THREADSTATUS_WAIT_IPC: 164 case THREADSTATUS_WAIT_IPC:
165 case THREADSTATUS_WAIT_MUTEX:
154 break; 166 break;
155 167
156 case THREADSTATUS_READY: 168 case THREADSTATUS_READY:
@@ -227,19 +239,19 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
227 SharedPtr<Process> owner_process) { 239 SharedPtr<Process> owner_process) {
228 // Check if priority is in ranged. Lowest priority -> highest priority id. 240 // Check if priority is in ranged. Lowest priority -> highest priority id.
229 if (priority > THREADPRIO_LOWEST) { 241 if (priority > THREADPRIO_LOWEST) {
230 LOG_ERROR(Kernel_SVC, "Invalid thread priority: %u", priority); 242 NGLOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
231 return ERR_OUT_OF_RANGE; 243 return ERR_OUT_OF_RANGE;
232 } 244 }
233 245
234 if (processor_id > THREADPROCESSORID_MAX) { 246 if (processor_id > THREADPROCESSORID_MAX) {
235 LOG_ERROR(Kernel_SVC, "Invalid processor id: %d", processor_id); 247 NGLOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
236 return ERR_OUT_OF_RANGE_KERNEL; 248 return ERR_OUT_OF_RANGE_KERNEL;
237 } 249 }
238 250
239 // TODO(yuriks): Other checks, returning 0xD9001BEA 251 // TODO(yuriks): Other checks, returning 0xD9001BEA
240 252
241 if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { 253 if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
242 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %016" PRIx64, name.c_str(), entry_point); 254 NGLOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
243 // TODO (bunnei): Find the correct error code to use here 255 // TODO (bunnei): Find the correct error code to use here
244 return ResultCode(-1); 256 return ResultCode(-1);
245 } 257 }
@@ -256,7 +268,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
256 thread->last_running_ticks = CoreTiming::GetTicks(); 268 thread->last_running_ticks = CoreTiming::GetTicks();
257 thread->processor_id = processor_id; 269 thread->processor_id = processor_id;
258 thread->wait_objects.clear(); 270 thread->wait_objects.clear();
259 thread->wait_address = 0; 271 thread->mutex_wait_address = 0;
272 thread->condvar_wait_address = 0;
273 thread->wait_handle = 0;
260 thread->name = std::move(name); 274 thread->name = std::move(name);
261 thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); 275 thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
262 thread->owner_process = owner_process; 276 thread->owner_process = owner_process;
@@ -276,8 +290,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
276 auto& linheap_memory = memory_region->linear_heap_memory; 290 auto& linheap_memory = memory_region->linear_heap_memory;
277 291
278 if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { 292 if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
279 LOG_ERROR(Kernel_SVC, 293 NGLOG_ERROR(Kernel_SVC,
280 "Not enough space in region to allocate a new TLS page for thread"); 294 "Not enough space in region to allocate a new TLS page for thread");
281 return ERR_OUT_OF_MEMORY; 295 return ERR_OUT_OF_MEMORY;
282 } 296 }
283 297
@@ -317,17 +331,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
317void Thread::SetPriority(u32 priority) { 331void Thread::SetPriority(u32 priority) {
318 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, 332 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
319 "Invalid priority value."); 333 "Invalid priority value.");
320 Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); 334 nominal_priority = priority;
321 nominal_priority = current_priority = priority; 335 UpdatePriority();
322}
323
324void Thread::UpdatePriority() {
325 u32 best_priority = nominal_priority;
326 for (auto& mutex : held_mutexes) {
327 if (mutex->priority < best_priority)
328 best_priority = mutex->priority;
329 }
330 BoostPriority(best_priority);
331} 336}
332 337
333void Thread::BoostPriority(u32 priority) { 338void Thread::BoostPriority(u32 priority) {
@@ -377,6 +382,38 @@ VAddr Thread::GetCommandBufferAddress() const {
377 return GetTLSAddress() + CommandHeaderOffset; 382 return GetTLSAddress() + CommandHeaderOffset;
378} 383}
379 384
385void Thread::AddMutexWaiter(SharedPtr<Thread> thread) {
386 thread->lock_owner = this;
387 wait_mutex_threads.emplace_back(std::move(thread));
388 UpdatePriority();
389}
390
391void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) {
392 boost::remove_erase(wait_mutex_threads, thread);
393 thread->lock_owner = nullptr;
394 UpdatePriority();
395}
396
397void Thread::UpdatePriority() {
398 // Find the highest priority among all the threads that are waiting for this thread's lock
399 u32 new_priority = nominal_priority;
400 for (const auto& thread : wait_mutex_threads) {
401 if (thread->nominal_priority < new_priority)
402 new_priority = thread->nominal_priority;
403 }
404
405 if (new_priority == current_priority)
406 return;
407
408 Core::System::GetInstance().Scheduler().SetThreadPriority(this, new_priority);
409
410 current_priority = new_priority;
411
412 // Recursively update the priority of the thread that depends on the priority of this one.
413 if (lock_owner)
414 lock_owner->UpdatePriority();
415}
416
380//////////////////////////////////////////////////////////////////////////////////////////////////// 417////////////////////////////////////////////////////////////////////////////////////////////////////
381 418
382/** 419/**
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index dbf47e269..e0a3c0934 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -18,7 +18,7 @@
18enum ThreadPriority : u32 { 18enum ThreadPriority : u32 {
19 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 19 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
20 THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps 20 THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
21 THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps 21 THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps
22 THREADPRIO_LOWEST = 63, ///< Lowest thread priority 22 THREADPRIO_LOWEST = 63, ///< Lowest thread priority
23}; 23};
24 24
@@ -43,6 +43,7 @@ enum ThreadStatus {
43 THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request 43 THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request
44 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false 44 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
45 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true 45 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
46 THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
46 THREADSTATUS_DORMANT, ///< Created but not yet made ready 47 THREADSTATUS_DORMANT, ///< Created but not yet made ready
47 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated 48 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
48}; 49};
@@ -54,7 +55,6 @@ enum class ThreadWakeupReason {
54 55
55namespace Kernel { 56namespace Kernel {
56 57
57class Mutex;
58class Process; 58class Process;
59 59
60class Thread final : public WaitObject { 60class Thread final : public WaitObject {
@@ -104,17 +104,20 @@ public:
104 void SetPriority(u32 priority); 104 void SetPriority(u32 priority);
105 105
106 /** 106 /**
107 * Boost's a thread's priority to the best priority among the thread's held mutexes.
108 * This prevents priority inversion via priority inheritance.
109 */
110 void UpdatePriority();
111
112 /**
113 * Temporarily boosts the thread's priority until the next time it is scheduled 107 * Temporarily boosts the thread's priority until the next time it is scheduled
114 * @param priority The new priority 108 * @param priority The new priority
115 */ 109 */
116 void BoostPriority(u32 priority); 110 void BoostPriority(u32 priority);
117 111
112 /// Adds a thread to the list of threads that are waiting for a lock held by this thread.
113 void AddMutexWaiter(SharedPtr<Thread> thread);
114
115 /// Removes a thread from the list of threads that are waiting for a lock held by this thread.
116 void RemoveMutexWaiter(SharedPtr<Thread> thread);
117
118 /// Recalculates the current priority taking into account priority inheritance.
119 void UpdatePriority();
120
118 /** 121 /**
119 * Gets the thread's thread ID 122 * Gets the thread's thread ID
120 * @return The thread's ID 123 * @return The thread's ID
@@ -205,19 +208,22 @@ public:
205 208
206 VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread 209 VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
207 210
208 /// Mutexes currently held by this thread, which will be released when it exits.
209 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
210
211 /// Mutexes that this thread is currently waiting for.
212 boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes;
213
214 SharedPtr<Process> owner_process; ///< Process that owns this thread 211 SharedPtr<Process> owner_process; ///< Process that owns this thread
215 212
216 /// Objects that the thread is waiting on, in the same order as they were 213 /// Objects that the thread is waiting on, in the same order as they were
217 // passed to WaitSynchronization1/N. 214 // passed to WaitSynchronization1/N.
218 std::vector<SharedPtr<WaitObject>> wait_objects; 215 std::vector<SharedPtr<WaitObject>> wait_objects;
219 216
220 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address 217 /// List of threads that are waiting for a mutex that is held by this thread.
218 std::vector<SharedPtr<Thread>> wait_mutex_threads;
219
220 /// Thread that owns the lock that this thread is waiting for.
221 SharedPtr<Thread> lock_owner;
222
223 // If waiting on a ConditionVariable, this is the ConditionVariable address
224 VAddr condvar_wait_address;
225 VAddr mutex_wait_address; ///< If waiting on a Mutex, this is the mutex address
226 Handle wait_handle; ///< The handle used to wait for the mutex.
221 227
222 std::string name; 228 std::string name;
223 229
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 8da745634..ad58bf043 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -77,7 +77,7 @@ void Timer::WakeupAllWaitingThreads() {
77} 77}
78 78
79void Timer::Signal(int cycles_late) { 79void Timer::Signal(int cycles_late) {
80 LOG_TRACE(Kernel, "Timer %u fired", GetObjectId()); 80 NGLOG_TRACE(Kernel, "Timer {} fired", GetObjectId());
81 81
82 signaled = true; 82 signaled = true;
83 83
@@ -97,7 +97,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
97 timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); 97 timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
98 98
99 if (timer == nullptr) { 99 if (timer == nullptr) {
100 LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle); 100 NGLOG_CRITICAL(Kernel, "Callback fired for invalid timer {:016X}", timer_handle);
101 return; 101 return;
102 } 102 }
103 103
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index acd65ee68..eb2e35eed 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -379,22 +379,22 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
379} 379}
380 380
381u64 VMManager::GetTotalMemoryUsage() { 381u64 VMManager::GetTotalMemoryUsage() {
382 LOG_WARNING(Kernel, "(STUBBED) called"); 382 NGLOG_WARNING(Kernel, "(STUBBED) called");
383 return 0xF8000000; 383 return 0xF8000000;
384} 384}
385 385
386u64 VMManager::GetTotalHeapUsage() { 386u64 VMManager::GetTotalHeapUsage() {
387 LOG_WARNING(Kernel, "(STUBBED) called"); 387 NGLOG_WARNING(Kernel, "(STUBBED) called");
388 return 0x0; 388 return 0x0;
389} 389}
390 390
391VAddr VMManager::GetAddressSpaceBaseAddr() { 391VAddr VMManager::GetAddressSpaceBaseAddr() {
392 LOG_WARNING(Kernel, "(STUBBED) called"); 392 NGLOG_WARNING(Kernel, "(STUBBED) called");
393 return 0x8000000; 393 return 0x8000000;
394} 394}
395 395
396u64 VMManager::GetAddressSpaceSize() { 396u64 VMManager::GetAddressSpaceSize() {
397 LOG_WARNING(Kernel, "(STUBBED) called"); 397 NGLOG_WARNING(Kernel, "(STUBBED) called");
398 return MAX_ADDRESS; 398 return MAX_ADDRESS;
399} 399}
400 400