summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2015-02-02 19:04:04 +0100
committerbunnei <bunneidev@gmail.com>2015-02-02 19:04:04 +0100
commit7f730ed158bc9bba064100b9644b318134ef0bb3 (patch)
treec4181a69ff882e1af1b7d65bf3596a6cb3dd88b9 /src/core/hle/kernel
parentMerge pull request #517 from bunnei/blend-factors (diff)
parentKernel: Stop creating useless Handles during object creation (diff)
downloadyuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.gz
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.bz2
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.lz
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.xz
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.tar.zst
yuzu-7f730ed158bc9bba064100b9644b318134ef0bb3.zip
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp13
-rw-r--r--src/core/hle/kernel/address_arbiter.h5
-rw-r--r--src/core/hle/kernel/event.cpp9
-rw-r--r--src/core/hle/kernel/event.h5
-rw-r--r--src/core/hle/kernel/kernel.cpp17
-rw-r--r--src/core/hle/kernel/kernel.h21
-rw-r--r--src/core/hle/kernel/mutex.cpp41
-rw-r--r--src/core/hle/kernel/mutex.h7
-rw-r--r--src/core/hle/kernel/semaphore.cpp5
-rw-r--r--src/core/hle/kernel/semaphore.h3
-rw-r--r--src/core/hle/kernel/session.cpp13
-rw-r--r--src/core/hle/kernel/session.h4
-rw-r--r--src/core/hle/kernel/shared_memory.cpp17
-rw-r--r--src/core/hle/kernel/shared_memory.h5
-rw-r--r--src/core/hle/kernel/thread.cpp53
-rw-r--r--src/core/hle/kernel/thread.h31
-rw-r--r--src/core/hle/kernel/timer.cpp28
-rw-r--r--src/core/hle/kernel/timer.h8
18 files changed, 158 insertions, 127 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2d01e2ef5..42f8ce2d9 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -15,14 +15,15 @@
namespace Kernel {
-ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) {
+AddressArbiter::AddressArbiter() {}
+AddressArbiter::~AddressArbiter() {}
+
+SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter);
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter));
address_arbiter->name = std::move(name);
- return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter));
+ return address_arbiter;
}
ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value,
@@ -51,7 +52,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
case ArbitrationType::WaitIfLessThanWithTimeout:
if ((s32)Memory::Read32(address) <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
+ GetCurrentThread()->WakeAfterDelay(nanoseconds);
HLE::Reschedule(__func__);
}
break;
@@ -71,7 +72,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
Memory::Write32(address, memory_value);
if (memory_value <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
+ GetCurrentThread()->WakeAfterDelay(nanoseconds);
HLE::Reschedule(__func__);
}
break;
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 638afff9e..8f6a1a8df 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -34,7 +34,7 @@ public:
* @param name Optional name used for debugging.
* @returns The created AddressArbiter.
*/
- static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown");
+ static SharedPtr<AddressArbiter> Create(std::string name = "Unknown");
std::string GetTypeName() const override { return "Arbiter"; }
std::string GetName() const override { return name; }
@@ -47,7 +47,8 @@ public:
ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds);
private:
- AddressArbiter() = default;
+ AddressArbiter();
+ ~AddressArbiter() override;
};
} // namespace FileSys
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index d9ad40c6a..898e1c98f 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -14,16 +14,17 @@
namespace Kernel {
-ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) {
+Event::Event() {}
+Event::~Event() {}
+
+SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
SharedPtr<Event> evt(new Event);
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt));
evt->signaled = false;
evt->reset_type = evt->intitial_reset_type = reset_type;
evt->name = std::move(name);
- return MakeResult<SharedPtr<Event>>(evt);
+ return evt;
}
bool Event::ShouldWait() {
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 2c3e6b14e..fba960d2a 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -18,7 +18,7 @@ public:
* @param reset_type ResetType describing how to create event
* @param name Optional name of event
*/
- static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown");
+ static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown");
std::string GetTypeName() const override { return "Event"; }
std::string GetName() const override { return name; }
@@ -39,7 +39,8 @@ public:
void Clear();
private:
- Event() = default;
+ Event();
+ ~Event() override;
};
} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d7fa4dcea..7e0b9542e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -14,14 +14,16 @@
namespace Kernel {
+unsigned int Object::next_object_id = 0;
+
SharedPtr<Thread> g_main_thread = nullptr;
HandleTable g_handle_table;
u64 g_program_id = 0;
-void WaitObject::AddWaitingThread(Thread* thread) {
+void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end())
- waiting_threads.push_back(thread);
+ waiting_threads.push_back(std::move(thread));
}
void WaitObject::RemoveWaitingThread(Thread* thread) {
@@ -30,11 +32,11 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr);
}
-Thread* WaitObject::WakeupNextThread() {
+SharedPtr<Thread> WaitObject::WakeupNextThread() {
if (waiting_threads.empty())
return nullptr;
- auto next_thread = waiting_threads.front();
+ auto next_thread = std::move(waiting_threads.front());
waiting_threads.erase(waiting_threads.begin());
next_thread->ReleaseWaitObject(this);
@@ -74,13 +76,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
// CTR-OS doesn't use generation 0, so skip straight to 1.
if (next_generation >= (1 << 15)) next_generation = 1;
- Handle handle = generation | (slot << 15);
- if (obj->handle == INVALID_HANDLE)
- obj->handle = handle;
-
generations[slot] = generation;
objects[slot] = std::move(obj);
+ Handle handle = generation | (slot << 15);
return MakeResult<Handle>(handle);
}
@@ -102,7 +101,7 @@ ResultCode HandleTable::Close(Handle handle) {
objects[slot] = nullptr;
- generations[generation] = next_free_slot;
+ generations[slot] = next_free_slot;
next_free_slot = slot;
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 9860479ac..4d8e388b6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -58,14 +58,12 @@ enum {
DEFAULT_STACK_SIZE = 0x4000,
};
-class HandleTable;
-
class Object : NonCopyable {
- friend class HandleTable;
- u32 handle = INVALID_HANDLE;
public:
virtual ~Object() {}
- Handle GetHandle() const { return handle; }
+
+ /// Returns a unique identifier for the object. For debugging purposes only.
+ unsigned int GetObjectId() const { return object_id; }
virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
@@ -101,7 +99,10 @@ private:
friend void intrusive_ptr_add_ref(Object*);
friend void intrusive_ptr_release(Object*);
+ static unsigned int next_object_id;
+
unsigned int ref_count = 0;
+ unsigned int object_id = next_object_id++;
};
// Special functions used by boost::instrusive_ptr to do automatic ref-counting
@@ -135,25 +136,26 @@ public:
* Add a thread to wait on this object
* @param thread Pointer to thread to add
*/
- void AddWaitingThread(Thread* thread);
+ void AddWaitingThread(SharedPtr<Thread> thread);
/**
* Removes a thread from waiting on this object (e.g. if it was resumed already)
* @param thread Pointer to thread to remove
*/
- void RemoveWaitingThread(Thread* thead);
+ void RemoveWaitingThread(Thread* thread);
/**
* Wake up the next thread waiting on this object
* @return Pointer to the thread that was resumed, nullptr if no threads are waiting
*/
- Thread* WakeupNextThread();
+ SharedPtr<Thread> WakeupNextThread();
/// Wake up all threads waiting on this object
void WakeupAllWaitingThreads();
private:
- std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available
+ /// Threads waiting for this object to become available
+ std::vector<SharedPtr<Thread>> waiting_threads;
};
/**
@@ -274,7 +276,6 @@ private:
};
extern HandleTable g_handle_table;
-extern SharedPtr<Thread> g_main_thread;
/// The ID code of the currently running game
/// TODO(Subv): This variable should not be here,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index acf484659..9f7166ca4 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -5,6 +5,8 @@
#include <map>
#include <vector>
+#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/common.h"
#include "core/hle/kernel/kernel.h"
@@ -13,9 +15,6 @@
namespace Kernel {
-typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap;
-static MutexMap g_mutex_held_locks;
-
/**
* Resumes a thread waiting for the specified mutex
* @param mutex The mutex that some thread is waiting on
@@ -33,21 +32,17 @@ static void ResumeWaitingThread(Mutex* mutex) {
}
void ReleaseThreadMutexes(Thread* thread) {
- auto locked_range = g_mutex_held_locks.equal_range(thread);
-
- // Release every mutex that the thread holds, and resume execution on the waiting threads
- for (auto iter = locked_range.first; iter != locked_range.second; ++iter) {
- ResumeWaitingThread(iter->second.get());
+ for (auto& mtx : thread->held_mutexes) {
+ ResumeWaitingThread(mtx.get());
}
-
- // Erase all the locks that this thread holds
- g_mutex_held_locks.erase(thread);
+ thread->held_mutexes.clear();
}
-ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) {
+Mutex::Mutex() {}
+Mutex::~Mutex() {}
+
+SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
SharedPtr<Mutex> mutex(new Mutex);
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex));
mutex->initial_locked = initial_locked;
mutex->locked = false;
@@ -58,7 +53,7 @@ ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name)
if (initial_locked)
mutex->Acquire();
- return MakeResult<SharedPtr<Mutex>>(mutex);
+ return mutex;
}
bool Mutex::ShouldWait() {
@@ -69,30 +64,22 @@ void Mutex::Acquire() {
Acquire(GetCurrentThread());
}
-void Mutex::Acquire(Thread* thread) {
+void Mutex::Acquire(SharedPtr<Thread> thread) {
_assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
if (locked)
return;
locked = true;
- g_mutex_held_locks.insert(std::make_pair(thread, this));
- holding_thread = thread;
+ thread->held_mutexes.insert(this);
+ holding_thread = std::move(thread);
}
void Mutex::Release() {
if (!locked)
return;
- auto locked_range = g_mutex_held_locks.equal_range(holding_thread);
-
- for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) {
- if (iter->second == this) {
- g_mutex_held_locks.erase(iter);
- break;
- }
- }
-
+ holding_thread->held_mutexes.erase(this);
ResumeWaitingThread(this);
}
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 1e69528f1..548403614 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -22,7 +22,7 @@ public:
* @param name Optional name of mutex
* @return Pointer to new Mutex object
*/
- static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown");
+ static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown");
std::string GetTypeName() const override { return "Mutex"; }
std::string GetName() const override { return name; }
@@ -43,11 +43,12 @@ public:
* @param mutex Mutex that is to be acquired
* @param thread Thread that will acquire the mutex
*/
- void Acquire(Thread* thread);
+ void Acquire(SharedPtr<Thread> thread);
void Release();
private:
- Mutex() = default;
+ Mutex();
+ ~Mutex() override;
};
/**
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index a9e406ef4..c8cf8b9a2 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -10,6 +10,9 @@
namespace Kernel {
+Semaphore::Semaphore() {}
+Semaphore::~Semaphore() {}
+
ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
std::string name) {
@@ -18,8 +21,6 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
SharedPtr<Semaphore> semaphore(new Semaphore);
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore));
// When the semaphore is created, some slots are reserved for other threads,
// and the rest is reserved for the caller thread
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 9bb404ab6..d8dc1fd78 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -47,7 +47,8 @@ public:
ResultVal<s32> Release(s32 release_count);
private:
- Semaphore() = default;
+ Semaphore();
+ ~Semaphore() override;
};
} // namespace
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
new file mode 100644
index 000000000..0594967f8
--- /dev/null
+++ b/src/core/hle/kernel/session.cpp
@@ -0,0 +1,13 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+Session::Session() {}
+Session::~Session() {}
+
+}
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 1788e4375..7cc9332c9 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -5,6 +5,7 @@
#pragma once
#include "core/hle/kernel/kernel.h"
+#include "core/mem_map.h"
namespace Kernel {
@@ -43,6 +44,9 @@ inline static u32* GetCommandBuffer(const int offset=0) {
*/
class Session : public WaitObject {
public:
+ Session();
+ ~Session() override;
+
std::string GetTypeName() const override { return "Session"; }
static const HandleType HANDLE_TYPE = HandleType::Session;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index eff68d481..4211fcf04 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -9,22 +9,23 @@
namespace Kernel {
-ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) {
- SharedPtr<SharedMemory> shared_memory(new SharedMemory);
+SharedMemory::SharedMemory() {}
+SharedMemory::~SharedMemory() {}
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory));
+SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
+ SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->name = std::move(name);
- return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory));
+
+ return shared_memory;
}
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
MemoryPermission other_permissions) {
if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
- LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
- GetHandle(), address);
+ LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
+ GetObjectId(), address);
// TODO: Verify error code with hardware
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
@@ -41,7 +42,7 @@ ResultVal<u8*> SharedMemory::GetPointer(u32 offset) {
if (base_address != 0)
return MakeResult<u8*>(Memory::GetPointer(base_address + offset));
- LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle());
+ LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
// TODO(yuriks): Verify error code.
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
ErrorSummary::InvalidState, ErrorLevel::Permanent);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index d393e8175..5833b411c 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -29,7 +29,7 @@ public:
* Creates a shared memory object
* @param name Optional object name, used only for debugging purposes.
*/
- static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown");
+ static SharedPtr<SharedMemory> Create(std::string name = "Unknown");
std::string GetTypeName() const override { return "SharedMemory"; }
@@ -57,7 +57,8 @@ public:
std::string name; ///< Name of shared memory object (optional)
private:
- SharedMemory() = default;
+ SharedMemory();
+ ~SharedMemory() override;
};
} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 56950ebd4..3987f9608 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,7 +4,6 @@
#include <algorithm>
#include <list>
-#include <map>
#include <vector>
#include "common/common.h"
@@ -41,6 +40,9 @@ static Thread* current_thread;
static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
static u32 next_thread_id; ///< The next available thread id
+Thread::Thread() {}
+Thread::~Thread() {}
+
Thread* GetCurrentThread() {
return current_thread;
}
@@ -108,6 +110,9 @@ void Thread::Stop(const char* reason) {
WakeupAllWaitingThreads();
// Stopped threads are never waiting.
+ for (auto& wait_object : wait_objects) {
+ wait_object->RemoveWaitingThread(this);
+ }
wait_objects.clear();
wait_address = 0;
}
@@ -228,13 +233,15 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
/// Event type for the thread wake up event
static int ThreadWakeupEventType = -1;
+// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
+// us to simply use a pool index or similar.
+static Kernel::HandleTable wakeup_callback_handle_table;
/// Callback that will wake up the thread it was scheduled for
-static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
- Handle handle = static_cast<Handle>(parameter);
- SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(handle);
+static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
+ SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle);
if (thread == nullptr) {
- LOG_ERROR(Kernel, "Thread doesn't exist %u", handle);
+ LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", thread_handle);
return;
}
@@ -248,14 +255,13 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
}
-void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) {
+void Thread::WakeAfterDelay(s64 nanoseconds) {
// Don't schedule a wakeup if the thread wants to wait forever
if (nanoseconds == -1)
return;
- _dbg_assert_(Kernel, thread != nullptr);
u64 microseconds = nanoseconds / 1000;
- CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle());
+ CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
}
void Thread::ReleaseWaitObject(WaitObject* wait_object) {
@@ -302,7 +308,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) {
void Thread::ResumeFromWait() {
// Cancel any outstanding wakeup events
- CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle());
+ CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
status &= ~THREADSTATUS_WAIT;
@@ -326,11 +332,11 @@ static void DebugThreadQueue() {
if (!thread) {
return;
}
- LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle());
+ LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId());
for (auto& t : thread_list) {
s32 priority = thread_ready_queue.contains(t.get());
if (priority != -1) {
- LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle());
+ LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId());
}
}
}
@@ -362,14 +368,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
SharedPtr<Thread> thread(new Thread);
- // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for
- // the time being. Create a handle here, it will be copied to the handle field in
- // the object and use by the rest of the code. This should be removed when other
- // code doesn't rely on the handle anymore.
- ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread);
- if (handle.Failed())
- return handle.Code();
-
thread_list.push_back(thread);
thread_ready_queue.prepare(priority);
@@ -385,6 +383,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->wait_objects.clear();
thread->wait_address = 0;
thread->name = std::move(name);
+ thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
ResetThread(thread.get(), arg, 0);
CallThread(thread.get());
@@ -418,16 +417,14 @@ void Thread::SetPriority(s32 priority) {
}
}
-Handle SetupIdleThread() {
+SharedPtr<Thread> SetupIdleThread() {
// We need to pass a few valid values to get around parameter checking in Thread::Create.
- auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
- THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE);
- _dbg_assert_(Kernel, thread_res.Succeeded());
- SharedPtr<Thread> thread = std::move(*thread_res);
+ auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
+ THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE).MoveFrom();
thread->idle = true;
CallThread(thread.get());
- return thread->GetHandle();
+ return thread;
}
SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) {
@@ -460,13 +457,13 @@ void Reschedule() {
HLE::g_reschedule = false;
if (next != nullptr) {
- LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
+ LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId());
SwitchContext(next);
} else {
- LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
+ LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId());
for (auto& thread : thread_list) {
- LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(),
+ LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),
thread->current_priority, thread->status);
}
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index d6299364a..633bb7c98 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -7,6 +7,8 @@
#include <string>
#include <vector>
+#include <boost/container/flat_set.hpp>
+
#include "common/common_types.h"
#include "core/core.h"
@@ -40,6 +42,8 @@ enum ThreadStatus {
namespace Kernel {
+class Mutex;
+
class Thread final : public WaitObject {
public:
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
@@ -78,6 +82,12 @@ public:
void ResumeFromWait();
/**
+ * Schedules an event to wake up the specified thread after the specified delay.
+ * @param nanoseconds The time this thread will be allowed to sleep for.
+ */
+ void WakeAfterDelay(s64 nanoseconds);
+
+ /**
* Sets the result after the thread awakens (from either WaitSynchronization SVC)
* @param result Value to set to the returned result
*/
@@ -103,8 +113,10 @@ public:
s32 processor_id;
- std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
+ /// Mutexes currently held by this thread, which will be released when it exits.
+ boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
+ std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
bool wait_all; ///< True if the thread is waiting on all objects before resuming
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
@@ -115,9 +127,15 @@ public:
bool idle = false;
private:
- Thread() = default;
+ Thread();
+ ~Thread() override;
+
+ /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
+ Handle callback_handle;
};
+extern SharedPtr<Thread> g_main_thread;
+
/// Sets up the primary application thread
SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);
@@ -151,19 +169,12 @@ void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bo
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
- * Schedules an event to wake up the specified thread after the specified delay.
- * @param handle The thread handle.
- * @param nanoseconds The time this thread will be allowed to sleep for.
- */
-void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds);
-
-/**
* Sets up the idle thread, this is a thread that is intended to never execute instructions,
* only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
* and will try to yield on every call.
* @returns The handle of the idle thread
*/
-Handle SetupIdleThread();
+SharedPtr<Thread> SetupIdleThread();
/// Initialize threading
void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 503a5d2ce..4352fc99c 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -2,8 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <set>
-
#include "common/common.h"
#include "core/core_timing.h"
@@ -15,18 +13,24 @@ namespace Kernel {
/// The event type of the generic timer callback event
static int timer_callback_event_type = -1;
+// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
+// us to simply use a pool index or similar.
+static Kernel::HandleTable timer_callback_handle_table;
+
+Timer::Timer() {}
+Timer::~Timer() {}
-ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) {
+SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
SharedPtr<Timer> timer(new Timer);
- // TOOD(yuriks): Don't create Handle (see Thread::Create())
- CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer));
timer->reset_type = reset_type;
timer->signaled = false;
timer->name = std::move(name);
timer->initial_delay = 0;
timer->interval_delay = 0;
- return MakeResult<SharedPtr<Timer>>(timer);
+ timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom();
+
+ return timer;
}
bool Timer::ShouldWait() {
@@ -38,17 +42,19 @@ void Timer::Acquire() {
}
void Timer::Set(s64 initial, s64 interval) {
+ // Ensure we get rid of any previous scheduled event
+ Cancel();
+
initial_delay = initial;
interval_delay = interval;
u64 initial_microseconds = initial / 1000;
- // TODO(yuriks): Figure out a replacement for GetHandle here
- CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
- GetHandle());
+ CoreTiming::ScheduleEvent(usToCycles(initial_microseconds),
+ timer_callback_event_type, callback_handle);
}
void Timer::Cancel() {
- CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle());
+ CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
}
void Timer::Clear() {
@@ -57,7 +63,7 @@ void Timer::Clear() {
/// The timer callback event, called when a timer is fired
static void TimerCallback(u64 timer_handle, int cycles_late) {
- SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle);
+ SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(timer_handle);
if (timer == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle);
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index c45e79954..540e4e187 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -19,7 +19,7 @@ public:
* @param name Optional name of timer
* @return The created Timer
*/
- static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown");
+ static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown");
std::string GetTypeName() const override { return "Timer"; }
std::string GetName() const override { return name; }
@@ -49,7 +49,11 @@ public:
void Clear();
private:
- Timer() = default;
+ Timer();
+ ~Timer() override;
+
+ /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
+ Handle callback_handle;
};
/// Initializes the required variables for timers