home *** CD-ROM | disk | FTP | other *** search
- *:ts=8
- *****************************************************************************
- * *
- * RES.S (C) Copyright Eddy Carroll 1989 *
- * *
- * This module allows you to make a duplicate copy of your current process. *
- * In fact, both processes actually share the same code. However, the *
- * seglist pointer of the current process is modified so that when the *
- * process terminates, the memory doesn't get freed (if it did, the new *
- * process would suddenly find itself deallocated. Hello guru...) *
- * This code only works when called from CLI processes. *
- * *
- * The parameters passed are similar to those for CreateProc(), with the *
- * difference that instead of passing a BPTR to a seglist, you pass the *
- * address of the function the new process should start executing at. *
- * *
- * When the new process returns from this function, it will be removed from *
- * the system, and its memory (finally) deallocated. *
- * *
- * The typical use for a function like this is to allow a program to detach *
- * itself from a CLI (completely, with no trailing console handles etc.) *
- * when it is run. This is a convenient feature for the user, if the program *
- * is of the sort designed to sit in the background the whole time, rather *
- * than do something immediately, then exit. *
- * *
- * Lattice provide cback.o which at first glance would seem to provide a *
- * similar solution. However, cback.o makes it difficult to print error *
- * messages to the console if there is an error on the command line - by *
- * the time you spot the error, the CLI prompt has already been printed *
- * and your error message is printed after it. This looks very messy. *
- * Res avoids this problem by not spawning the background process until *
- * after the error checking has been done. *
- * *
- * From C, you call it as follows: *
- * *
- * pid = res(name,pri,func,stacksize) *
- * *
- * name - pointer to null terminated string *
- * pri - integer, priority of the new process *
- * func - pointer to the function for new process to call *
- * stacksize - integer, size of the stack for the new process *
- * *
- * pid - Process ID of new process, or 0 if none created *
- * *
- *****************************************************************************
-
- INCLUDE "exec/types.i"
- INCLUDE "exec/alerts.i"
- INCLUDE "exec/nodes.i"
- INCLUDE "exec/lists.i"
- INCLUDE "exec/ports.i"
- INCLUDE "exec/libraries.i"
- INCLUDE "exec/tasks.i"
- INCLUDE "libraries/dos.i"
- INCLUDE "libraries/dosextens.i"
- INCLUDE "workbench/startup.i"
- INCLUDE "exec/funcdef.i"
- INCLUDE "exec/exec_lib.i"
- INCLUDE "libraries/dos_lib.i"
-
- xref _exit
- xref _DOSBase
- xdef _res
-
- AbsExecBase equ 4
- segsize equ 36 ; Size of fake seg. (code = 28 bytes)
-
- csect text,0,0,1,2 * xref's after this are 16-bit reloc
-
-
- callsys macro
- CALLLIB _LVO\1
- endm
-
- _res:
- movem.l d2-d4/a2/a3/a6,-(a7) ; Save registers
- move.l AbsExecBase.w,a6 ; Get base of Exec library
- moveq #0,d1 ; Any sort of memory will do
- moveq #segsize,d0 ; Get size of fake segment
- callsys AllocMem ; Grab some memory
- tst.l d0 ; Did we get any?
- beq fatal ; If not, abort immediately!
- move.l d0,a3 ; Save pointer to memory
- sub.l a1,a1 ; NULL pointer indicates our process
- callsys FindTask ; Get pointer to our process block
- move.l d0,a2 ; Save it
- move.l pr_CLI(A2),a0 ; Get BPTR to our process's segarray
- add.l a0,a0 ; Convert BPTR to address
- add.l a0,a0 ;
- move.l cli_Module(a0),4(a3) ; Make fake segment point to our code
- clr.l cli_Module(a0) ; Remove process seg. from CLI seglist
- move.l #segsize,(a3) ; Set size of fake seglist
- lea.l 8(a3),a2 ; Get pointer to first code byte
-
- ;
- ; Now a tiny machine code program is constructed. It looks like this:
- ;
- ; move.l #$xxxxxx,A4 ; Initialise A4
- ; jsr $xxxxxx ; Call user program
- ; move.l #$xxxxxx,A6 ; Load DOSbase into A6
- ; move.l #$xxxxxx,d1 ; Get BPTR to this segment
- ; jmp UnLoadSeg(A6) ; Unload our process from memory
- ;
- ; It's built "on the fly" so to speak, to keep code size down, and also
- ; because it's a convenient way of initialising all the variables.
- ; Note that a potential problem exists if DOSBase should somehow alter or
- ; disappear. We'll assume it will remain relatively stable for the next
- ; few years anyway :-)
- ;
-
- move.l _DOSBase,a6 ; Prepare for DOS call
- move.w #$287C,(a2)+ ; Store MOVE.L $xxxxxx,A4 instruction
- move.l a4,(a2)+ ; Output value of A4 to initialise to
- move.w #$4EB9,(a2)+ ; Store JSR $xxxxxx
- move.l 36(a7),(a2)+ ; followed by address of user function
- move.w #$2C7C,(a2)+ ; Store MOVE.L $xxxxxx,A6 instruction
- move.l a6,(a2)+ ; followeds by current DOSbase
- ;
- lea 4(a3),a3 ; Now get seglist ptr to fake segment
- move.l a3,d3 ; and convert it to BPTR
- lsr.l #2,d3 ; D3 now has seglist ptr to fake seg
- move.w #$223C,(a2)+ ; Store MOVE.L $xxxxxx,D1 instruction
- move.l d3,(a2)+ ; Followed by BPTR to the segment
- move.l #$4EEEFF64,(a2)+ ; Store JMP UnLoadSeg(A6)
- ;
- move.l 28(A7),d1 ; Get pointer to name
- move.l 32(A7),d2 ; Get process priority
- move.l 40(A7),d4 ; Get stacksize
- callsys CreateProc ; Create new process
- movem.l (a7)+,d2-d4/a2/a3/a6 ; Pop registers
- rts ; Return
- fatal:
- moveq #120,d0 ; Set error exit code
- jmp _exit ; And exit
-
- end
-