From cmarshall@acorn.co.uk Wed Apr 15 03:48:28 1992 Received: from unido.Germany.EU.net by helpdesk.rus.uni-stuttgart.de (5.52/BelWue-1.0SG(subsidiary)) (for zrzm0111) id AA11509; Wed, 15 Apr 92 03:48:28 MST Received: from eros.uknet.ac.uk by mail.Germany.EU.net with SMTP (5.65+/UNIDO-2.1.0.b) via EUnet for helpdesk.rus.uni-stuttgart.de id AA28243; Wed, 15 Apr 92 03:49:54 +0200 Received: from acorn.co.uk by eros.uknet.ac.uk with UUCP id <23398-0@eros.uknet.ac.uk>; Wed, 15 Apr 1992 02:48:15 +0100 Received: from oak.acorn.co.uk by acorn.co.uk (4.1/Am32) id AA29108; Tue, 14 Apr 92 10:52:30 BST Date: Tue, 14 Apr 92 10:52:53 +0100 From: cmarshall@acorn.co.uk (Chris Marshall) To: zrzm0111 Subject: Re: Wanted: Information about the preempter Message-Id: <29EAB985@cmarshall> Status: RO In article <1992Apr13.183936.3762@news.uni-stuttgart.de> you wrote: >Hi > >A few weeks ago, someone told here, that he wrote a tool for preemptive >multitasking and will public it in comp.binaries.acorn. >Unfortunatly comp.binaries.acorn is closed for a while. Could someone >give me informations about the author ? It's included here... >thanks >so long >MUFTI > >ps: > Shouldn't the moderator of comp.binaries.acorn lay a forward to > one of the ftp/mail-servers, if he isn't on duty for a long time ? > The software he gets is not for private Acorn ltd. use ..... We could forward all stuff to Albert at Newcastle. The reasons that nothing has been posted for a while are as follows:- a) Phil Colmer is ill at present; he would normally handle comp.sources.acorn b) Alan Glover and myself are v. busy right now. I expect to begin posting things again soon, maybe withing the next week or two. As for Alan, I don't know. Unfortunately, moderating comp.*.acorn isn't really seen as part as the 'job' that we do here, so it has to be a spare time activity. Chris. ______________________________________________________________________ Chris Marshall cmarshall@acorn.co.uk >From pc123@phx.cam.ac.uk Tue Feb 25 19:29:59 1992 Received: by oak.acorn.co.uk (4.1/Ai1.6) id AA11229; Tue, 25 Feb 92 19:29:56 GMT Received: by acorn.co.uk (4.1/Am32) id AA13477; Tue, 25 Feb 92 19:29:02 GMT Received: from phx.cam.ac.uk by eros.uknet.ac.uk via JANET with NIFTP (PP) id <25975-0@eros.uknet.ac.uk>; Tue, 25 Feb 1992 18:22:59 +0000 Date: Tue, 25 Feb 92 18:22:08 GMT >From: Pete To: submit@acorn.co.uk Subject: Code for pre-empting a non-desktop task Message-Id: Newsgroups: comp.sources.acorn Here is the code to demonstrate how you can pre-empt a non-desktop program without running it in a taskwindow or under FrontEnd, as I promised on c-s-a recently. The code implements a module which acts a bit like FrontEnd but is a tinsy bit more efficient in its use of RMA; it should be possible to convert it for multitasking raytracers or other code you are writing without too much difficulty. The module writes all output generated by the program into a circular buffer at a fixed offset in its workspace - a desktop task then uses the OS_Module call to find out where the workspace is, and reads data out. The effect is that text produced by a program is not stored in the RMA, so excessive fragmentation does not occur. This also implies that this module is only the "business end" of a complete FrontEnd replacement, and you have to write a desktop client program as well, to display output produced by a task in a window. I am not posting the client here, because this source is really for illustration only. The module also allows the task it is running to be stopped and restarted under control of the controlling program. This is accomplished by writing various values into another word at a fixed offset in the module's workspace. Similarly the module may be asked to kill the program it is pre-empting (never scheduling it again, and closing all its files) or terminate it (call its exit handler). As I wrote Express Assembler, the module is written in Express format. You shouldn't have too much trouble understanding it, as it does not use any fancy features. It is well known that only Quiche Eaters comment their programs well. I have added a few, but... ...if you find you need help following it, send me mail and I will do my best to help. Or flame about it on c-s-a instead :-) . SETTYPE "MODULE" OBJECT "!YAMU.Initiator" ORG 0 ASSUME PC,0 ASSUME R12,&10000000 SET VSTR,"1.00" DD LANGUAGE,0,0,SERVICE,TITLE,HELP,0,0,0,0,0 TITLE DB "Initiator",0 ALIGN HELP DB "Initiator",9,"`VSTR` (",OSVAR "Sys$Date" RIGHT 6," ",OSVAR "Sys$Year",")",0 ALIGN TASKDESC DB "Init",0 ALIGN LANGUAGE LOCALS MOV R11,R0 ; Claim memory MOV R0,#6 LIT R3,WEND-WSTART SWI "OS_Module" STR R2,[R12] STR R12,[R2] MOV R12,R2 ; Initialise variables MOV R0,#0 ST R0,MEMORYMAPVETOED ST R0,OUTBUFFERREAD ST R0,OUTBUFFERWRITE ST R0,MESSAGES ST R0,SUSPENDED ST R0,TERMINATING ST R0,HANDLESUSED ; Register as Wimp task MOV R0,#200 LIT R1,&4B534154 ADR R2,TASKDESC SWI "Wimp_Initialise" ST R1,TASKHANDLE ; Calculate appropriate (initial) slot size. This is not calculated ; in any special way, it just tries to allocate a reasonable amount ; of space. The newer applications ask the Wimp for more space if ; they run out. MVN R0,#0 MVN R1,#0 SWI "Wimp_SlotSize" ADD R0,R0,R1 ADD R0,R0,R2 CMP R0,#512*1024 MOVGE R0,#512*1024 SUBLT R0,R0,#64*1024 CMP R0,#0 MOVLE R0,#16*1024 MVN R1,#0 SWI "Wimp_SlotSize" ; Initialise environment, so that funny things don't happen when the ; background task calls the exit handler, etc. In fact the exit ; handler has to come back into this code in order for us to tidy up. MOV R0,#6 ; Error handler ADR R1,ERRORHANDLER MOV R2,R12 ADR R3,ERRORBUFFER SWI "OS_ChangeEnvironment" ADR R0,OLDERRORHANDLER STMIA R0,{R1-R3} MOV R0,#11 ; Exit handler ADR R1,EXITHANDLER MOV R2,R12 MOV R3,#0 SWI "OS_ChangeEnvironment" ADR R0,OLDEXITHANDLER STMIA R0,{R1-R3} ; Set interruption of background task BL SETCALLAFTER BL CLAIMVECS ; And start the task off MOV R0,R11 SWI "OS_Write0" ; This just writes the name of the command SWI "OS_NewLine" ; run into the output buffer. MOV R0,R11 SWI "OS_CLI" ; Execute the * command that runs the task. ; This may return, if no application is started. In this case, there ; is an outstanding ticker event to cancel, but apart from that we ; just exit. ADR R13,USRSTACK BL CANCELTICKER ; Cancel the descheduling time-out. BL RELEASEVECS ; Release vectors we have claimed. B KILLMODULE MAINLOOP BL RELEASEVECS ; Must release all vectors before polling. A MOV R0,#0 ADR R1,POLLBLOCK SWI "Wimp_Poll" TEQ R0,#0 BLNE NONIDLEPOLL ADR R13,USRSTACK BL RECEIVEMESSAGES BNE A ; See whether the output buffer is empty - if not we wait until it ; has been emptied before running the task again. LD R0,OUTBUFFERREAD LD R1,OUTBUFFERWRITE TEQ R0,R1 BNE A ; If the task has been stopped by the controlling task, don't ; reschedule it. LD R0,SUSPENDED TEQ R0,#0 BNE A ; Set up conditions for re-entering task BL SETCALLAFTER ; Create a new CallAfter event BL CLAIMVECS ; and claim the vectors again. ; If the task is being terminated, get ready to call OS_Exit LD R0,TERMINATING TEQ R0,#0 MOV R0,#0 ST R0,TERMINATING ; Back into the task again. When restoring the registers, note that ; the correct method for doing this is very dependent on the current ; processor mode - what is shown is NOT a general way of restoring ; a register dump after an exception. ADR R0,REGBUF LDMEQIA R0,{R0-PC}^ ; Restore the task's registers. LDMIA R0,{R0-R14} MOV R0,#0 LIT R1,&58454241 MOV R2,#2 SWI "OS_Exit" ; Task is being terminated. Note how we can ; even call OS_Exit "within" a CallBack handler. ; General rubbish to do with being a Wimp task, nothing amazing here. NONIDLEPOLL TEQ R0,#17 TEQNE R0,#18 MOVNES PC,R14 LD R0,POLLBLOCK+16 TEQ R0,#0 ; Message_Quit MOVNES PC,R14 ADR R13,USRSTACK BL CANCELTICKER MOV R0,#0 ST R0,OUTBUFFERREAD ST R0,OUTBUFFERWRITE ; and continue into KILLMODULE, below. ; Code to kill the module off. Nothing here that you don't get in ; other modules, the only point worthy of note is that we hang around ; in this routine until all the characters have been read out of the ; circular buffer. KILLMODULE LOCALS ; Restore environment MOV R0,#6 ; Error handler ADR R1,OLDERRORHANDLER LDMIA R1,{R1-R3} SWI "OS_ChangeEnvironment" MOV R0,#11 ; Exit handler ADR R1,OLDEXITHANDLER LDMIA R1,{R1-R3} SWI "OS_ChangeEnvironment" ; Write the return code into the message word, for the foreground ; task LD R0,RETURNCODE ORR R0,R0,#&80000000 ST R0,MESSAGES ; Now call Wimp_Poll until all the characters have been removed from ; the buffer and the return code has been read A MOV R0,#0 ADR R1,POLLBLOCK SWI "Wimp_Poll" LD R0,OUTBUFFERREAD LD R1,OUTBUFFERWRITE TEQ R0,R1 BNE A LD R0,MESSAGES TEQ R0,#0 BNE A ; Finish off as a Wimp task LD R0,TASKHANDLE LIT R1,&4B534154 SWI "Wimp_CloseDown" ; Release workspace MOV R0,#7 MOV R2,R12 SWI "OS_Module" ; Zero private word so RISC OS doesn't free it again!! LD R0,PRIVATEWORD MOV R1,#0 STR R1,[R0] ; ExitAndDie to end program and kill module; don't set return code ; as this was set by foreground task. MOV R0,#0 MOV R1,#0 MOV R2,#0 ADR R3,TITLE SWI "OS_ExitAndDie" ; Just a standard service call handler. Traps Service_Memory so we ; get to keep the memory that the pre-empted task will run in! SERVICE ; Nothing to do here except veto attempts by the Wimp to remove all ; our memory - this is tried once at the start. TEQ R1,#&11 ; Service_Memory MOVNES PC,R14 STMFD R13!,{R0,R12,R14} LDR R12,[R12] LD R0,MEMORYMAPVETOED TEQ R0,#0 LDMNEFD R13!,{R0,R12,PC}^ MOV R1,#0 MOV R0,#1 ST R0,MEMORYMAPVETOED LDMFD R13!,{R0,R12,PC}^ ; Claim write character (so we redirect the program's output into ; the circular buffer) and open file (so we know what files the ; program has open, so we can close them again if it is killed). CLAIMVECS MOV R0,#3 ; WrchV ADR R1,WRCHV MOV R2,R12 SWI "OS_Claim" MOV R0,#&D ; FindV ADR R1,FINDV MOV R2,R12 SWI "OS_Claim" MOVS PC,R14 RELEASEVECS MOV R0,#3 ; WrchV ADR R1,WRCHV MOV R2,R12 SWI "OS_Release" MOV R0,#&D ; FindV ADR R1,FINDV MOV R2,R12 SWI "OS_Release" MOVS PC,R14 ; Schedule a descheduling event. SETCALLAFTER MOV R0,#20 ADR R1,INTERRUPT MOV R2,R12 SWI "OS_CallAfter" MOVS PC,R14 CANCELTICKER STMFD R13!,{R0,R1,R14} ADR R0,INTERRUPT MOV R1,R12 SWI "OS_RemoveTickerEvent" LDMFD R13!,{R0,R1,PC}^ WRCHV STMFD R13!,{R1-R2} LD R1,OUTBUFFERREAD LD R2,OUTBUFFERWRITE ADD R2,R2,#2 BIC R2,R2,#&400 TEQ R1,R2 BLEQ CANCELTICKER BLEQ SETCALLBACK LD R1,OUTBUFFERWRITE ADR R2,OUTBUFFER STRB R0,[R1,R2] ADD R1,R1,#1 BIC R1,R1,#&400 ST R1,OUTBUFFERWRITE LDMFD R13!,{R1-R2} LDMFD R13!,{PC}^ FINDV LOCALS TEQ R0,#0 ; Closing a file BEQ A STMFD R13!,{R12} STMFD R13!,{PC} MOVS PC,R14 MOV R0,R0 ; Our code is re-entered a word further down, so we waste ; this word. LDMFD R13!,{R12} LDMVSFD R13!,{PC} STMFD R13!,{R2,R3} ADR R2,HANDLES LD R3,HANDLESUSED TEQ R3,#32 MOVEQ R3,#31 STR R0,[R2,R3,LSL #2] ADD R3,R3,#1 ST R3,HANDLESUSED LDMFD R13!,{R2,R3} LDMFD R13!,{PC}^ A TEQ R1,#0 ; Closing all files BEQ B STMFD R13!,{R2,R8,R9,R14} LD R8,HANDLESUSED ADR R9,HANDLES C TEQ R8,#0 LDMEQFD R13!,{R2,R8,R9,PC}^ LDR R2,[R9],#4 SUB R8,R8,#1 TEQ R1,R2 BNE C MOV R2,#0 STR R2,[R9,#-4] LDMFD R13!,{R2,R8,R9,PC}^ B STMFD R13!,{R0,R14} MOV R0,#0 ST R0,HANDLESUSED LDMFD R13!,{R0,PC}^ INTERRUPT ; Remember that we must not corrupt R14svc, so we have to mess about ; with changing processor mode. STMFD R13!,{R0,R14} ; R14irq goes onto irq stack. MOVS R0,PC ; Preserve old processor mode. TEQP PC,#3 MOV R0,R0 STMFD R13!,{R14} BL SETCALLBACK ; Use CallBack code. LDMFD R13!,{R14} TEQP R0,#0 MOV R0,R0 LDMFD R13!,{R0,PC}^ ; The following is just standard CallBack code, it restores the ; handler address to its old value before returning to the main ; program loop. SETCALLBACK STMFD R13!,{R0-R3,R14} MOV R0,#7 ; CallBack ADR R1,CALLBACKHANDLER MOV R2,R12 ADR R3,REGBUF SWI "OS_ChangeEnvironment" ADR R14,OLDCALLBACK STMIA R14,{R1-R3} SWI "OS_SetCallBack" LDMFD R13!,{R0-R3,PC}^ CALLBACKHANDLER TEQP PC,#0 MOV R0,R0 MOV R0,#7 ADR R1,OLDCALLBACK LDMIA R1,{R1-R3} SWI "OS_ChangeEnvironment" B MAINLOOP ; If we get an error reported, we write it into the circular buffer ; and kill the program. ERRORHANDLER MOV R12,R0 MOV R0,#2 ST R0,RETURNCODE SWI "OS_NewLine" ADR R0,ERRORBUFFER+8 SWI "OS_Write0" SWI "OS_NewLine" ADR R13,USRSTACK BL CANCELTICKER BL RELEASEVECS B KILLMODULE ; If the program exits, we tidy up. EXITHANDLER ST R2,RETURNCODE ADR R13,USRSTACK BL CANCELTICKER BL RELEASEVECS B KILLMODULE ; These messages control the pre-empted task. They allow the ; controlling process to stop and restart it, terminate it (which ; invokes the program's exit handler) and kill it (which will never ; reschedule it, and just closes all its files before shutting down). RECEIVEMESSAGES LOCALS STMFD R13!,{R0,R14} LD R0,MESSAGES STMFD R13!,{R0} TST R0,#&80000000 MOVEQ R0,#0 ST R0,MESSAGES LDMFD R13!,{R0} TEQ R0,#1 ; Suspend BEQ A TEQ R0,#2 ; Restart BEQ B TEQ R0,#3 ; Terminate BEQ C TEQ R0,#4 ; Kill BEQ D LDMFD R13!,{R0,PC}^ A MOV R0,#1 ST R0,SUSPENDED LDMFD R13!,{R0,PC}^ B MOV R0,#0 ST R0,SUSPENDED LDMFD R13!,{R0,PC}^ C MOV R0,#1 ST R0,TERMINATING LDMFD R13!,{R0,PC}^ D MOV R9,#0 LD R10,HANDLESUSED ADR R11,HANDLES E TEQ R10,#0 BEQ F MOV R0,#0 LDR R1,[R11],#4 TEQ R1,#0 ADDNE R9,R9,#1 SWINE "OS_Find" SUB R10,R10,#1 B E F BL CLAIMVECS SWI "OS_WriteS" DB 13,10,10,"Killed",13,10,0 ALIGN MOV R0,R9 ADR R1,ERRORBUFFER MOV R2,#16 SWI "OS_ConvertCardinal4" SWI "OS_Write0" SWI "OS_WriteS" DB " file(s) closed",13,10,0 ALIGN BL RELEASEVECS MOV R0,#2 ST R0,RETURNCODE B KILLMODULE DSECT ORG &10000000 WSTART PRIVATEWORD ALLOC 4 MESSAGES ALLOC 4 ; Messages are written here by a controlling ; task. OUTBUFFERREAD ALLOC 4 OUTBUFFERWRITE ALLOC 4 OUTBUFFER ALLOC 1024 ; The output circular buffer TASKHANDLE ALLOC 4 MEMORYMAPVETOED ALLOC 4 SUSPENDED ALLOC 4 TERMINATING ALLOC 4 HANDLESUSED ALLOC 4 RETURNCODE ALLOC 4 REGBUF ALLOC 4*16 OLDCALLBACK ALLOC 4*3 OLDERRORHANDLER ALLOC 4*3 OLDEXITHANDLER ALLOC 4*3 HANDLES ALLOC 4*32 POLLBLOCK ALLOC 256 ERRORBUFFER ALLOC 256+4+4 ALLOC 64 USRSTACK WEND DEND END