diff --git a/src/boot/main.c b/src/boot/main.c index 65c45572..985b8243 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -303,13 +303,17 @@ void handle_dp_complete(void) { sCurrentDisplaySPTask = NULL; } -OSTimer RCPHangTimer; +OSTimerEx RCPHangTimer; void start_rcp_hang_timer(void) { - osSetTimer(&RCPHangTimer, OS_USEC_TO_CYCLES(3000000), (OSTime) 0, &gIntrMesgQueue, (OSMesg) MESG_RCP_HUNG); + if (RCPHangTimer.started == FALSE) { + osSetTimer(&RCPHangTimer.timer, OS_USEC_TO_CYCLES(3000000), (OSTime) 0, &gIntrMesgQueue, (OSMesg) MESG_RCP_HUNG); + RCPHangTimer.started = TRUE; + } } void stop_rcp_hang_timer(void) { - osStopTimer(&RCPHangTimer); + osStopTimer(&RCPHangTimer.timer); + RCPHangTimer.started = FALSE; } void alert_rcp_hung_up(void) { diff --git a/src/game/main.h b/src/game/main.h index 26f4679f..2ee80007 100644 --- a/src/game/main.h +++ b/src/game/main.h @@ -97,6 +97,16 @@ extern s8 gDebugLevelSelect; extern s8 gShowDebugText; #endif +// Special struct that keeps track of whether its timer has been set. +// Without this check, there is a bug at high CPU loads in which +// the RCP timer gets set twice and the game tries to +// insert __osBaseTimer into a ring buffer that only contains itself, +// causing a particularly messy crash. +typedef struct { + u8 started; + OSTimer timer; +} OSTimerEx; + void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg); void dispatch_audio_sptask(struct SPTask *spTask); void exec_display_list(struct SPTask *spTask);