log in | register | forums


User accounts
Register new account
Forgot password
Forum stats
List of members
Search the forums

Advanced search
Recent discussions
- I want to digitise some A3010 software - ONLY COPY (Gen:5)
- RISC OS ports website (News:5)
- For Swaps/Trade Acorn User/Archi World Magazine Collection (Gen:5)
- More Acorn Magazine nostalgia (News:)
- RISC OS London Show 2018 (News:)
- NetSurf or Iconbar? (Site:3)
- September News round-up (News:)
- DDE tools updated to DDE28c (News:)
- Orpheus hits crowdfunding target (News:2)
- Orpheus launch crowdfunding campaign (News:5)
Latest postings RSS Feeds
RSS 2.0 | 1.0 | 0.9
Atom 0.3
Misc RDF | CDF
Site Search
Article archives
The Icon Bar: Programming: How do transient callbacks work?
  How do transient callbacks work?
  sirbod (12:16 21/6/2012)
  sirbod (22:09 21/6/2012)
    arawnsley (23:08 21/6/2012)
      Phlamethrower (00:31 22/6/2012)
        sirbod (07:50 22/6/2012)
  gerph (19:52 13/9/2012)
    sirbod (20:28 13/9/2012)
      gerph (14:54 14/9/2012)
        sirbod (21:41 14/9/2012)
Jon Abbott Message #120656, posted by sirbod at 12:16, 21/6/2012
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 22:09, 21/6/2012, in reply to message #120656
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

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

LDMFD R13!, {R11-R12, R14}

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

;Called from SWI vector when certain keys are pressed, to load a disc image

.insV_SPSR DCD 0

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
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

MRS R0, SPSR ;32bit, store 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

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

TEQ R0, #0 ;are we running on a 32bit CPU?
BNE insV_disk_loader_exit_32bit ;YES

TEQNEP R0, #0 ;26bit, use PC flags
NOP ;now back in original CPU mode
B insV_disk_loader_exit

LDR R0, insV_CPSR ;switch back to original CPU mode
MSR CPSR_all, R0
LDR R0, insV_SPSR ;restore SPSR
MSR SPSR_all, R0

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 23:08, 21/6/2012, in reply to message #120659
R-Comp chap
Posts: 470
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 00:31, 22/6/2012, in reply to message #120662
PhlamethrowerHot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot Hot stuff

Posts: 15065
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 07:50, 22/6/2012, in reply to message #120665
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 smile, 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 ]
Justin Fletcher Message #121071, posted by gerph at 19:52, 13/9/2012, in reply to message #120656
Posts: 9
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.
  ^[ Log in to reply ]
Jon Abbott Message #121075, posted by sirbod at 20:28, 13/9/2012, in reply to message #121071
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 ]
Justin Fletcher Message #121079, posted by gerph at 14:54, 14/9/2012, in reply to message #121075
Posts: 9
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.
  ^[ Log in to reply ]
Jon Abbott Message #121082, posted by sirbod at 21:41, 14/9/2012, in reply to message #121079
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 ]

The Icon Bar: Programming: How do transient callbacks work?