mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-12-19 14:32:44 +00:00
Requeue some external messages if their queues were full to prevent game lockups
This commit is contained in:
parent
df7e820d8c
commit
a920954404
7 changed files with 38 additions and 28 deletions
|
|
@ -154,7 +154,7 @@ extern "C" void osFlashWriteBuffer_recomp(uint8_t * rdram, recomp_context * ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the message indicating write completion
|
// Send the message indicating write completion
|
||||||
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(mq, 0, false, true);
|
||||||
|
|
||||||
ctx->r2 = 0;
|
ctx->r2 = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ extern "C" void osFlashReadArray_recomp(uint8_t * rdram, recomp_context * ctx) {
|
||||||
save_read(PASS_RDRAM dramAddr, offset, count);
|
save_read(PASS_RDRAM dramAddr, offset, count);
|
||||||
|
|
||||||
// Send the message indicating read completion
|
// Send the message indicating read completion
|
||||||
osSendMesg(PASS_RDRAM mq, 0, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(mq, 0, false, true);
|
||||||
|
|
||||||
ctx->r2 = 0;
|
ctx->r2 = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
|
||||||
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
|
recomp::do_rom_read(rdram, rdram_address, physical_addr, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(mq, 0, false, true);
|
||||||
} else if (physical_addr >= recomp::sram_base) {
|
} else if (physical_addr >= recomp::sram_base) {
|
||||||
if (!recomp::sram_allowed()) {
|
if (!recomp::sram_allowed()) {
|
||||||
ultramodern::error_handling::message_box("Attempted to use SRAM saving with other save type");
|
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_
|
||||||
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
save_read(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(mq, 0, false, true);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
|
fprintf(stderr, "[WARN] PI DMA read from unknown region, phys address 0x%08X\n", physical_addr);
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +302,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
|
||||||
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
save_write(rdram, rdram_address, physical_addr - recomp::sram_base, size);
|
||||||
|
|
||||||
// Send a message to the mq to indicate that the transfer completed
|
// Send a message to the mq to indicate that the transfer completed
|
||||||
osSendMesg(rdram, mq, 0, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(mq, 0, false, true);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
|
fprintf(stderr, "[WARN] PI DMA write to unknown region, phys address 0x%08X\n", physical_addr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ bool thread_queue_empty(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
||||||
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
PTR(OSThread) thread_queue_peek(RDRAM_ARG PTR(PTR(OSThread)) queue);
|
||||||
|
|
||||||
// Message queues.
|
// Message queues.
|
||||||
|
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked);
|
||||||
void wait_for_external_message(RDRAM_ARG1);
|
void wait_for_external_message(RDRAM_ARG1);
|
||||||
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
|
void wait_for_external_message_timed(RDRAM_ARG1, u32 millis);
|
||||||
|
|
||||||
|
|
@ -77,7 +78,7 @@ PTR(OSThread) this_thread();
|
||||||
void set_main_thread();
|
void set_main_thread();
|
||||||
bool is_game_thread();
|
bool is_game_thread();
|
||||||
void submit_rsp_task(RDRAM_ARG PTR(OSTask) task);
|
void submit_rsp_task(RDRAM_ARG PTR(OSTask) task);
|
||||||
void send_si_message(RDRAM_ARG1);
|
void send_si_message();
|
||||||
uint32_t get_speed_multiplier();
|
uint32_t get_speed_multiplier();
|
||||||
|
|
||||||
// Time
|
// Time
|
||||||
|
|
|
||||||
|
|
@ -226,21 +226,19 @@ void vi_thread_func() {
|
||||||
if (ultramodern::is_game_started()) {
|
if (ultramodern::is_game_started()) {
|
||||||
remaining_retraces--;
|
remaining_retraces--;
|
||||||
|
|
||||||
uint8_t* rdram = events_context.rdram;
|
|
||||||
std::lock_guard lock{ events_context.message_mutex };
|
std::lock_guard lock{ events_context.message_mutex };
|
||||||
ViState* cur_state = events_context.vi.get_cur_state();
|
ViState* cur_state = events_context.vi.get_cur_state();
|
||||||
if (remaining_retraces == 0) {
|
if (remaining_retraces == 0) {
|
||||||
if (cur_state->mq != NULLPTR) {
|
if (cur_state->mq != NULLPTR) {
|
||||||
if (osSendMesg(PASS_RDRAM cur_state->mq, cur_state->msg, OS_MESG_NOBLOCK) == -1) {
|
// Send a message to the VI queue, and do not set it to be requeued if the queue was full.
|
||||||
//printf("Game skipped a VI frame!\n");
|
// The worst case scenario is that the game misses a VI message and has to wait a little longer for the next.
|
||||||
}
|
ultramodern::enqueue_external_message(cur_state->mq, cur_state->msg, false, false);
|
||||||
}
|
}
|
||||||
remaining_retraces = cur_state->retrace_count;
|
remaining_retraces = cur_state->retrace_count;
|
||||||
}
|
}
|
||||||
if (events_context.ai.mq != NULLPTR) {
|
if (events_context.ai.mq != NULLPTR) {
|
||||||
if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) {
|
// 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.
|
||||||
//printf("Game skipped a AI frame!\n");
|
ultramodern::enqueue_external_message(events_context.ai.mq, events_context.ai.msg, false, false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,13 +251,13 @@ void vi_thread_func() {
|
||||||
void sp_complete() {
|
void sp_complete() {
|
||||||
uint8_t* rdram = events_context.rdram;
|
uint8_t* rdram = events_context.rdram;
|
||||||
std::lock_guard lock{ events_context.message_mutex };
|
std::lock_guard lock{ events_context.message_mutex };
|
||||||
osSendMesg(PASS_RDRAM events_context.sp.mq, events_context.sp.msg, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(events_context.sp.mq, events_context.sp.msg, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_complete() {
|
void dp_complete() {
|
||||||
uint8_t* rdram = events_context.rdram;
|
uint8_t* rdram = events_context.rdram;
|
||||||
std::lock_guard lock{ events_context.message_mutex };
|
std::lock_guard lock{ events_context.message_mutex };
|
||||||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(events_context.dp.mq, events_context.dp.msg, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
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_) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::send_si_message(RDRAM_ARG1) {
|
void ultramodern::send_si_message() {
|
||||||
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(events_context.si.mq, events_context.si.msg, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
void ultramodern::init_events(RDRAM_ARG ultramodern::renderer::WindowHandle window_handle) {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ extern "C" s32 osContReset(RDRAM_ARG PTR(OSMesgQueue) mq, PTR(OSContStatus) data
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) {
|
extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) {
|
||||||
ultramodern::send_si_message(PASS_RDRAM1);
|
ultramodern::send_si_message();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +109,7 @@ extern "C" s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue) mq) {
|
||||||
}
|
}
|
||||||
update_poll_time();
|
update_poll_time();
|
||||||
|
|
||||||
ultramodern::send_si_message(rdram);
|
ultramodern::send_si_message();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,33 +9,44 @@ struct QueuedMessage {
|
||||||
PTR(OSMesgQueue) mq;
|
PTR(OSMesgQueue) mq;
|
||||||
OSMesg mesg;
|
OSMesg mesg;
|
||||||
bool jam;
|
bool jam;
|
||||||
|
bool requeue_if_blocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
|
static moodycamel::BlockingConcurrentQueue<QueuedMessage> external_messages {};
|
||||||
|
|
||||||
void enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam) {
|
void ultramodern::enqueue_external_message(PTR(OSMesgQueue) mq, OSMesg msg, bool jam, bool requeue_if_blocked) {
|
||||||
external_messages.enqueue({mq, msg, jam});
|
external_messages.enqueue({mq, msg, jam, requeue_if_blocked});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block);
|
bool do_send(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, bool jam, bool block);
|
||||||
|
|
||||||
void dequeue_external_messages(RDRAM_ARG1) {
|
void dequeue_external_messages(RDRAM_ARG1) {
|
||||||
QueuedMessage to_send;
|
QueuedMessage to_send;
|
||||||
|
std::vector<QueuedMessage> requeued_messages{};
|
||||||
while (external_messages.try_dequeue(to_send)) {
|
while (external_messages.try_dequeue(to_send)) {
|
||||||
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
|
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
|
||||||
|
requeued_messages.push_back(to_send);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (QueuedMessage& cur_mesg : requeued_messages) {
|
||||||
|
external_messages.enqueue(cur_mesg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::wait_for_external_message(RDRAM_ARG1) {
|
void ultramodern::wait_for_external_message(RDRAM_ARG1) {
|
||||||
QueuedMessage to_send;
|
QueuedMessage to_send;
|
||||||
external_messages.wait_dequeue(to_send);
|
external_messages.wait_dequeue(to_send);
|
||||||
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
|
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
|
||||||
|
external_messages.enqueue(to_send);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ultramodern::wait_for_external_message_timed(RDRAM_ARG1, u32 millis) {
|
void ultramodern::wait_for_external_message_timed(RDRAM_ARG u32 millis) {
|
||||||
QueuedMessage to_send;
|
QueuedMessage to_send;
|
||||||
if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{millis})) {
|
if (external_messages.wait_dequeue_timed(to_send, std::chrono::milliseconds{millis})) {
|
||||||
do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false);
|
if (!do_send(PASS_RDRAM to_send.mq, to_send.mesg, to_send.jam, false) && to_send.requeue_if_blocked) {
|
||||||
|
external_messages.enqueue(to_send);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +149,7 @@ extern "C" s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags)
|
||||||
|
|
||||||
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
|
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
|
||||||
if (!ultramodern::is_game_thread()) {
|
if (!ultramodern::is_game_thread()) {
|
||||||
enqueue_external_message(mq_, msg, jam);
|
ultramodern::enqueue_external_message(mq_, msg, jam, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +171,7 @@ extern "C" s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags)
|
||||||
|
|
||||||
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
|
// Don't directly send to the message queue if this isn't a game thread to avoid contention.
|
||||||
if (!ultramodern::is_game_thread()) {
|
if (!ultramodern::is_game_thread()) {
|
||||||
enqueue_external_message(mq_, msg, jam);
|
ultramodern::enqueue_external_message(mq_, msg, jam, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ void timer_thread(RDRAM_ARG1) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Waiting for the timer completed, so send the timer's message to its message queue
|
// Waiting for the timer completed, so send the timer's message to its message queue
|
||||||
osSendMesg(PASS_RDRAM cur_timer->mq, cur_timer->msg, OS_MESG_NOBLOCK);
|
ultramodern::enqueue_external_message(cur_timer->mq, cur_timer->msg, false, true);
|
||||||
// If the timer has a specified interval then reload it with that value
|
// If the timer has a specified interval then reload it with that value
|
||||||
if (cur_timer->interval != 0) {
|
if (cur_timer->interval != 0) {
|
||||||
cur_timer->timestamp = cur_timer->interval + time_now();
|
cur_timer->timestamp = cur_timer->interval + time_now();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue