Skip to content

Commit a849ecf

Browse files
authored
Requeue some external messages if their queues were full to prevent game lockups (#125)
1 parent df7e820 commit a849ecf

7 files changed

Lines changed: 38 additions & 28 deletions

File tree

librecomp/src/flash.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
154154
}
155155

156156
// Send the message indicating write completion
157-
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
157+
ultramodern::enqueue_external_message(mq, 0, false, true);
158158

159159
ctx->r2 = 0;
160160
}
@@ -193,7 +193,7 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
193193
save_read(PASS_RDRAM dramAddr, offset, count);
194194

195195
// Send the message indicating read completion
196-
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
196+
ultramodern::enqueue_external_message(mq, 0, false, true);
197197

198198
ctx->r2 = 0;
199199
}

librecomp/src/pi.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
275275
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
276276

277277
// Send a message to the mq to indicate that the transfer completed
278-
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
278+
ultramodern::enqueue_external_message(mq, 0, false, true);
279279
} else if (physical_addr >= recomp::sram_base) {
280280
if (!recomp::sram_allowed()) {
281281
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
@@ -285,7 +285,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
285285
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
286286

287287
// Send a message to the mq to indicate that the transfer completed
288-
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
288+
ultramodern::enqueue_external_message(mq, 0, false, true);
289289
} else {
290290
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
291291
}
@@ -302,7 +302,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
302302
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
303303

304304
// Send a message to the mq to indicate that the transfer completed
305-
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
305+
ultramodern::enqueue_external_message(mq, 0, false, true);
306306
} else {
307307
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
308308
}

ultramodern/include/ultramodern/ultramodern.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue);
5252
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
5353

5454
// Message queues.
55+
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked);
5556
void wait_for_external_message(RDRAM_ARG1);
5657
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
5758

@@ -77,7 +78,7 @@ PTR(OSThread) this_thread();
7778
void set_main_thread();
7879
bool is_game_thread();
7980
void submit_rsp_task(RDRAM_ARG PTR(OSTask) task);
80-
void send_si_message(RDRAM_ARG1);
81+
void send_si_message();
8182
uint32_t get_speed_multiplier();
8283

8384
// Time

ultramodern/src/events.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -226,21 +226,19 @@ void vi_thread_func() {
226226
if (ultramodern::is_game_started()) {
227227
remaining_retraces--;
228228

229-
uint8_t* rdram = events_context.rdram;
230229
std::lock_guard lock{ events_context.message_mutex };
231230
ViState* cur_state = events_context.vi.get_cur_state();
232231
if (remaining_retraces == 0) {
233232
if (cur_state->mq != NULLPTR) {
234-
if (osSendMesg(PASS_RDRAM cur_state->mq, cur_state->msg, OS_MESG_NOBLOCK) == -1) {
235-
//printf("Game skipped a VI frame!\n");
236-
}
233+
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
234+
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
235+
ultramodern::enqueue_external_message(cur_state->mq, cur_state->msg, false, false);
237236
}
238237
remaining_retraces = cur_state->retrace_count;
239238
}
240239
if (events_context.ai.mq != NULLPTR) {
241-
if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) {
242-
//printf("Game skipped a AI frame!\n");
243-
}
240+
// Send a message to the VI queue, and do not set it to be requeued if the queue was full for the same reason as the VI message above.
241+
ultramodern::enqueue_external_message(events_context.ai.mq, events_context.ai.msg, false, false);
244242
}
245243
}
246244

@@ -253,13 +251,13 @@ void vi_thread_func() {
253251
void sp_complete() {
254252
uint8_t* rdram = events_context.rdram;
255253
std::lock_guard lock{ events_context.message_mutex };
256-
osSendMesg(PASS_RDRAM events_context.sp.mq, events_context.sp.msg, OS_MESG_NOBLOCK);
254+
ultramodern::enqueue_external_message(events_context.sp.mq, events_context.sp.msg, false, true);
257255
}
258256

259257
void dp_complete() {
260258
uint8_t* rdram = events_context.rdram;
261259
std::lock_guard lock{ events_context.message_mutex };
262-
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
260+
ultramodern::enqueue_external_message(events_context.dp.mq, events_context.dp.msg, false, true);
263261
}
264262

265263
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
@@ -559,8 +557,8 @@ void ultramodern::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
559557
}
560558
}
561559

562-
void ultramodern::send_si_message(RDRAM_ARG1) {
563-
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
560+
void ultramodern::send_si_message() {
561+
ultramodern::enqueue_external_message(events_context.si.mq, events_context.si.msg, false, true);
564562
}
565563

566564
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {

ultramodern/src/input.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ extern "C" s32 osContReset(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(OSContStatus) data
9898
}
9999

100100
extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) {
101-
ultramodern::send_si_message(PASS_RDRAM1);
101+
ultramodern::send_si_message();
102102

103103
return 0;
104104
}
@@ -109,7 +109,7 @@ extern "C" s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue) mq) {
109109
}
110110
update_poll_time();
111111

112-
ultramodern::send_si_message(rdram);
112+
ultramodern::send_si_message();
113113

114114
return 0;
115115
}

ultramodern/src/mesgqueue.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,44 @@ struct QueuedMessage {
99
PTR(OSMesgQueue) mq;
1010
OSMesg mesg;
1111
bool jam;
12+
bool requeue_if_blocked;
1213
};
1314

1415
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
1516

16-
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam) {
17-
external_messages.enqueue({mq, msg, jam});
17+
void ultramodern::enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked) {
18+
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});
1819
}
1920

2021
bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block);
2122

2223
void dequeue_external_messages(RDRAM_ARG1) {
2324
QueuedMessage to_send;
25+
std::vector<QueuedMessage> requeued_messages{};
2426
while (external_messages.try_dequeue(to_send)) {
25-
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
27+
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
28+
requeued_messages.push_back(to_send);
29+
}
30+
}
31+
for (QueuedMessage& cur_mesg : requeued_messages) {
32+
external_messages.enqueue(cur_mesg);
2633
}
2734
}
2835

2936
void ultramodern::wait_for_external_message(RDRAM_ARG1) {
3037
QueuedMessage to_send;
3138
external_messages.wait_dequeue(to_send);
32-
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
39+
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
40+
external_messages.enqueue(to_send);
41+
}
3342
}
3443

35-
void ultramodern::wait_for_external_message_timed(RDRAM_ARG1, u32 millis) {
44+
void ultramodern::wait_for_external_message_timed(RDRAM_ARG u32 millis) {
3645
QueuedMessage to_send;
3746
if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{millis})) {
38-
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
47+
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
48+
external_messages.enqueue(to_send);
49+
}
3950
}
4051
}
4152

@@ -138,7 +149,7 @@ extern "C" s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags)
138149

139150
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
140151
if (!ultramodern::is_game_thread()) {
141-
enqueue_external_message(mq_, msg, jam);
152+
ultramodern::enqueue_external_message(mq_, msg, jam, false);
142153
return 0;
143154
}
144155

@@ -160,7 +171,7 @@ extern "C" s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags)
160171

161172
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
162173
if (!ultramodern::is_game_thread()) {
163-
enqueue_external_message(mq_, msg, jam);
174+
ultramodern::enqueue_external_message(mq_, msg, jam, false);
164175
return 0;
165176
}
166177

ultramodern/src/timer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ void timer_thread(RDRAM_ARG1) {
130130
}
131131
else {
132132
// Waiting for the timer completed, so send the timer's message to its message queue
133-
osSendMesg(PASS_RDRAM cur_timer->mq, cur_timer->msg, OS_MESG_NOBLOCK);
133+
ultramodern::enqueue_external_message(cur_timer->mq, cur_timer->msg, false, true);
134134
// If the timer has a specified interval then reload it with that value
135135
if (cur_timer->interval != 0) {
136136
cur_timer->timestamp = cur_timer->interval + time_now();

0 commit comments

Comments
 (0)