Module termination
Rick Murray (539) 13850 posts |
Something that has always bugged me about modules in RISC OS (other than SVC mode!) is that there’s no way for a module to legitimately self terminate. There are all sorts of hacks (execute RMKill as an OSCLI, set up a tiny bit of code in the RMA to do it on a callback, etc etc) but they all suffer from either potentially re-entering a removed/unlinked module or small memory leaks from helper code that can’t be freed from within itself (though I’ve seen one that frees its own RMA allocation irregardless 1). Wouldn’t it be so much simpler if there was a SWI that could mark a module as pending removal, and upon exit from SVC mode (ie the module), it is removed. 1 I’m using this word to wind up those who don’t think it’s a real word. |
David J. Ruck (33) 1636 posts |
Have you got a use case for a self terminating module? |
Rick Murray (539) 13850 posts |
Seems to me to be the wrong answer, but nevertheless, I have thought it might be useful for a module to be able to terminate itself if situations change. It is capable of assessing whether or not it should run at startup, but thereafter is expected to remain loaded. Also, a remote server shutdown, if parts of the server are implemented in a module, might benefit from the ability to shut itself down. Those are off the top of my head. I’m sure I’ve thought of others in my years, but since RISC OS can’t, one doesn’t tend to give it much more thought. |
Jeffrey Lee (213) 6048 posts |
I thought the well-known “correct” way of doing this was to inject code onto the SVC stack. Maybe it’s not as well-known as I thought? kill_me STMFD SP!,{R1,LR} ADR R0,callback ADR R1,stack_code SWI XOS_AddCallback LDMFD SP!,{R1,PC} callback SUB SP,SP,#12 STMFD SP!,{R0-R2,LR} LDMIA R12,{R0,R2,LR} ADD R1,SP,#16 STMIA R1,{R0,R2,LR} ADD R2,R1,#12 MOV R0,#1 SWI XOS_SynchroniseCodeAreas MOV R0,#4 ADR R1,module_title ADD PC,SP,#16 stack_code SWI XOS_Module LDMIA SP!,{R0-R2} LDR PC,[SP],#16 OK, it’s not a SWI, but it is small, easily reused, and should work on all OS versions. |
Chris Mahoney (1684) 2165 posts |
With the bonus of being completely impenetrable to C programmers like me! :) |
Jon Abbott (1421) 2651 posts |
Isn’t OS_ExitAndDie meant for this? Injecting code into the SVC stack isn’t something I’d advise – the memory area may have execution blocked. |
Jeffrey Lee (213) 6048 posts |
// Request that this module self-terminates _kernel_oserror *kill_me(void);
OS_ExitAndDie is for module tasks. You don’t really want a non-task module to call OS_Exit and kill the foreground app :-)
Yeah, it’s not a very nice solution, but it’s one of the few areas of memory where it is possible to free a memory “allocation” while executing code from within the allocated block. Maybe scratch space would work as a substitute? (I’m not familiar enough with the rules about when it’s safe to use it) |
Jon Abbott (1421) 2651 posts |
Are you sure that’s the case? It was my understanding that the calling address is checked and if it’s outside of AppSpace the current task isn’t terminated – it just results in the Module self-terminating. |
Jeffrey Lee (213) 6048 posts |
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ExitAndDie ; r0-r2 parameters for Exit ; r3 pointer to module name TerminateAndSodOff ROUT Push "r0-r2" LDR r10, =ZeroPage [ ZeroPage = 0 STR r10, [r10, #Curr_Active_Object] | MOV r14, #0 STR r14, [r10, #Curr_Active_Object] ] MOV r1, r3 MOV r0, #ModHandReason_Delete SWI XOS_Module Pull "r0-r2" SWI XOS_Exit https://gitlab.riscosopen.org/RiscOS/Sources/Kernel/-/blob/Kernel-6_40/s/MoreSWIs#L846 |
Julie Stamp (8365) 474 posts |
You could have an OS_Module reason code to try and kill you on a callback. But how would the kernel know which module to kill? You could point the R12 value for the callback at the base of the module, but if (completely improbably) someone killed you and another module got loaded in your place before the callback happened the new module would get mistakenly killed. |
Rick Murray (539) 13850 posts |
By name. Basically like *RMKill and OS_Module 4, but safe to be issued by a module to itself.
No, it’s by name, not address. So the utterly improbable series of events would be:
Essentially you’re expecting no callbacks to occur between the third point (request to die) and the fifth (don’t load a new one because one is already there – theoretically leading to the one already there being killed). I don’t think that is possible because it implies somehow quitting Store (in the desktop environment) and running it (also in the desktop environment) in the absence of callbacks. |
Julie Stamp (8365) 474 posts |
Sorry I was talking about addresses because I was wondering if a callback would solve the problem of when to do it – obviously the initial OS_Module in your service call handler could use a name, but if the kernel set a callback it would have to remember somehow which module needed killing. |
Rick Murray (539) 13850 posts |
No, it should be the kernel’s responsibility to set up the callback. Because if not, you’ll have one of two choices:
Hence Jeffrey’s solution of doing it in stack.
Which is not our problem any more than any other parts of the inner workings. ;-) |
Julie Stamp (8365) 474 posts |
Yes I think setting a flag somewhere the best option so far. It could be in the module header, but then wouldn’t work for ROM modules, not that they’d be doing this. |
Colin (478) 2433 posts |
Write an application that you load with the module that sits waiting for Message_TaskCloseDown from !store and kills your module and quits. Can you kill a module from an application in a runnable module? Probably not. Redirect output from line where the runimage is run to pipe:$.log That will stop the obey file completing. Then add rmkill module after the runimage line. In fact I don’t think you need redirect output just having a kill command after the line that the app is run will do the trick – or I may be misremembering some feature |
Julie Stamp (8365) 474 posts |
Yes that’s what OS_ExitAndDie is for, and is probably a lot easier than trying to find a way to make the OS do it. |
Chris Hall (132) 3558 posts |
It could be in the module header, but then wouldn’t work for ROM modules, not that they’d be doing this. Unless you can put something useful in its place. Ho ho! |