123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- #
- ;
- ; (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
- ; See the copyright notice in the ACK home directory, in the file "Copyright".
- ;
- ;
- ; Module: implementation of coroutines
- ; Author: Ceriel J.H. Jacobs
- ; Version: $Header$
- ;
- ; This version works for EM implementations that have a contiguous downwards
- ; growing stack, on which data below the stack-pointer is not destroyed.
- ;
- #include <em_mes.h>
- #include <m2_traps.h>
- mes 2, EM_WSIZE, EM_PSIZE
- ; This file contains the implementation of the following routines from
- ; the SYSTEM module:
- ; TRANSFER, NEWPROCESS
- ; The NEWPROCESS routine creates a new coroutine stack frame.
- ; The TRANSFER routine implements transfers from one coroutine to another.
- ; The memory organization for coroutines is rather complicated.
- ; One problem is caused by the fact that the user must allocate the
- ; stackspace. So, this stackspace can be located anywhere, including on
- ; the heap. This means that we cannot use this space as a stack, because
- ; in EM, the stack-pointer may never point below the heap-pointer.
- ; So, this space is only used to save the stack when the coroutine isn't
- ; running.
- ; It also contains information about the size of the frame, the
- ; address of the procedure that forms the coroutine body, the offset
- ; of the LB from the start of the frame, and the offset of the SP from
- ; the start of the frame.
- ; So, is looks like this:
- ; |-----------------------------|
- ; | |
- ; | |
- ; | |
- ; .
- ; .
- ; .
- ; | |
- ; | |
- ; | | <--- coroutine ident
- ; |-----------------------------|
- ; | saved SP |
- ; |-----------------------------|
- ; | saved LB |
- ; |-----------------------------|
- ; | procedure address or 0 |
- ; |-----------------------------|
- ; | size |
- ; |-----------------------------|
- ;
- ; Another problem is that the coroutines must always run at the same
- ; place in the stack. Therefore, in the runtime startoff a piece of the
- ; stack is allocated for coroutines.
- exp $_SYSTEM__NEWPROCESS
- exp $_SYSTEM__TRANSFER
- inp $ChkSize
- pro $_SYSTEM__NEWPROCESS, 0
- ; This procedure only initializes the area used for saving the stack.
- ; Its definition is:
- ; PROCEDURE NEWPROCESS(P:PROC; A:ADDRESS; n:CARDINAL; VAR p1:ADDRESS);
- lol 2*EM_PSIZE ; size of frame (n)
- cal $ChkSize
- asp EM_WSIZE
- lfr EM_WSIZE
- sil EM_PSIZE ; store size in area (indicated by A)
- lal EM_PSIZE
- loi EM_PSIZE ; address of area (A)
- lal 0
- loi EM_PSIZE ; address of coroutine body (P)
- lal EM_PSIZE
- loi EM_PSIZE
- adp EM_WSIZE
- sti EM_PSIZE ; store it in area
- lal EM_PSIZE
- loi EM_PSIZE
- adp 3*EM_PSIZE + EM_WSIZE ; this becomes the coroutine identifier
- lal 2*EM_PSIZE+EM_WSIZE
- loi EM_PSIZE
- sti EM_PSIZE
- ret 0
- end 0
- target
- bss EM_PSIZE, 0, 0
- pro $_SYSTEM__TRANSFER, 0
- ; This procedure does all the hard work.
- ; It must save the current environment, and restore the one to which the
- ; transfer is done. It must also make it look like the return is done
- ; from ITS invocation of transfer.
- ; Definition is:
- ; PROCEDURE TRANSFER(VAR p1, p2 : ADDRESS);
- mes ms_gto ; This is a dangerous procedure
- lal EM_PSIZE
- loi EM_PSIZE
- loi EM_PSIZE ; address of target coroutine
- dup EM_PSIZE
- lae CurrentProcess
- loi EM_PSIZE
- dup EM_PSIZE
- lal 0
- loi EM_PSIZE ; address of place where to store address of current coroutine
- sti EM_PSIZE ; store
- cmp ; compare with current process
- zne *1
- ; Here, no real transfer needs to be done
- asp EM_PSIZE
- ret 0 ; just return
- 1
- lae target
- sti EM_PSIZE ; store it in target
- ; Now, we save the current stack
- ; Use local base from main program
- lor 0 ; load LB
- lae CurrentProcess
- loi EM_PSIZE
- adp -2*EM_PSIZE
- sti EM_PSIZE ; save it
- lor 1 ; load SP
- lae CurrentProcess
- loi EM_PSIZE
- adp -EM_PSIZE
- sti EM_PSIZE ; save it
- ; Now, we must find a stack we can temporarily use.
- ; Just take the one from the main program.
- lae MainProcess
- loi EM_PSIZE
- adp -EM_PSIZE
- loi EM_PSIZE
- str 1 ; temporary stackpointer
- lae MainLB
- loi EM_PSIZE
- str 0
- lae CurrentProcess
- loi EM_PSIZE
- lae MainProcess
- loi EM_PSIZE
- cmp
- zeq *2
- lae StackBase
- loi EM_PSIZE
- lae CurrentProcess
- loi EM_PSIZE
- adp -3*EM_PSIZE-EM_WSIZE
- loi EM_WSIZE ; get size
- ngi EM_WSIZE
- ads EM_WSIZE ; gives source address
- lae CurrentProcess
- loi EM_PSIZE ; destination address
- lae CurrentProcess
- loi EM_PSIZE
- adp -3*EM_PSIZE-EM_WSIZE
- loi EM_WSIZE
- bls EM_WSIZE ; copy
- 2
- lae target
- loi EM_PSIZE
- dup EM_PSIZE
- lae CurrentProcess
- sti EM_PSIZE ; store target process descriptor in _CurrentProcess
- lae MainProcess
- loi EM_PSIZE
- cmp
- zeq *4
- ; Now check if the coroutine was called before
- lae target
- loi EM_PSIZE
- adp -3*EM_PSIZE
- loi EM_PSIZE
- zer EM_PSIZE
- cmp
- zeq *5
- ; No, it was'nt
- lae StackBase
- loi EM_PSIZE
- str 1 ; new stack pointer
- lae target
- loi EM_PSIZE
- adp -3*EM_PSIZE
- loi EM_PSIZE
- zer EM_PSIZE
- lae target
- loi EM_PSIZE
- adp -3*EM_PSIZE
- sti EM_PSIZE
- cai
- loc 0
- cal $exit
- ret 0
- 5
- lae target
- loi EM_PSIZE ; push source address
- lae StackBase
- loi EM_PSIZE ; subtract size from this and we have the destination address
- lae target
- loi EM_PSIZE
- adp -3*EM_PSIZE-EM_WSIZE
- loi EM_WSIZE
- ngi EM_WSIZE
- ads EM_WSIZE ; got it
- lae target
- loi EM_PSIZE
- adp -3*EM_PSIZE-EM_WSIZE
- loi EM_WSIZE
- bls EM_WSIZE
- 4
- lae target
- loi EM_PSIZE
- adp -2*EM_PSIZE
- loi EM_PSIZE
- str 0 ; restore LB
- lae target
- loi EM_PSIZE
- adp -EM_PSIZE
- loi EM_PSIZE
- str 1 ; restore SP
- ret 0
- end 0
- pro $ChkSize, 0
- lol 0
- loc 3*EM_PSIZE+EM_WSIZE
- sbi EM_WSIZE
- dup EM_WSIZE
- stl 0
- loe StackSize
- cmu EM_WSIZE
- zle *1
- loc M2_TOOLARGE ; trap number for "stack size too large"
- trp
- 1
- lol 0
- loc EM_WSIZE-1
- adi EM_WSIZE
- loc EM_WSIZE
- dvi EM_WSIZE
- loc EM_WSIZE
- mli EM_WSIZE
- ret EM_WSIZE
- end 0
|