summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/thread.h4
-rw-r--r--src/core/core_timing.cpp38
2 files changed, 31 insertions, 11 deletions
diff --git a/src/common/thread.h b/src/common/thread.h
index 1552f58e0..e17a7850f 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -54,6 +54,10 @@ public:
54 is_set = false; 54 is_set = false;
55 } 55 }
56 56
57 [[nodiscard]] bool IsSet() {
58 return is_set;
59 }
60
57private: 61private:
58 std::condition_variable condvar; 62 std::condition_variable condvar;
59 std::mutex mutex; 63 std::mutex mutex;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 2dbb99c8b..b45c1b918 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -243,17 +243,17 @@ std::optional<s64> CoreTiming::Advance() {
243 basic_lock.lock(); 243 basic_lock.lock();
244 244
245 if (evt.reschedule_time != 0) { 245 if (evt.reschedule_time != 0) {
246 const auto next_schedule_time{new_schedule_time.has_value()
247 ? new_schedule_time.value().count()
248 : evt.reschedule_time};
249
246 // If this event was scheduled into a pause, its time now is going to be way behind. 250 // If this event was scheduled into a pause, its time now is going to be way behind.
247 // Re-set this event to continue from the end of the pause. 251 // Re-set this event to continue from the end of the pause.
248 auto next_time{evt.time + evt.reschedule_time}; 252 auto next_time{evt.time + next_schedule_time};
249 if (evt.time < pause_end_time) { 253 if (evt.time < pause_end_time) {
250 next_time = pause_end_time + evt.reschedule_time; 254 next_time = pause_end_time + next_schedule_time;
251 } 255 }
252 256
253 const auto next_schedule_time{new_schedule_time.has_value()
254 ? new_schedule_time.value().count()
255 : evt.reschedule_time};
256
257 event_queue.emplace_back( 257 event_queue.emplace_back(
258 Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); 258 Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
259 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 259 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
@@ -264,8 +264,7 @@ std::optional<s64> CoreTiming::Advance() {
264 } 264 }
265 265
266 if (!event_queue.empty()) { 266 if (!event_queue.empty()) {
267 const s64 next_time = event_queue.front().time - global_timer; 267 return event_queue.front().time;
268 return next_time;
269 } else { 268 } else {
270 return std::nullopt; 269 return std::nullopt;
271 } 270 }
@@ -278,11 +277,28 @@ void CoreTiming::ThreadLoop() {
278 paused_set = false; 277 paused_set = false;
279 const auto next_time = Advance(); 278 const auto next_time = Advance();
280 if (next_time) { 279 if (next_time) {
281 if (*next_time > 0) { 280 // There are more events left in the queue, sleep until the next event.
282 std::chrono::nanoseconds next_time_ns = std::chrono::nanoseconds(*next_time); 281 const auto diff_ns{*next_time - GetGlobalTimeNs().count()};
283 event.WaitFor(next_time_ns); 282 if (diff_ns > 0) {
283 // Only try to sleep if the remaining time is >= 1ms. Take off 500 microseconds
284 // from the target time to account for possible over-sleeping, and spin the
285 // remaining.
286 const auto sleep_time_ns{diff_ns - 500LL * 1'000LL};
287 const auto sleep_time_ms{sleep_time_ns / 1'000'000LL};
288 if (sleep_time_ms >= 1) {
289 event.WaitFor(std::chrono::nanoseconds(sleep_time_ns));
290 }
291
292 const auto end_time{std::chrono::nanoseconds(*next_time)};
293 while (!paused && !event.IsSet() && GetGlobalTimeNs() < end_time) {
294 }
295
296 if (event.IsSet()) {
297 event.Reset();
298 }
284 } 299 }
285 } else { 300 } else {
301 // Queue is empty, wait until another event is scheduled and signals us to continue.
286 wait_set = true; 302 wait_set = true;
287 event.Wait(); 303 event.Wait();
288 } 304 }