diff options
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 97 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 22 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 4 |
6 files changed, 76 insertions, 111 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 37eec4c84..b5a0cc3a3 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -79,8 +79,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 79 | ErrorSummary::WrongArgument, ErrorLevel::Usage); | 79 | ErrorSummary::WrongArgument, ErrorLevel::Usage); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | HLE::Reschedule(__func__); | ||
| 83 | |||
| 84 | // The calls that use a timeout seem to always return a Timeout error even if they did not put | 82 | // The calls that use a timeout seem to always return a Timeout error even if they did not put |
| 85 | // the thread to sleep | 83 | // the thread to sleep |
| 86 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || | 84 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0c8752670..be7a5a6d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -31,13 +31,62 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||
| 31 | waiting_threads.erase(itr); | 31 | waiting_threads.erase(itr); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | void WaitObject::WakeupAllWaitingThreads() { | 34 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { |
| 35 | for (auto thread : waiting_threads) | 35 | // Remove the threads that are ready or already running from our waitlist |
| 36 | thread->ResumeFromWait(); | 36 | waiting_threads.erase(std::remove_if(waiting_threads.begin(), waiting_threads.end(), [](SharedPtr<Thread> thread) -> bool { |
| 37 | return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY; | ||
| 38 | }), waiting_threads.end()); | ||
| 39 | |||
| 40 | if (waiting_threads.empty()) | ||
| 41 | return nullptr; | ||
| 37 | 42 | ||
| 38 | waiting_threads.clear(); | 43 | auto candidate_threads = waiting_threads; |
| 39 | 44 | ||
| 40 | HLE::Reschedule(__func__); | 45 | // Eliminate all threads that are waiting on more than one object, and not all of them are ready |
| 46 | candidate_threads.erase(std::remove_if(candidate_threads.begin(), candidate_threads.end(), [](SharedPtr<Thread> thread) -> bool { | ||
| 47 | for (auto object : thread->wait_objects) | ||
| 48 | if (object->ShouldWait()) | ||
| 49 | return true; | ||
| 50 | return false; | ||
| 51 | }), candidate_threads.end()); | ||
| 52 | |||
| 53 | // Return the thread with the lowest priority value (The one with the highest priority) | ||
| 54 | auto thread_itr = std::min_element(candidate_threads.begin(), candidate_threads.end(), [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { | ||
| 55 | return lhs->current_priority < rhs->current_priority; | ||
| 56 | }); | ||
| 57 | |||
| 58 | if (thread_itr == candidate_threads.end()) | ||
| 59 | return nullptr; | ||
| 60 | |||
| 61 | return *thread_itr; | ||
| 62 | } | ||
| 63 | |||
| 64 | void WaitObject::WakeupAllWaitingThreads() { | ||
| 65 | // Wake up all threads that can be awoken, in priority order | ||
| 66 | while (auto thread = GetHighestPriorityReadyThread()) { | ||
| 67 | if (thread->wait_objects.empty()) { | ||
| 68 | Acquire(); | ||
| 69 | // Set the output index of the WaitSynchronizationN call to the index of this object. | ||
| 70 | if (thread->wait_set_output) { | ||
| 71 | thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); | ||
| 72 | thread->wait_set_output = false; | ||
| 73 | } | ||
| 74 | } else { | ||
| 75 | for (auto object : thread->wait_objects) { | ||
| 76 | object->Acquire(); | ||
| 77 | // Remove the thread from the object's waitlist | ||
| 78 | object->RemoveWaitingThread(thread.get()); | ||
| 79 | } | ||
| 80 | // Note: This case doesn't update the output index of WaitSynchronizationN. | ||
| 81 | // Clear the thread's waitlist | ||
| 82 | thread->wait_objects.clear(); | ||
| 83 | } | ||
| 84 | |||
| 85 | // Set the result of the call to WaitSynchronization to RESULT_SUCCESS | ||
| 86 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 87 | thread->ResumeFromWait(); | ||
| 88 | // Note: Removing the thread from the object's waitlist will be done by GetHighestPriorityReadyThread | ||
| 89 | } | ||
| 41 | } | 90 | } |
| 42 | 91 | ||
| 43 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { | 92 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 231cf7b75..eb5a3bf7e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -155,6 +155,9 @@ public: | |||
| 155 | /// Wake up all threads waiting on this object | 155 | /// Wake up all threads waiting on this object |
| 156 | void WakeupAllWaitingThreads(); | 156 | void WakeupAllWaitingThreads(); |
| 157 | 157 | ||
| 158 | /// Obtains the highest priority thread that is ready to run from this object's waiting list. | ||
| 159 | SharedPtr<Thread> GetHighestPriorityReadyThread(); | ||
| 160 | |||
| 158 | /// Get a const reference to the waiting threads list for debug use | 161 | /// Get a const reference to the waiting threads list for debug use |
| 159 | const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; | 162 | const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; |
| 160 | 163 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 84d6d24c6..49ed9d899 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -120,8 +120,6 @@ void Thread::Stop() { | |||
| 120 | u32 tls_slot = | 120 | u32 tls_slot = |
| 121 | ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | 121 | ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; |
| 122 | Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); | 122 | Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); |
| 123 | |||
| 124 | HLE::Reschedule(__func__); | ||
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | Thread* ArbitrateHighestPriorityThread(u32 address) { | 125 | Thread* ArbitrateHighestPriorityThread(u32 address) { |
| @@ -181,50 +179,6 @@ static void PriorityBoostStarvedThreads() { | |||
| 181 | } | 179 | } |
| 182 | 180 | ||
| 183 | /** | 181 | /** |
| 184 | * Gets the registers for timeout parameter of the next WaitSynchronization call. | ||
| 185 | * @param thread a pointer to the thread that is ready to call WaitSynchronization | ||
| 186 | * @returns a tuple of two register pointers to low and high part of the timeout parameter | ||
| 187 | */ | ||
| 188 | static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) { | ||
| 189 | bool thumb_mode = (thread->context.cpsr & TBIT) != 0; | ||
| 190 | u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE); | ||
| 191 | u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF; | ||
| 192 | |||
| 193 | if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { | ||
| 194 | // svc #0x24 (WaitSynchronization1) | ||
| 195 | return std::make_tuple(&thread->context.cpu_registers[2], | ||
| 196 | &thread->context.cpu_registers[3]); | ||
| 197 | } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { | ||
| 198 | // svc #0x25 (WaitSynchronizationN) | ||
| 199 | return std::make_tuple(&thread->context.cpu_registers[0], | ||
| 200 | &thread->context.cpu_registers[4]); | ||
| 201 | } | ||
| 202 | |||
| 203 | UNREACHABLE(); | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Updates the WaitSynchronization timeout parameter according to the difference | ||
| 208 | * between ticks of the last WaitSynchronization call and the incoming one. | ||
| 209 | * @param timeout_low a pointer to the register for the low part of the timeout parameter | ||
| 210 | * @param timeout_high a pointer to the register for the high part of the timeout parameter | ||
| 211 | * @param last_tick tick of the last WaitSynchronization call | ||
| 212 | */ | ||
| 213 | static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) { | ||
| 214 | s64 timeout = ((s64)*timeout_high << 32) | *timeout_low; | ||
| 215 | |||
| 216 | if (timeout != -1) { | ||
| 217 | timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds | ||
| 218 | |||
| 219 | if (timeout < 0) | ||
| 220 | timeout = 0; | ||
| 221 | |||
| 222 | *timeout_low = timeout & 0xFFFFFFFF; | ||
| 223 | *timeout_high = timeout >> 32; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Switches the CPU's active thread context to that of the specified thread | 182 | * Switches the CPU's active thread context to that of the specified thread |
| 229 | * @param new_thread The thread to switch to | 183 | * @param new_thread The thread to switch to |
| 230 | */ | 184 | */ |
| @@ -254,32 +208,6 @@ static void SwitchContext(Thread* new_thread) { | |||
| 254 | 208 | ||
| 255 | current_thread = new_thread; | 209 | current_thread = new_thread; |
| 256 | 210 | ||
| 257 | // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun | ||
| 258 | // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire | ||
| 259 | // the requested wait object(s) before continuing. | ||
| 260 | if (new_thread->waitsynch_waited) { | ||
| 261 | // CPSR flag indicates CPU mode | ||
| 262 | bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0; | ||
| 263 | |||
| 264 | // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM | ||
| 265 | new_thread->context.pc -= thumb_mode ? 2 : 4; | ||
| 266 | |||
| 267 | // Get the register for timeout parameter | ||
| 268 | u32 *timeout_low, *timeout_high; | ||
| 269 | std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); | ||
| 270 | |||
| 271 | // Update the timeout parameter | ||
| 272 | UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks); | ||
| 273 | } | ||
| 274 | |||
| 275 | // Clean up the thread's wait_objects, they'll be restored if needed during | ||
| 276 | // the svcWaitSynchronization call | ||
| 277 | for (size_t i = 0; i < new_thread->wait_objects.size(); ++i) { | ||
| 278 | SharedPtr<WaitObject> object = new_thread->wait_objects[i]; | ||
| 279 | object->RemoveWaitingThread(new_thread); | ||
| 280 | } | ||
| 281 | new_thread->wait_objects.clear(); | ||
| 282 | |||
| 283 | ready_queue.remove(new_thread->current_priority, new_thread); | 211 | ready_queue.remove(new_thread->current_priority, new_thread); |
| 284 | new_thread->status = THREADSTATUS_RUNNING; | 212 | new_thread->status = THREADSTATUS_RUNNING; |
| 285 | 213 | ||
| @@ -319,17 +247,13 @@ static Thread* PopNextReadyThread() { | |||
| 319 | void WaitCurrentThread_Sleep() { | 247 | void WaitCurrentThread_Sleep() { |
| 320 | Thread* thread = GetCurrentThread(); | 248 | Thread* thread = GetCurrentThread(); |
| 321 | thread->status = THREADSTATUS_WAIT_SLEEP; | 249 | thread->status = THREADSTATUS_WAIT_SLEEP; |
| 322 | |||
| 323 | HLE::Reschedule(__func__); | ||
| 324 | } | 250 | } |
| 325 | 251 | ||
| 326 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, | 252 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, |
| 327 | bool wait_set_output, bool wait_all) { | 253 | bool wait_set_output) { |
| 328 | Thread* thread = GetCurrentThread(); | 254 | Thread* thread = GetCurrentThread(); |
| 329 | thread->wait_set_output = wait_set_output; | 255 | thread->wait_set_output = wait_set_output; |
| 330 | thread->wait_all = wait_all; | ||
| 331 | thread->wait_objects = std::move(wait_objects); | 256 | thread->wait_objects = std::move(wait_objects); |
| 332 | thread->waitsynch_waited = true; | ||
| 333 | thread->status = THREADSTATUS_WAIT_SYNCH; | 257 | thread->status = THREADSTATUS_WAIT_SYNCH; |
| 334 | } | 258 | } |
| 335 | 259 | ||
| @@ -351,15 +275,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 351 | return; | 275 | return; |
| 352 | } | 276 | } |
| 353 | 277 | ||
| 354 | thread->waitsynch_waited = false; | ||
| 355 | |||
| 356 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { | 278 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { |
| 279 | thread->wait_set_output = false; | ||
| 357 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 280 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, |
| 358 | ErrorSummary::StatusChanged, | 281 | ErrorSummary::StatusChanged, |
| 359 | ErrorLevel::Info)); | 282 | ErrorLevel::Info)); |
| 360 | |||
| 361 | if (thread->wait_set_output) | ||
| 362 | thread->SetWaitSynchronizationOutput(-1); | ||
| 363 | } | 283 | } |
| 364 | 284 | ||
| 365 | thread->ResumeFromWait(); | 285 | thread->ResumeFromWait(); |
| @@ -399,6 +319,7 @@ void Thread::ResumeFromWait() { | |||
| 399 | 319 | ||
| 400 | ready_queue.push_back(current_priority, this); | 320 | ready_queue.push_back(current_priority, this); |
| 401 | status = THREADSTATUS_READY; | 321 | status = THREADSTATUS_READY; |
| 322 | HLE::Reschedule(__func__); | ||
| 402 | } | 323 | } |
| 403 | 324 | ||
| 404 | /** | 325 | /** |
| @@ -494,13 +415,11 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 494 | thread->last_running_ticks = CoreTiming::GetTicks(); | 415 | thread->last_running_ticks = CoreTiming::GetTicks(); |
| 495 | thread->processor_id = processor_id; | 416 | thread->processor_id = processor_id; |
| 496 | thread->wait_set_output = false; | 417 | thread->wait_set_output = false; |
| 497 | thread->wait_all = false; | ||
| 498 | thread->wait_objects.clear(); | 418 | thread->wait_objects.clear(); |
| 499 | thread->wait_address = 0; | 419 | thread->wait_address = 0; |
| 500 | thread->name = std::move(name); | 420 | thread->name = std::move(name); |
| 501 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); | 421 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); |
| 502 | thread->owner_process = g_current_process; | 422 | thread->owner_process = g_current_process; |
| 503 | thread->waitsynch_waited = false; | ||
| 504 | 423 | ||
| 505 | // Find the next available TLS index, and mark it as used | 424 | // Find the next available TLS index, and mark it as used |
| 506 | auto& tls_slots = Kernel::g_current_process->tls_slots; | 425 | auto& tls_slots = Kernel::g_current_process->tls_slots; |
| @@ -555,8 +474,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 555 | ready_queue.push_back(thread->current_priority, thread.get()); | 474 | ready_queue.push_back(thread->current_priority, thread.get()); |
| 556 | thread->status = THREADSTATUS_READY; | 475 | thread->status = THREADSTATUS_READY; |
| 557 | 476 | ||
| 558 | HLE::Reschedule(__func__); | ||
| 559 | |||
| 560 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); | 477 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); |
| 561 | } | 478 | } |
| 562 | 479 | ||
| @@ -619,14 +536,6 @@ void Reschedule() { | |||
| 619 | 536 | ||
| 620 | HLE::DoneRescheduling(); | 537 | HLE::DoneRescheduling(); |
| 621 | 538 | ||
| 622 | // Don't bother switching to the same thread. | ||
| 623 | // But if the thread was waiting on objects, we still need to switch it | ||
| 624 | // to perform PC modification, change state to RUNNING, etc. | ||
| 625 | // This occurs in the case when an object the thread is waiting on immediately wakes up | ||
| 626 | // the current thread before Reschedule() is called. | ||
| 627 | if (next == cur && (next == nullptr || next->waitsynch_waited == false)) | ||
| 628 | return; | ||
| 629 | |||
| 630 | if (cur && next) { | 539 | if (cur && next) { |
| 631 | LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); | 540 | LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); |
| 632 | } else if (cur) { | 541 | } else if (cur) { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e0ffcea8a..63b97b74f 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <unordered_map> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include <boost/container/flat_set.hpp> | 10 | #include <boost/container/flat_set.hpp> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -125,6 +126,16 @@ public: | |||
| 125 | void SetWaitSynchronizationOutput(s32 output); | 126 | void SetWaitSynchronizationOutput(s32 output); |
| 126 | 127 | ||
| 127 | /** | 128 | /** |
| 129 | * Retrieves the index that this particular object occupies in the list of objects | ||
| 130 | * that the thread passed to WaitSynchronizationN. | ||
| 131 | * It is used to set the output value of WaitSynchronizationN when the thread is awakened. | ||
| 132 | * @param object Object to query the index of. | ||
| 133 | */ | ||
| 134 | s32 GetWaitObjectIndex(WaitObject* object) { | ||
| 135 | return wait_objects_index[object->GetObjectId()]; | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 128 | * Stops a thread, invalidating it from further use | 139 | * Stops a thread, invalidating it from further use |
| 129 | */ | 140 | */ |
| 130 | void Stop(); | 141 | void Stop(); |
| @@ -154,16 +165,16 @@ public: | |||
| 154 | 165 | ||
| 155 | VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread | 166 | VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread |
| 156 | 167 | ||
| 157 | bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait | ||
| 158 | |||
| 159 | /// Mutexes currently held by this thread, which will be released when it exits. | 168 | /// Mutexes currently held by this thread, which will be released when it exits. |
| 160 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; | 169 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; |
| 161 | 170 | ||
| 162 | SharedPtr<Process> owner_process; ///< Process that owns this thread | 171 | SharedPtr<Process> owner_process; ///< Process that owns this thread |
| 163 | std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on | 172 | std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on |
| 173 | std::unordered_map<int, s32> wait_objects_index; ///< Mapping of Object ids to their position in the last waitlist that this object waited on. | ||
| 174 | |||
| 164 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address | 175 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address |
| 165 | bool wait_all; ///< True if the thread is waiting on all objects before resuming | 176 | |
| 166 | bool wait_set_output; ///< True if the output parameter should be set on thread wakeup | 177 | bool wait_set_output; ///< True if the WaitSynchronizationN output parameter should be set on thread wakeup |
| 167 | 178 | ||
| 168 | std::string name; | 179 | std::string name; |
| 169 | 180 | ||
| @@ -215,10 +226,9 @@ void WaitCurrentThread_Sleep(); | |||
| 215 | * @param wait_objects Kernel objects that we are waiting on | 226 | * @param wait_objects Kernel objects that we are waiting on |
| 216 | * @param wait_set_output If true, set the output parameter on thread wakeup (for | 227 | * @param wait_set_output If true, set the output parameter on thread wakeup (for |
| 217 | * WaitSynchronizationN only) | 228 | * WaitSynchronizationN only) |
| 218 | * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) | ||
| 219 | */ | 229 | */ |
| 220 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, | 230 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, |
| 221 | bool wait_set_output, bool wait_all); | 231 | bool wait_set_output); |
| 222 | 232 | ||
| 223 | /** | 233 | /** |
| 224 | * Waits the current thread from an ArbitrateAddress call | 234 | * Waits the current thread from an ArbitrateAddress call |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index eac181f4e..b50cf520d 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -60,14 +60,10 @@ void Timer::Set(s64 initial, s64 interval) { | |||
| 60 | u64 initial_microseconds = initial / 1000; | 60 | u64 initial_microseconds = initial / 1000; |
| 61 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, | 61 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, |
| 62 | callback_handle); | 62 | callback_handle); |
| 63 | |||
| 64 | HLE::Reschedule(__func__); | ||
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | void Timer::Cancel() { | 65 | void Timer::Cancel() { |
| 68 | CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); | 66 | CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); |
| 69 | |||
| 70 | HLE::Reschedule(__func__); | ||
| 71 | } | 67 | } |
| 72 | 68 | ||
| 73 | void Timer::Clear() { | 69 | void Timer::Clear() { |