diff options
| -rw-r--r-- | .travis-deps.sh | 2 | ||||
| -rw-r--r-- | .travis.yml | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 3 | 
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      curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \          | sudo tar -xz -C /usr/local --strip-components=1  elif [ "$TRAVIS_OS_NAME" = osx ]; then +    export HOMEBREW_CACHE="$PWD/.homebrew-cache" +    mkdir -p "$HOMEBREW_CACHE"      brew tap homebrew/versions      brew install qt5 glfw3 pkgconfig  fi diff --git a/.travis.yml b/.travis.yml index 1cb369d5b..8c5aceb7c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,11 @@ os:  language: cpp +cache: +  apt: true +  directories: +    - .homebrew-cache +  before_install:   - sh .travis-deps.sh 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/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__);  } | 
