CLib |_kernel_unwind| on ARMv7
Jon Abbott (1421) 2651 posts |
Under what condition is |_kernel_unwind| called internally within CLib? I’m not seeing it called when running CLib code on Pi1, but am on Pi2/3. To date, I’ve not bothered implementing a local _kernel_unwind to make it 26bit code compatible, as I believed (possibly wrongly) that it was only used in the event of an error occurring. If I patch it and re-run the code it seems to run okay, but I’d like to know why its getting called in the first place. |
Rick Murray (539) 13840 posts |
I’m not sure why different machines behave differently? However it appears to be called here when calling _kernel_exit() in non-user mode – not sure exactly how C programs terminate, so don’t know if this is helpful. ;-) That’s all I spotted looking in the RISC_OSLib sources for the CLib/Kernel stuff. Asides from the obvious (backtrace/postmortem), that is. |
Jeffrey Lee (213) 6048 posts |
A search through the CLib sources turns up the following:
I’d guess that it’s the last one that’s most likely to go wrong – there’s a fair bit of code related to it (see s.k_body). In particular, it looks like the EventHandler routine (event environment handler claimant) will set R12 to 1 on exit in order to request that the OS schedules a callback (to CallBackHandler, the callback environment handler), which then calls through to FindAndCallHandlers in order to deliver the event. |
Jon Abbott (1421) 2651 posts |
That confuses me as well. As far as I can tell, it shouldn’t be called and isn’t on Pi1. I did look at the OSLib source and couldn’t fathom out how |_kernel_unwind| was being called. At the time it’s called its in USER, which should rule out the non-user case. I’ve also tried today’s RISCOS build on both Pi1 and Pi3, to rule out build/changes. Pi1 works as expected, Pi3 crashes within |_kernel_unwind| so it’s specific to ARMv7. Also, I know it’s being called internally within CLib as my code reports _kernel_unwind as being unsupported (I’ve yet to code a replacement, as its way down the priority list – games don’t generally crash!)
Sounds plausible as I know at least one game is crashing during an interrupt, but why the differing behaviour between Pi1 and Pi2/3? |
Jon Abbott (1421) 2651 posts |
I’ve just rechecked the PRM regarding the language descriptor, but am confused by the size:
It describes the first 24 bytes of the structure, but what are the optional entries? It references Interfacing a language run-time system to the Acorn library kernel, which rather unhelpfully has a circular reference:
|
Jeffrey Lee (213) 6048 posts |
k_body defines the structure here, and it appears to match what’s in my RISC OS 3 PRM (dead tree edition). 13 words = 52 bytes.
Yeah, looks like that’s just a mistake in the cross-referencing – it’s like that in the printed version too. But if you skip forwards a couple of pages you’ll find the section it’s meant to link to. |
Jon Abbott (1421) 2651 posts |
Ah, yes:
|
Jon Abbott (1421) 2651 posts |
I’ve not found root cause for the different behaviour between Pi1 and Pi2/3, although have tracked the unwind down to Events being raised. FindCallHandlers was attempting to pass them on to the app…which failed as there’s no suitable handler, it then does the unwind. I’m guessing it’s an event the default CLib handler can’t deal with? As a workaround, I’ve implemented memory wide EventProc / UnhandledEventProc / FastEventProc in the language descriptor, which return v1=-1 / v2=lang_event. From looking at the source for FCH_ClientCalled this appears to trigger an exit, bypassing FCH_Unwind |
Jon Abbott (1421) 2651 posts |
Done some more digging this morning. I’ve forced Clib to use it’s default CLib EventHandler / UnhandledEventHandler to rule out client Event handlers. The only event that’s being raised is event 11 (A key has been pressed or released), which doesn’t trigger an unwind on Pi1. For the most part it doesn’t trigger an unwind on Pi2/3 either, however sometimes it does. The PRM states:
If I’m understanding that description correctly, CLib’s EventHandler simply returns with the event unhandled, UnhandledEventHandler is then called, which calls SIGINT if setup. If there’s no SIGINT or SIGINT doesn’t return, it returns with the event unhandled and triggers a stack unwind. The unwind is occurring when the event is passed to CLib’s EventHandler, which doesn’t make much sense going by the PRM’s description of the process involved. |