Spawning tasks
Jon Abbott (1421) 2651 posts |
Is there a correct way to spawn a USER task from a module? At the moment, a *Command is called from an Obey file with the address of the task. My module then points R13 to the end of application space, clears down the SVC stack, enters USER, stacks both SVC R14 and a return to itself, finally calling the address in question. On return it pulls SVC R14 from the user stack, switches back to SVC and then exits. Essentially, I need to replicate what *GO does – assuming that’s using the correct method. I need a method that will work both under the WIMP and when single tasking outside of the WIMP. |
Jeffrey Lee (213) 6048 posts |
The normal way to start a module as an application/task is to give the module a ‘start’ entry point and then use OS_Module 0 to invoke it (with your module’s name passed in in R1). That’s how *BASIC works (the BASIC module implements the command as a call to OS_Module 0). However it’s worth pointing out that all that *Go and OS_Module 0 really do is issue OS_FSControl 2, flatten the SVC stack, switch to user mode, and then call the target code. So if you’re emulating *Go it might be easier to just start the new task manually via OS_FSControl 2. I.e. pass the address of the target code into OS_FSControl 2, then install any environment handlers or do any other setup you need, then flatten the SVC stack & call the code. Saves having to enter your module (with the CAO pointing to the module) and then repoint the CAO to the target code when you’re about to enter it. |
Rick Murray (539) 13840 posts |
Is this something that can be done without insider knowledge of how the kernel works ? |
Jeffrey Lee (213) 6048 posts |
Good questions! Technically you can read the address of the top of the SVC stack from OS_ReadSysInfo 6. But that call is for internal use only. So I guess the only correct way of starting a new task is to use OS_Module 0 and let the kernel flatten the stack for you. |
Jon Abbott (1421) 2651 posts |
I don’t think I explained clearly enough, I don’t want to run a module, I want to spawn a new task from within a module. There’s no current method to do this if the task in memory other than *GO and I’m not convinced it’s method is correct. Will the method *GO uses not break the WIMP if called from a Wimp Task? Flattening the SVC stack sounds like it’s assuming its switched to single task. Where does R14 point to when *GO calls the code? |
Jeffrey Lee (213) 6048 posts |
The SVC stack is empty whenever the Wimp calls a task. So the Wimp won’t care if it gets flattened again. But yes, issuing *Go will effectively start a new task ‘ontop’ of the current one. As far as the Wimp is concerned it will still think it’s the same task, and any attempts to call Wimp_Initialise from the child task will (I think!) result in an error. If you want control to return to your code once the child task exits then you’ll need to basically do the same as system() does and take a copy of the current environment handlers, install new ones (to allow you to catch the termination of the new child task), and then from within those handlers restore the old environment handlers and resume execution of your code. If you want to start a new task alongside your current task (i.e. start it as a new Wimp task) then TaskManager_StartTask or *WimpTask look like your main choices. If the code you’re *Go’ing is already loaded into your wimpslot then this will obviously require some shenanigans in the child task to copy the workspace over before starting execution.
Nowhere. OS_Exit, or invoking an error handler, are the only methods tasks should use to terminate themselves. You also shouldn’t need to set R13, that’s the task’s responsibility (e.g. read application slot limit via OS_GetEnv). |
Jon Abbott (1421) 2651 posts |
I’ve found a few games crash on entry as they’re assuming R13 is setup, my guess is that R13 is initialized by OS_FSControl 4 when an Absolute is *RUN, but not if *LOAD and then call them directly. It’s academic though, as it won’t hurt to initialize R13 before I call the code.
That will explain why quite a few games crash on exit, they’re assuming R14 points somewhere. I think my only option to the problem is point R14 to “SWI OS_Exit”, hypervise OS_Exit and take over once the I’ve let the game’s Exit handler do it’s thing. |