diff options
| author | 2018-04-26 14:28:54 -0700 | |
|---|---|---|
| committer | 2018-04-26 14:28:54 -0700 | |
| commit | 7391741a204d6f25a06132eda214b2199b60a084 (patch) | |
| tree | aeeb723744c4563ad608361b82dd938b062a3e09 /src/core/hle/kernel | |
| parent | Added PREPO to logging backend, Removed comments from SaveReportWithUser (diff) | |
| parent | Merge pull request #403 from lioncash/common (diff) | |
| download | yuzu-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.cpp | 64 | ||||
| -rw-r--r-- | src/core/hle/kernel/condition_variable.h | 63 | ||||
| -rw-r--r-- | src/core/hle/kernel/errors.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/handle_table.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 179 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.h | 88 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/resource_limit.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 17 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 296 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 81 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 8 |
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 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | ConditionVariable::ConditionVariable() {} | ||
| 15 | ConditionVariable::~ConditionVariable() {} | ||
| 16 | |||
| 17 | ResultVal<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 | |||
| 31 | bool ConditionVariable::ShouldWait(Thread* thread) const { | ||
| 32 | return GetAvailableCount() <= 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | void ConditionVariable::Acquire(Thread* thread) { | ||
| 36 | if (GetAvailableCount() <= 0) | ||
| 37 | return; | ||
| 38 | |||
| 39 | SetAvailableCount(GetAvailableCount() - 1); | ||
| 40 | } | ||
| 41 | |||
| 42 | ResultCode 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 | |||
| 56 | s32 ConditionVariable::GetAvailableCount() const { | ||
| 57 | return Memory::Read32(guest_addr); | ||
| 58 | } | ||
| 59 | |||
| 60 | void 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 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class ConditionVariable final : public WaitObject { | ||
| 17 | public: | ||
| 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 | |||
| 58 | private: | ||
| 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) { | |||
| 48 | ResultVal<Handle> HandleTable::Duplicate(Handle handle) { | 48 | ResultVal<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; | |||
| 18 | enum class HandleType : u32 { | 18 | enum 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 | ||
| 16 | namespace Kernel { | 17 | namespace Kernel { |
| 17 | 18 | ||
| 18 | void 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); | 21 | static 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 | ||
| 27 | Mutex::Mutex() {} | 24 | SharedPtr<Thread> highest_priority_thread; |
| 28 | Mutex::~Mutex() {} | 25 | u32 num_waiters = 0; |
| 29 | 26 | ||
| 30 | SharedPtr<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 | ||
| 48 | bool 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(); | 44 | static 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 | ||
| 53 | void Mutex::Acquire(Thread* thread) { | 58 | ResultCode 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 | ||
| 63 | ResultCode 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 | ||
| 80 | void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { | 97 | ResultCode 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 | |||
| 87 | void 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 | ||
| 95 | void 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 | ||
| 111 | Handle 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 | ||
| 116 | SharedPtr<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 | ||
| 121 | void 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 | ||
| 127 | bool 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 | ||
| 132 | void 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 | ||
| 16 | class Thread; | 16 | class Thread; |
| 17 | 17 | ||
| 18 | class Mutex final : public WaitObject { | 18 | class Mutex final { |
| 19 | public: | 19 | public: |
| 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 | ||
| 80 | private: | 32 | private: |
| 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 | */ | ||
| 99 | void 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 | ||
| 156 | u8* SharedMemory::GetPointer(u32 offset) { | 157 | u8* 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. |
| 34 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 33 | static 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 | ||
| 42 | static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { | 41 | static 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. |
| 48 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 47 | static 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 |
| 55 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 54 | static 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 | |||
| 91 | static ResultCode SendSyncRequest(Handle handle) { | 90 | static 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. |
| 108 | static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | 107 | static 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 |
| 121 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | 120 | static 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 |
| 180 | static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 handle_count, | 179 | static 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 |
| 242 | static ResultCode CancelSynchronization(Handle thread_handle) { | 241 | static 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 |
| 258 | static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | 257 | static 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 |
| 284 | static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | 268 | static 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 |
| 294 | static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { | 275 | static 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 |
| 300 | static void OutputDebugString(VAddr address, s32 len) { | 281 | static 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 |
| 307 | static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { | 288 | static 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 |
| 376 | static ResultCode SetThreadActivity(Handle handle, u32 unknown) { | 357 | static 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 |
| 382 | static ResultCode GetThreadContext(Handle handle, VAddr addr) { | 364 | static 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 |
| 426 | static u32 GetCurrentProcessorNumber() { | 403 | static 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 | ||
| 431 | static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, | 408 | static 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 | ||
| 461 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | 438 | static 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 |
| 497 | static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { | 473 | static 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 |
| 503 | static void ExitProcess() { | 479 | static 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 |
| 587 | static ResultCode StartThread(Handle thread_handle) { | 563 | static 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 |
| 601 | static void ExitThread() { | 577 | static 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 |
| 609 | static void SleepThread(s64 nanoseconds) { | 585 | static 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 |
| 627 | static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, | 603 | static 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); | 631 | static 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); |
| 712 | static 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 |
| 750 | static ResultCode CloseHandle(Handle handle) { | 698 | static 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 |
| 756 | static ResultCode ResetSignal(Handle handle) { | 704 | static 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 |
| 765 | static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { | 713 | static 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 | ||
| 772 | static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) { | 720 | static 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 | ||
| 779 | static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) { | 727 | static 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 | ||
| 785 | static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permissions, | 733 | static 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 | ||
| 798 | static ResultCode ClearEvent(Handle handle) { | 746 | static 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 | ||
| 949 | static const FunctionDef* GetSVCInfo(u32 func_num) { | 897 | static 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 | */ |
| 106 | static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | 103 | static 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, | |||
| 317 | void Thread::SetPriority(u32 priority) { | 331 | void 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 | |||
| 324 | void 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 | ||
| 333 | void Thread::BoostPriority(u32 priority) { | 338 | void Thread::BoostPriority(u32 priority) { |
| @@ -377,6 +382,38 @@ VAddr Thread::GetCommandBufferAddress() const { | |||
| 377 | return GetTLSAddress() + CommandHeaderOffset; | 382 | return GetTLSAddress() + CommandHeaderOffset; |
| 378 | } | 383 | } |
| 379 | 384 | ||
| 385 | void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { | ||
| 386 | thread->lock_owner = this; | ||
| 387 | wait_mutex_threads.emplace_back(std::move(thread)); | ||
| 388 | UpdatePriority(); | ||
| 389 | } | ||
| 390 | |||
| 391 | void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { | ||
| 392 | boost::remove_erase(wait_mutex_threads, thread); | ||
| 393 | thread->lock_owner = nullptr; | ||
| 394 | UpdatePriority(); | ||
| 395 | } | ||
| 396 | |||
| 397 | void 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 @@ | |||
| 18 | enum ThreadPriority : u32 { | 18 | enum 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 | ||
| 55 | namespace Kernel { | 56 | namespace Kernel { |
| 56 | 57 | ||
| 57 | class Mutex; | ||
| 58 | class Process; | 58 | class Process; |
| 59 | 59 | ||
| 60 | class Thread final : public WaitObject { | 60 | class 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 | ||
| 79 | void Timer::Signal(int cycles_late) { | 79 | void 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 | ||
| 381 | u64 VMManager::GetTotalMemoryUsage() { | 381 | u64 VMManager::GetTotalMemoryUsage() { |
| 382 | LOG_WARNING(Kernel, "(STUBBED) called"); | 382 | NGLOG_WARNING(Kernel, "(STUBBED) called"); |
| 383 | return 0xF8000000; | 383 | return 0xF8000000; |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | u64 VMManager::GetTotalHeapUsage() { | 386 | u64 VMManager::GetTotalHeapUsage() { |
| 387 | LOG_WARNING(Kernel, "(STUBBED) called"); | 387 | NGLOG_WARNING(Kernel, "(STUBBED) called"); |
| 388 | return 0x0; | 388 | return 0x0; |
| 389 | } | 389 | } |
| 390 | 390 | ||
| 391 | VAddr VMManager::GetAddressSpaceBaseAddr() { | 391 | VAddr VMManager::GetAddressSpaceBaseAddr() { |
| 392 | LOG_WARNING(Kernel, "(STUBBED) called"); | 392 | NGLOG_WARNING(Kernel, "(STUBBED) called"); |
| 393 | return 0x8000000; | 393 | return 0x8000000; |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | u64 VMManager::GetAddressSpaceSize() { | 396 | u64 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 | ||