summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/kernel.h12
-rw-r--r--src/core/hle/kernel/semaphore.cpp8
-rw-r--r--src/core/hle/kernel/semaphore.h2
-rw-r--r--src/core/hle/kernel/thread.cpp56
-rw-r--r--src/core/hle/kernel/thread.h4
-rw-r--r--src/core/hle/svc.cpp3
6 files changed, 56 insertions, 29 deletions
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7123485be..683fffeee 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -14,6 +14,10 @@ typedef s32 Result;
namespace Kernel {
+// From kernel.h. Declarations duplicated here to avoid a circular header dependency.
+class Thread;
+Thread* GetCurrentThread();
+
enum KernelHandle {
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
@@ -81,6 +85,10 @@ public:
template <class T>
T* Get(Handle handle) {
+ if (handle == CurrentThread) {
+ return reinterpret_cast<T*>(GetCurrentThread());
+ }
+
if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
if (handle != 0) {
LOG_ERROR(Kernel, "Bad object handle %08x", handle);
@@ -99,6 +107,10 @@ public:
// ONLY use this when you know the handle is valid.
template <class T>
T *GetFast(Handle handle) {
+ if (handle == CurrentThread) {
+ return reinterpret_cast<T*>(GetCurrentThread());
+ }
+
const Handle realHandle = handle - HANDLE_OFFSET;
_dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
return static_cast<T*>(pool[realHandle]);
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 6f56da8a9..f955d1957 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -20,8 +20,8 @@ public:
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Semaphore; }
Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Semaphore; }
- u32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
- u32 available_count; ///< Number of free slots left in the semaphore
+ s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
+ s32 available_count; ///< Number of free slots left in the semaphore
std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
std::string name; ///< Name of semaphore (optional)
@@ -49,8 +49,8 @@ public:
////////////////////////////////////////////////////////////////////////////////////////////////////
-ResultCode CreateSemaphore(Handle* handle, u32 initial_count,
- u32 max_count, const std::string& name) {
+ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
+ s32 max_count, const std::string& name) {
if (initial_count > max_count)
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index f0075fdb8..ad474b875 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -18,7 +18,7 @@ namespace Kernel {
* @param name Optional name of semaphore
* @return ResultCode of the error
*/
-ResultCode CreateSemaphore(Handle* handle, u32 initial_count, u32 max_count, const std::string& name = "Unknown");
+ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown");
/**
* Releases a certain number of slots from a semaphore.
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 1c04701de..834308926 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -83,8 +83,7 @@ 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
-/// Gets the current thread
-inline Thread* GetCurrentThread() {
+Thread* GetCurrentThread() {
return current_thread;
}
@@ -148,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) {
}
}
-/// Verify that a thread has not been released from waiting
-static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
- _dbg_assert_(Kernel, thread != nullptr);
- return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
+/// Check if a thread is blocking on a specified wait type
+static bool CheckWaitType(const Thread* thread, WaitType type) {
+ return (type == thread->wait_type) && (thread->IsWaiting());
}
-/// Verify that a thread has not been released from waiting (with wait address)
-static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
- _dbg_assert_(Kernel, thread != nullptr);
- return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address);
+/// Check if a thread is blocking on a specified wait type with a specified handle
+static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) {
+ return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle);
+}
+
+/// Check if a thread is blocking on a specified wait type with a specified handle and address
+static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
+ return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address);
}
/// Stops the current thread
@@ -172,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
thread->status = THREADSTATUS_DORMANT;
for (Handle waiting_handle : thread->waiting_threads) {
Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
- if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
+
+ if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle))
ResumeThreadFromWait(waiting_handle);
- }
}
thread->waiting_threads.clear();
@@ -210,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
for (Handle handle : thread_queue) {
Thread* thread = g_object_pool.Get<Thread>(handle);
- if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
+ if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
continue;
if (thread == nullptr)
@@ -235,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
for (Handle handle : thread_queue) {
Thread* thread = g_object_pool.Get<Thread>(handle);
- if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
+ if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
ResumeThreadFromWait(handle);
}
}
@@ -306,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) {
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
if (thread) {
thread->status &= ~THREADSTATUS_WAIT;
+ thread->wait_handle = 0;
+ thread->wait_type = WAITTYPE_NONE;
if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
ChangeReadyState(thread, true);
}
@@ -469,19 +473,27 @@ void Reschedule() {
Thread* prev = GetCurrentThread();
Thread* next = NextThread();
HLE::g_reschedule = false;
- if (next > 0) {
- LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
+ if (next != nullptr) {
+ LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
SwitchContext(next);
+ } else {
+ LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
- // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
- // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
- // This results in the current thread yielding on a VBLANK once, and then it will be
- // immediately placed back in the queue for execution.
- if (prev->wait_type == WAITTYPE_VBLANK) {
- ResumeThreadFromWait(prev->GetHandle());
+ for (Handle handle : thread_queue) {
+ Thread* thread = g_object_pool.Get<Thread>(handle);
+ LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
+ thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle);
}
}
+
+ // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put
+ // to sleep. So, we'll just immediately set it to "ready" again after an attempted context
+ // switch has occurred. This results in the current thread yielding on a sleep once, and then it
+ // will immediately be placed back in the queue for execution.
+
+ if (CheckWaitType(prev, WAITTYPE_SLEEP))
+ ResumeThreadFromWait(prev->GetHandle());
}
ResultCode GetThreadId(u32* thread_id, Handle handle) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index be7adface..65e8ef554 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -40,7 +40,6 @@ enum WaitType {
WAITTYPE_SEMA,
WAITTYPE_EVENT,
WAITTYPE_THREADEND,
- WAITTYPE_VBLANK,
WAITTYPE_MUTEX,
WAITTYPE_SYNCH,
WAITTYPE_ARB,
@@ -78,6 +77,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address);
/// Arbitrate all threads currently waiting...
void ArbitrateAllThreads(u32 arbiter, u32 address);
+/// Gets the current thread
+Thread* GetCurrentThread();
+
/// Gets the current thread handle
Handle GetCurrentThreadHandle();
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 47e9bf77e..70ef7839c 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) {
static void SleepThread(s64 nanoseconds) {
LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
- // Check for next thread to schedule
+ // Sleep current thread and check for next thread to schedule
+ Kernel::WaitCurrentThread(WAITTYPE_SLEEP);
HLE::Reschedule(__func__);
}