I finally managed to nail it, and learnt a few things along the way. Seems these things aren't new, but aren't widely publicised, so it seemed worth making a post to save other people's time.
The root cause was that the reboot from VSH to GAME is not very good at properly tidying everything up automatically. I had a kernel thread that just wasn't getting stopped, and presumably it was crashing at some point during the invocation of reboot.bin by the kernel.
Because of that, what I thought was a crash during the load of the module during GAME boot, was actually a crash of the VSH module during VSH shutdown. So I saw lots of odd things that were seemingly inexplicable.
The main odd thing:
SYMPTOM: Adding sceKernelDelayThread() in random places stopped the module from crashing "during startup".
EXPLANATION: sceDisplayWaitVBlank() doesn't yield the thread in the same way as sceKernelDelayThread(). It seems that module tidyup during reboot can't kill kernel threads that only yield via waitvblank. So, a kmode main loop that was basically:
Code: Select all
while(1)
{
sceDisplayWaitVBlank();
...
}
Code: Select all
while(1)
{
sceKernelDelayThread(100);
sceDisplayWaitVBlank();
...
}
An alternative solution I found before I understood the yield behaviour:
There are some little-known module callbacks that you can use to detect reboot, and cause your module to exit. It seems that module_stop() is not called for OE VSH plugins, so that's no help. But these functions:
module_reboot_phase
module_reboot_before
are. I haven't looked into any more detail on module_reboot_phase(), but noticed that it is called 3 times during the boot to GAME mode.
module_reboot_before() seems to be called last thing before the crash I was seeing, so I added some code to do the following, which will also avoid the crash:
Code: Select all
int module_reboot_before()
{
terminate_flag = 1;
sceKernelWaitThreadEnd(mainthreadid, 0);
return 0;
}
I have no idea of the true function prototypes for these funcs, but for my purposes int func(void) was sufficient. If you want to use them, you need to add them to your exports.exp, alongside module_start.
There's also another standard prx function, module_bootstart, but I haven't seen that called at any point in my module - presumably it happens after the reboot.
References I used to find some of this info:
1. http://hitmen.c02.at/files/yapspd/psp_doc/chap26.html
Groepaz's great doc, search for module_start.
2. http://svn.pspsp.org/svn/CheatMaster/crt0_prx.c
Although I don't think the prototype for _reboot_before is likely to be correct either.
Hope this helps someone to avoid the pain I've gone through recently. :)