; Contextml.asm ; L. Stewart, December 8, 1982 4:13 PM ; modified to maintain ←stackLimit, L. Stewart, October 5, 1982 12:51 PM ; directly manipulated wakeup disable counter ; November 8, 1982 3:06 PM, use osstatics.c ; November 10, 1982 3:49 PM, add max runtime stuff ; December 8, 1982 4:13 PM, remove blken ; February 23, 1983 3:10 PM, remove osstatics ; March 3, 1983 2:42 PM, access to statics $INCLUDE(Lark.d) C←CODE SEGMENT CTXNext EQU 0 ; link field CTXsp EQU 2 ; saved stack pointer CTXBase EQU 4 ; stack limit CTXpc EQU 6 ; initial PC CTXnm EQU 8 ; string name of context CTXmr EQU 10 ; maxrun CTXcl EQU 12 ; caller who ran maxrun lenCTX EQU 30 ; bytes, leave space for RPC and system C←DATA SEGMENT EXTRN ←stackLimit:WORD EXTRN ←wdc:WORD ; following statics must stay in order for GetCtxData to work ←CtxRunning DW 0 ←ctxCal DW 0 ←startT DW 0 dummyC DW 0 DW ? dummySL DW ? DW ? dummynm DW ? DW ? DW ? C←DATA ENDS ASSUME CS:C←CODE, DS:C←DATA, ES:C←DATA EXTRN ←Zero:NEAR EXTRN ←CallDebugger:NEAR ←CurrentContext PROC NEAR MOV BX,←CtxRunning RET ←CurrentContext ENDP ←InitCtxPkg PROC NEAR MOV ←ctxCal,0 MOV DI,OFFSET dummyC CLD MOV ←CtxRunning, DI XOR AX,AX STOSW STOSW MOV AX,←stackLimit STOSW XOR AX,AX STOSW MOV AX,"noContext" STOSW RET ←InitCtxPkg ENDP ; struct ctx *InitNContext(name, region, length, proc) ; char *name; /* string */ ; char *region; /* base of available space */ ; int length; /* length in words of available space */ ; int proc(); /* proc to call on first invocation */ ; returns ; struct RPCCtx * see context.h ←InitNContext PROC NEAR PUSH BP MOV BP,SP MOV AX,[4+BP] ; region PUSH AX CALL ←InitContext POP AX ; dump arguement MOV AX,[6+BP] ; fetch name MOV [CTXnm+BX],AX ; put into context MOV SP,BP POP BP RET ←InitNContext ENDP ; struct ctx *InitContext(region, length, proc) ; char *region; /* base of available space */ ; int length; /* length in words of available space */ ; int proc(); /* proc to call on first invocation */ ; returns ; struct RPCCtx * see context.h ; InitContext puts the context structure at the top of the region ; because the stack grows downwards. The initial value of the ; frame pointer will be 0 when proc is called. This is a clue to ; stack tracers that it is the first frame. ←InitContext PROC NEAR PUSH BP MOV BP,SP ; zero it PUSH CX PUSH BX MOV BX,CX ; length MOV CX,[4+BP] ; region CALL ←Zero POP BX POP CX ; continue MOV SI,[4+BP] ; region MOV DI,SI ; copy it ADD DI,CX ; add length *2 ADD DI,CX SUB DI,lenCTX ; construct pointer to base of ctx MOV WORD PTR [CTXNext+DI], 0 MOV [CTXBase+DI],SI ; set stackbase MOV WORD PTR [CTXnm+DI], 0 ; name MOV [CTXpc+DI],BX ; proc LEA BX,[DI-2] ; addr of first frame word on stack MOV [CTXsp+DI],BX ; set initial sp to just below ctx MOV WORD PTR [BX],0 ; initial frame pointer MOV BX,DI ; return context MOV SP,BP POP BP RET ←InitContext ENDP ; CallContext(c) ; struct ctx *c; ←CallContext LABEL NEAR PUSH BP PUSH ←stackLimit ; save stackLimit PUSH ←ctxCal ; save previous ctxCal PUSH ←CtxRunning ; save running context MOV ←ctxCal,SP ; save this ctxCal JMP nxtCtx ; jump into Block code ←Block LABEL NEAR MOV BX,←CtxRunning ; pick up current context PUSH BP ; save frame pointer MOV [CTXsp+BX],SP ; save stack pointer ; measure runtime MOV SI,clklo MOV AX,[SI] ; get new time SUB AX,←startT ; subtract start time CMP AX,[CTXmr+BX] ; new record? JNA blkb MOV [CTXmr+BX],AX MOV SI,SP MOV AX,[2+SI] MOV [CTXcl+BX],AX blkb: MOV BX,[CTXNext+BX] ; next context to try ; here to resume next context on list nxtCtx: OR BX,BX ; check for end of list ; or 0 arg to CallContext JZ donCtx ; none left MOV ←CtxRunning,BX ; save new context runCtx: MOV BX,clklo MOV AX,[BX] MOV ←startT,AX CMP ←wdc,0 JNZ ←BADBLK CLI ; fast IWDC MOV BX,←CtxRunning MOV SP,[CTXsp+BX] ; load saved stack pointer MOV AX,[CTXBase+BX] ; load saved stack limit ADD AX,018H ; 24 byte cushion MOV ←stackLimit,AX ; checked by StkChk CMP ←wdc,0 ; fast DWDC JNZ iwasoff STI iwasoff: POP BP ; load saved frame pointer OR BP,BP ; if frame==0, call proc JZ firstRun RET ; return from Block in new process firstRun: MOV AX,[CTXpc+BX] CALL AX ; call procedure with ctx as arg JMP ←Block ; if it returns, call again ←BADBLK: ; musn't block with ints disabled MOV BX,08765H CALL ←CallDebugger donCtx: MOV AX,←ctxCal ; restore stack of ctxCal OR AX,AX JZ notCtx ; Block called from outside MOV SP,AX POP ←CtxRunning POP ←ctxCal POP ←stackLimit POP BP RET ; return from CallContext ; If Block is called from outside any CallContext, it just returns notCtx: MOV BX,←CtxRunning JMP runCtx ←GetCtxData PROC NEAR MOV BX,OFFSET ←CtxRunning RET ←GetCtxData ENDP PUBLIC ←CtxRunning PUBLIC ←ctxCal PUBLIC ←InitCtxPkg PUBLIC ←Block PUBLIC ←CurrentContext PUBLIC ←InitNContext ; PUBLIC ←InitContext PUBLIC ←CallContext PUBLIC ←GetCtxData C←CODE ENDS END