Acorn Arcade forums: Programming: How do transient callbacks work?
|
How do transient callbacks work? |
|
sirbod (11:16 21/6/2012) sirbod (21:09 21/6/2012) arawnsley (22:08 21/6/2012) Phlamethrower (23:31 21/6/2012) sirbod (06:50 22/6/2012) gerph (18:52 13/9/2012) sirbod (19:28 13/9/2012) gerph (13:54 14/9/2012) sirbod (20:41 14/9/2012)
|
|
Jon Abbott |
Message #120656, posted by sirbod at 11:16, 21/6/2012 |
Member
Posts: 563
|
More specifically, what does RISC OS do to setup the CPU, stack etc prior too and on return from the code its calling?
I can't use CallBack directly, as it causes OS_Module (Free) to leak memory...however I need to mirror what it does off the SWI vector.
Yes, I know it sounds daft as I'm doing what CallBack does already, but its the only way to cure the memory leak.
I've tried various things, but certain games crash with my code - which work via a CallBack, so I'm missing something. |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #120659, posted by sirbod at 21:09, 21/6/2012, in reply to message #120656 |
Member
Posts: 563
|
My source code. I'm afraid it's a bit illegible as white spaces are stripped out.
SWI_vectorHandler replaces the OS SWI vector. insV_disk_loader switches the CPU mode to 26/32bit SVC, does the disk swap and then changes back to the SWI vector entry CPU mode, before passing the original SWI call back to the OS.
.vectorHandler_swapdisc DCD 0
.SWI_vectorHandler STMFD R13!, {R11-R12, R14}
LDR R12, insV_R0 ;is a disc change pending? TEQ R12, #0 BNE vector_handler_disc_swap ;YES, action it
.vector_Handler_forward LDMFD R13!, {R11-R12, R14} LDR PC, OS_SWI_Vector
.vector_handler_disc_swap LDR R11, vectorHandler_swapdisc ;are we dealing with the request? TEQ R11, #0 BNE vector_Handler_forward ;YES
STR R12, vectorHandler_swapdisc ;pending disc change BL insV_disc_loader ;action it immediately MOV R12, #0 STR R12, vectorHandler_swapdisc ;allow disc swaps B vector_Handler_forward
;insV_disk_loader ;---------------- ;Called from SWI vector when certain keys are pressed, to load a disc image
.insV_SPSR DCD 0
.insV_disk_loader STMFD R13!, {R0-R3, R14}
LDR R0, ADF_Mounted ;do we have an image mounted? TEQ R0, #0 BEQ insV_disk_loader_exit ;NO, exit
LDR R0, OS_26bit TEQ R0, #0 ;are we running on 32bit OS? BEQ insV_disk_loader_OS_32bit
TEQ PC, PC ;are we running on 32bit CPU? MOVNE R0, #0 MRSEQ R0, SPSR ;32bit, store SPSR STR R0, insV_SPSR MRSEQ R0, CPSR ;32bit, use CPSR MOVNE R0, PC ;26bit, use the PC flags STR R0, insV_CPSR ;store current PSR BICEQ R0, R0, #%11011111 ;32bit, clear mode/IRQ/FIQ bits BICNE R0, R0, #%11<<26 ;26bit, clear IRQ/FIQ bits ORR R0, R0, #%11 ;SVC(26) MSREQ CPSR_c, R0 ;32bit, use CPSR TEQNEP R0, #0 ;26bit, use PC flags NOP ;now in correct SVC mode B insV_disk_loader_P1
.insV_disk_loader_OS_32bit MRS R0, SPSR ;32bit, store SPSR STR R0, insV_SPSR MRS R0, CPSR ;32bit, use CPSR STR R0, insV_CPSR ;store current PSR BIC R0, R0, #%11011111 ;clear mode bits ORR R0, R0, #%00010011 ;SVC32, enable interrupts MSR CPSR_c, R0 ;32bit, use CPSR NOP
.insV_disk_loader_P1 LDR R1, insV_R0 SUB R1, R1, #128 ;convert key to ASCII "1" to "9" ADRL R0, Current_File_Mounted ;now we need to load the correct disc MOV R2, R0 .find_disc_number ;find end of filename LDRB R3, [R2], #1 TEQ R3, #0 BNE find_disc_number
STRB R1, [R2, #-2] ;store the disc number over the last char
;************ finally perform the disc swap *********** BL Entry_ADFMount ;mount the disc ;******************************************************
LDR R0, insV_SPSR TEQ R0, #0 ;are we running on a 32bit CPU? BNE insV_disk_loader_exit_32bit ;YES
LDR R0, insV_CPSR TEQNEP R0, #0 ;26bit, use PC flags NOP ;now back in original CPU mode B insV_disk_loader_exit
.insV_disk_loader_exit_32bit LDR R0, insV_CPSR ;switch back to original CPU mode MSR CPSR_all, R0 NOP LDR R0, insV_SPSR ;restore SPSR MSR SPSR_all, R0
.insV_disk_loader_exit MOV R0, #0 STR R0, insV_R0 ;allow key traps again LDMFD R13!, {R0-R3, PC}
|
|
[ Log in to reply ] |
|
Andrew Rawnsley |
Message #120662, posted by arawnsley at 22:08, 21/6/2012, in reply to message #120659 |
R-Comp chap
Posts: 600
|
If you don't get answers for some of these here, you could try on www.riscosopen.org - that seems to be slightly more frequented by "those what know" than Iconbar, although Jeffrey (who is probably more knowledgable than almost anyone these days) posts to both. |
|
[ Log in to reply ] |
|
Jeffrey Lee |
Message #120665, posted by Phlamethrower at 23:31, 21/6/2012, in reply to message #120662 |
Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff
Posts: 15100
|
I'm guessing the fact that your code crashes in some games is because it enables IRQs, even if the SWI that you're hooking onto was called with IRQs disabled. The kernel will only ever trigger callbacks if IRQs were enabled (except for the couple of places where callbacks are triggered manually, e.g. OS_ReadC).
To see what RISC OS does, it's probably best to look directly at the source code, either for RISC OS 5 or as far back as 3.6 & 3.7 if you check the history. The SLVK_* routines are used on exit from SWIs, while "The SWI despatch routine" located just below them is what sits on the SWI vector. If you're wondering why things look a bit funky (lots of {PC}-relative symbols) it's because various bits need to be PC-relative so the SWI despatcher works properly when copied to RAM. callback_checking is the routine that checks whether it's safe to trigger callbacks, and then Do_CallBack to actually trigger them (whether transient callbacks or the callback environment handler)
[Edited by Phlamethrower at 00:32, 22/6/2012] |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #120666, posted by sirbod at 06:50, 22/6/2012, in reply to message #120665 |
Member
Posts: 563
|
Brilliant, looking at the source, it appears to force the CPU to SVC with IRQ/FIQ enabled, so I have that right.
The only differences as far as I can tell are the following checks:
1. SPSR is User mode 2. SPSR has IRQ enabled 3. R13 is SVCSTK - 3 * 4
I'll try adding (1) / (2). I think I can drop 3 as the SVC stack is rarely empty in games.
Thanks for the pointer, just what I needed.
EDIT: Checking for (2) has fixed the crashing in Heimdall , I think I can safely ignore (1) and (3) as neither can be assumed to happen in a game.
[Edited by sirbod at 10:14, 22/6/2012] |
|
[ Log in to reply ] |
|
Charles Justin Ferguson |
Message #121071, posted by gerph at 18:52, 13/9/2012, in reply to message #120656 |
Member
Posts: 48
|
Sounds like you're talking rubbish. Transient callbacks do not cause OS_Module free to leak memory. You have some other problem than knowing about transient callbacks which you need to resolve. Consult the PRMs chapter on the Program Environment for details of what the transient callbacks are, when they're triggered and what OS_AddCallBack does. Compare and contrast with the environment handler for OS_CallBack which is significantly different. ________ -- Gerph |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #121075, posted by sirbod at 19:28, 13/9/2012, in reply to message #121071 |
Member
Posts: 563
|
Sounds like you're talking rubbish. Transient callbacks do not cause OS_Module free to leak memory. I should have gone back and edited that when I tracked down the specific cause below, which is in the ADFFS thread:
SharedCLibrary is claiming several blocks, which it releases shortly after. Although they've been freed, they're still showing in the heap as allocated:
RMA Claim - SharedCLibrary - 2000 - result 224AB54 RMA Claim - SharedCLibrary - 4000 - result 22600F4 RMA Claim - SharedCLibrary - 1BCC - result 2248F84 RMA Claim - SharedCLibrary - 1000 - result 2264104 RMA Claim - SharedCLibrary - 8000 - result 2265144 RMA Claim - ADFFS - C7F04 - result 226D124 RMA Claim - ADFFS - 1E40 - result 2335034 RMA Free - SharedCLibrary - 8000 - 2265144 RMA Free - SharedCLibrary - 1BCC - 2248F84 RMA Free - SharedCLibrary - 4000 - 22600F4 RMA Free - SharedCLibrary - 2000 - 224AB54 RMA Free - SharedCLibrary - 1000 - 2264104 ...then a similar sequence on the next disc load, only difference being ADFFS releases it's two blocks before the next load
The tail end of the RMA heap after this is:
2248F84 (1BD0) - Alloc (should be Free) 224AB54 (2010) - Alloc (should be Free) 224CB64 (1010) - Alloc 224DB74 (1BD0) - Alloc 224F744 (4010) - Alloc 2253754 (2010) - Alloc 2255764 (2980) - Alloc 22580E4 (8010) - Alloc 22600F4 (4010) - Alloc (should be Free) 2264104 (1010) - Alloc (should be Free) 2265114 (8010) - Alloc (should be Free) 226D124 (10C10) - Free 227DD34 (C7F10) - Alloc 2345C44 (1E50) - Alloc
As you can see, the five blocks claimed and released by SharedCLibrary are all still showing as Alloc in the heap. They total up to 66K, which leaks every time this happens.
I've confirmed this happens on RO 3.10 and 3.70, no idea about later RO versions. It only happens when done under a transient callback, in the end I had to avoid using the OS transients and code my own off the SWI vector. |
|
[ Log in to reply ] |
|
Charles Justin Ferguson |
Message #121079, posted by gerph at 13:54, 14/9/2012, in reply to message #121075 |
Member
Posts: 48
|
So you've got allocations that are happening from a C module. Ok. That doesn't say anything about how they're interacting with the callbacks. There is almost certainly something wrong with *your code* if you are working with a C module.
Launching into a 'frees don't work on transient callbacks, how do I work around this' is just plain wrong. There /are/ problems with RISC OS 3.1; realloc does not work within C module code. However later systems function correctly in this regard.
I have no idea what on earth you think you're trying to achieve by replacing the SWI handler itself but I believe that whatever you're doing, you're trying to work around problems in your code and your misunderstanding of the system.
From the look of things you're blaming a core component when you still haven't investigated the cause of the issue in your own code. You should *always* distrust your own code more than any other part of the system. Then you distrust libraries that you use. Then you distrust interfaces. Then the OS. Then hardware. The compiler's in there somewhere.
Use a memory tracking system like Fortify or similar in your C module, or create one of your own, and investigate where your code is going wrong. Look at the content of the memory being leaked.
If you've got an absolutely reproducible test case as you say, diagnosing the cause should be significantly easier. ________ -- Gerph |
|
[ Log in to reply ] |
|
Jon Abbott |
Message #121082, posted by sirbod at 20:41, 14/9/2012, in reply to message #121079 |
Member
Posts: 563
|
Use a memory tracking system like Fortify or similar in your C module Very useful advice, ADFFS however is pure assembler.
If you look at my previous post, you'll see that the Heap manager receives the free request, actions it, but doesn't actually mark the memory as free. Under what condition this happens I don't know, I never managed to create a reliable repro.
It's an obscure bug I'll grant, when it was initially reported, I couldn't believe it either. The solution was simple enough though, avoid all use of transient callbacks. This actually solved another issue, which was transient callback not being triggered as per the documented process, which is documented in another programming thread.
Whilst testing that, we also discovered OS_LeaveOS also had a bug, causing it to not return to the correct location on 26bit OS's.
[Edited by sirbod at 21:42, 14/9/2012] |
|
[ Log in to reply ] |
|
|
Acorn Arcade forums: Programming: How do transient callbacks work? |