Path: utzoo!attcan!uunet!aplcen!uakari.primate.wisc.edu!zaphod.mps.ohio-state.edu!usc!ucsd!ucbvax!hplabs!hpda!hpcuhc!hpsemc!jmorris From: jmorris@hpsemc.HP.COM (John V. Morris) Newsgroups: comp.sys.hp Subject: Re: HPPA Context switching code - still having problems Message-ID: <1250036@hpsemc.HP.COM> Date: 2 Jul 90 22:14:25 GMT References: <7748@ccncsu.ColoState.EDU> Organization: HP Technology Access Center, Cupertino, CA Lines: 269 Here's another version of the coroutine stuff. This version saves and restores registers directly instead of using setjmp/longjmp. John Morris HP VAB Partners Lab (408)725-3871 ----------------------------- Cut Here ----------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, # then unwrap it by saving it in a file and typing "sh file". # # Wrapped by jmorris at hpsemc on Mon Jul 2 15:09:19 1990 # Contents: # Makefile coroutine.s test.c PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:$PATH; export PATH echo 'At the end, you should see the message "End of shell archive."' echo Extracting Makefile sed 's/^@//' >Makefile <<'@//E*O*F Makefile//' all: coroutine.o test test: test.o coroutine.o cc -g test.o coroutine.o -o test @.s.o: cc -c $*.s @//E*O*F Makefile// set `wc -lwc coroutine.s <<'@//E*O*F coroutine.s//' ;************************************************************************* ; ; char stack[STACKSIZE]; ; typedef int environment[1]; ; ; environment env; ; environment oldenv, newenv; ; ; coroutine(env, routine, param, stack, STACKSIZE); ; ; resume(oldenv, newenv) ; ; Coroutine() initializes a new co-routine. ; Co-routines are very similar to processes, but they all take place ; inside one UNIX process. Since the operating system is not involved, ; the context switch time ("resume" time) is very short. ; ; Resume() switches from one co-routine to another. The current context ; is saved in oldenv, and the new context is loaded from newenv. ; ; When a co-routine is activated the first time, the specified procedure ; will be invoked with the specified parameter. The procedure should ; not return. (It should resume to another coroutine, or exit). ; ; History ; 900702 John Morris Anticipating shared libraries. Code is now position ; independent and it saves gr19 as well. ; ; 900702 John Morris Using the .enter and .leave macros to save and restore ; registers in the stack. Environment only contains ; the stack pointer. ; ; 891103 John Morris Now saving and restoring registers directly instead ; of calling setjmp, longjmp. Should work on MPE-XL now. ; ; 891031 John Morris Changed call to $$dyncall to match conventions. ; Linker was blindly replacing the bl $$dyncall,2 ; with ble $$dyncall, and return address was messed up. ; ; 880506 John Morris Changed name to "coroutine" and included the resume ; function in same file. Also, added parameter that ; gets passed to coroutine the first time it is invoked. ; Use $$dyncall to do dynamic subroutine call instead ; of ble instruction. ; ; 870000 John Morris Originally written to satisfy various customer's needs ; at the HP Technology Access Center. ;************************************************************************** .code #define env arg0 #define routine arg1 #define param arg2 #define stack arg3 #define size r31 #define temp r31 .import $$dyncall ; void coroutine(env, routine, param, stack, size); ;************************************************************************ ; coroutine creates a 'setjmp' environment with a new stack ;************************************************************************ coroutine .proc .callinfo .export coroutine .enter ; Note that 'size' is not actually used by this routine. It is necessary ; if equivalent routines are to be implemented on other architectures ; (for example, if stack grows down instead of up). ; align the new stack area to an 8 byte boundary addi 7, stack, stack ; add 7 to round up depi 0, 31, 3, stack ; clear the low 3 bits, effect is to round up. ; define a dummy stack frame to serve as the "main" addi 48, stack, stack ; allocate the smallest stack frame ; define the frame used during the "newstate" fragment. stw r0, -20(stack) ; set a zero return address for debugger addi 56, stack, stack ; allocate stack frame with two integers. stw routine, -56(stack) ; save the routine address to invoke later on stw param, -52(stack) ; save the parameter to pass on ; define the frame inside the "resume" program. bl .+8, temp ; get the address of newstate ldo newstate-oldstate(temp), temp ; (position independent in case we oldstate ; want to use it in shared libraries) stw temp,-20(stack) ; save "newstate" as the return address addi 112, stack, stack ; MUST MATCH FRAME SIZE OF RESUME(). ; initial values of registers don't matter. ; save the stack pointer in the environment variable stw stack,0(env) ; save the new stack pointer ; done .leave .procend ; void newstate() ;******************************************************************* ; newstate is the the first code executed when a new coroutine starts up ;******************************************************************* ; newstate takes care of the initial dynamic procedure call. Doing the ; call indirectly solves a number of problems relating to cross-space ; jumps. It also makes it easy to pass a parameter to the starting ; procedure. ; ; Note that newstate does not actually get called, but resume() "returns" ; to it the first time a coroutine gets started up. ; .proc .callinfo caller, frame=8 newstate ; call the initial routine, passing it the specified parameter ldw -56(sp), r22 ; get the procedure address from stack ldw -52(sp), arg0 ; get the parameter we saved in the stack .call bl $$dyncall, 31 ; invoke the procedure copy 31, rp ; (Note: linker substitutes ble for bl) ; the routine should not return break .procend old .equ arg0 new .equ arg1 ; resume(old, new) ;********************************************************************* ; resume switches context from one coroutine to another ;********************************************************************* .proc .callinfo save_rp, entry_gr=19, entry_fr=15, entry_sr=3 .export resume resume .enter ; save the old stack pointer and restore the new stw sp, 0(old) ldw 0(new), sp ; done .leave .procend @//E*O*F coroutine.s// set `wc -lwc test.c <<'@//E*O*F test.c//' /****************************************************************** Test program for coroutines. Creates a bunch of coroutines, and then switches among them **********************************************************************/ #define COUNT 10 typedef int environment[1]; typedef char stack_type[50000]; /* allocate a stack and a context for each coroutine */ /* (also, allocate an extra context for the main program) */ environment env[COUNT+1]; stack_type stack[COUNT]; main() { int i, proc(); /* create the coroutines */ for (i = 0; i