summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis-deps.sh2
-rw-r--r--.travis.yml5
-rw-r--r--src/core/hle/kernel/kernel.h12
-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, 58 insertions, 24 deletions
diff --git a/.travis-deps.sh b/.travis-deps.sh
index 8e22a6358..b978e552e 100644
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -20,6 +20,8 @@ if [ "$TRAVIS_OS_NAME" = linux -o -z "$TRAVIS_OS_NAME" ]; then
20 curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \ 20 curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \
21 | sudo tar -xz -C /usr/local --strip-components=1 21 | sudo tar -xz -C /usr/local --strip-components=1
22elif [ "$TRAVIS_OS_NAME" = osx ]; then 22elif [ "$TRAVIS_OS_NAME" = osx ]; then
23 export HOMEBREW_CACHE="$PWD/.homebrew-cache"
24 mkdir -p "$HOMEBREW_CACHE"
23 brew tap homebrew/versions 25 brew tap homebrew/versions
24 brew install qt5 glfw3 pkgconfig 26 brew install qt5 glfw3 pkgconfig
25fi 27fi
diff --git a/.travis.yml b/.travis.yml
index 1cb369d5b..8c5aceb7c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,11 @@ os:
4 4
5language: cpp 5language: cpp
6 6
7cache:
8 apt: true
9 directories:
10 - .homebrew-cache
11
7before_install: 12before_install:
8 - sh .travis-deps.sh 13 - sh .travis-deps.sh
9 14
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;
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17// From kernel.h. Declarations duplicated here to avoid a circular header dependency.
18class Thread;
19Thread* GetCurrentThread();
20
17enum KernelHandle { 21enum KernelHandle {
18 CurrentThread = 0xFFFF8000, 22 CurrentThread = 0xFFFF8000,
19 CurrentProcess = 0xFFFF8001, 23 CurrentProcess = 0xFFFF8001,
@@ -81,6 +85,10 @@ public:
81 85
82 template <class T> 86 template <class T>
83 T* Get(Handle handle) { 87 T* Get(Handle handle) {
88 if (handle == CurrentThread) {
89 return reinterpret_cast<T*>(GetCurrentThread());
90 }
91
84 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 92 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
85 if (handle != 0) { 93 if (handle != 0) {
86 LOG_ERROR(Kernel, "Bad object handle %08x", handle); 94 LOG_ERROR(Kernel, "Bad object handle %08x", handle);
@@ -99,6 +107,10 @@ public:
99 // ONLY use this when you know the handle is valid. 107 // ONLY use this when you know the handle is valid.
100 template <class T> 108 template <class T>
101 T *GetFast(Handle handle) { 109 T *GetFast(Handle handle) {
110 if (handle == CurrentThread) {
111 return reinterpret_cast<T*>(GetCurrentThread());
112 }
113
102 const Handle realHandle = handle - HANDLE_OFFSET; 114 const Handle realHandle = handle - HANDLE_OFFSET;
103 _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); 115 _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
104 return static_cast<T*>(pool[realHandle]); 116 return static_cast<T*>(pool[realHandle]);
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;
83static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup 83static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
84static u32 next_thread_id; ///< The next available thread id 84static u32 next_thread_id; ///< The next available thread id
85 85
86/// Gets the current thread 86Thread* GetCurrentThread() {
87inline Thread* GetCurrentThread() {
88 return current_thread; 87 return current_thread;
89} 88}
90 89
@@ -148,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) {
148 } 147 }
149} 148}
150 149
151/// Verify that a thread has not been released from waiting 150/// Check if a thread is blocking on a specified wait type
152static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { 151static bool CheckWaitType(const Thread* thread, WaitType type) {
153 _dbg_assert_(Kernel, thread != nullptr); 152 return (type == thread->wait_type) && (thread->IsWaiting());
154 return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
155} 153}
156 154
157/// Verify that a thread has not been released from waiting (with wait address) 155/// Check if a thread is blocking on a specified wait type with a specified handle
158static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { 156static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) {
159 _dbg_assert_(Kernel, thread != nullptr); 157 return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle);
160 return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address); 158}
159
160/// Check if a thread is blocking on a specified wait type with a specified handle and address
161static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
162 return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address);
161} 163}
162 164
163/// Stops the current thread 165/// Stops the current thread
@@ -172,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
172 thread->status = THREADSTATUS_DORMANT; 174 thread->status = THREADSTATUS_DORMANT;
173 for (Handle waiting_handle : thread->waiting_threads) { 175 for (Handle waiting_handle : thread->waiting_threads) {
174 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); 176 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
175 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 177
178 if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle))
176 ResumeThreadFromWait(waiting_handle); 179 ResumeThreadFromWait(waiting_handle);
177 }
178 } 180 }
179 thread->waiting_threads.clear(); 181 thread->waiting_threads.clear();
180 182
@@ -210,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
210 for (Handle handle : thread_queue) { 212 for (Handle handle : thread_queue) {
211 Thread* thread = g_object_pool.Get<Thread>(handle); 213 Thread* thread = g_object_pool.Get<Thread>(handle);
212 214
213 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) 215 if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
214 continue; 216 continue;
215 217
216 if (thread == nullptr) 218 if (thread == nullptr)
@@ -235,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
235 for (Handle handle : thread_queue) { 237 for (Handle handle : thread_queue) {
236 Thread* thread = g_object_pool.Get<Thread>(handle); 238 Thread* thread = g_object_pool.Get<Thread>(handle);
237 239
238 if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) 240 if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
239 ResumeThreadFromWait(handle); 241 ResumeThreadFromWait(handle);
240 } 242 }
241} 243}
@@ -306,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) {
306 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); 308 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
307 if (thread) { 309 if (thread) {
308 thread->status &= ~THREADSTATUS_WAIT; 310 thread->status &= ~THREADSTATUS_WAIT;
311 thread->wait_handle = 0;
312 thread->wait_type = WAITTYPE_NONE;
309 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 313 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
310 ChangeReadyState(thread, true); 314 ChangeReadyState(thread, true);
311 } 315 }
@@ -469,19 +473,27 @@ void Reschedule() {
469 Thread* prev = GetCurrentThread(); 473 Thread* prev = GetCurrentThread();
470 Thread* next = NextThread(); 474 Thread* next = NextThread();
471 HLE::g_reschedule = false; 475 HLE::g_reschedule = false;
472 if (next > 0) {
473 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
474 476
477 if (next != nullptr) {
478 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
475 SwitchContext(next); 479 SwitchContext(next);
480 } else {
481 LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
476 482
477 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep 483 for (Handle handle : thread_queue) {
478 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. 484 Thread* thread = g_object_pool.Get<Thread>(handle);
479 // This results in the current thread yielding on a VBLANK once, and then it will be 485 LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
480 // immediately placed back in the queue for execution. 486 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle);
481 if (prev->wait_type == WAITTYPE_VBLANK) {
482 ResumeThreadFromWait(prev->GetHandle());
483 } 487 }
484 } 488 }
489
490 // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put
491 // to sleep. So, we'll just immediately set it to "ready" again after an attempted context
492 // switch has occurred. This results in the current thread yielding on a sleep once, and then it
493 // will immediately be placed back in the queue for execution.
494
495 if (CheckWaitType(prev, WAITTYPE_SLEEP))
496 ResumeThreadFromWait(prev->GetHandle());
485} 497}
486 498
487ResultCode GetThreadId(u32* thread_id, Handle handle) { 499ResultCode 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 {
40 WAITTYPE_SEMA, 40 WAITTYPE_SEMA,
41 WAITTYPE_EVENT, 41 WAITTYPE_EVENT,
42 WAITTYPE_THREADEND, 42 WAITTYPE_THREADEND,
43 WAITTYPE_VBLANK,
44 WAITTYPE_MUTEX, 43 WAITTYPE_MUTEX,
45 WAITTYPE_SYNCH, 44 WAITTYPE_SYNCH,
46 WAITTYPE_ARB, 45 WAITTYPE_ARB,
@@ -78,6 +77,9 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address);
78/// Arbitrate all threads currently waiting... 77/// Arbitrate all threads currently waiting...
79void ArbitrateAllThreads(u32 arbiter, u32 address); 78void ArbitrateAllThreads(u32 arbiter, u32 address);
80 79
80/// Gets the current thread
81Thread* GetCurrentThread();
82
81/// Gets the current thread handle 83/// Gets the current thread handle
82Handle GetCurrentThreadHandle(); 84Handle GetCurrentThreadHandle();
83 85
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) {
352static void SleepThread(s64 nanoseconds) { 352static void SleepThread(s64 nanoseconds) {
353 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); 353 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
354 354
355 // Check for next thread to schedule 355 // Sleep current thread and check for next thread to schedule
356 Kernel::WaitCurrentThread(WAITTYPE_SLEEP);
356 HLE::Reschedule(__func__); 357 HLE::Reschedule(__func__);
357} 358}
358 359