Trailing-Edge
-
PDP-10 Archives
-
BB-D351C-SM_3-16-83
-
sources/xdispa.p11
There are 5 other files named xdispa.p11 in the archive. Click here to see a list.
.SBTTL XDISPA - task scheduler and dispatcher
; this section contains the dispatcher. it distributes cpu
; time among the tasks on a "non-preemptive" basis.
; that is, a task must deliberately relinquish control by
; calling "wait" before another task can get control.
;
; in addition, the once-per-clock-tick subroutines are called
; from here, as are the once-per-second subroutines.
;
; if a task takes too much time, the clock tick interrupt will
; issue a stopcode, so each task calls "wait" after only
; a little processing.
.REPT 0
COPYRIGHT (c) 1982,1981,1980, 1979
DIGITAL EQUIPMENT CORPORATION, maynard, mass.
THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
TRANSFERRED.
THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
CORPORATION.
DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
.ENDR
; REVISION HISTORY
; 4(001) BS ADD VERSION NUMBER
;
; 4(002) RLS MOVE LOOP CHECK FROM DSPIDL TO WAIT OTHERWISE IT REQUIRES
; ALL TASKS TO BE SIMULTANEOUSLY IDLE AT LEAST ONCE PER SECOND!!
; 4(003) RLS 25-Feb-81 remove task timer checking from DSPIDL and make
; function TSKTIK - called from CLKINT.
; Move calls to once/tick routines(DSPDQT,DSPDLT) from
; DSPIDL to CLKINT - made necessary by task timer change
; above. Of course, it should have been this way anyhow.
; make DSPUDC check if task waiting for timer whenever
; TCTIM is zero.
; 4(004) RLS 05-OCT-81 Move call to DSPDLS from dspidl to CLKINT.
VDISPT=004
VEDIT=VEDIT+VDISPT
.SBTTL SKED - the moby hyber function
ISKD: ;schedule a task interrupt
;2(SP)/interrupting task
;trace caller,interrupting task,previous interrupting task,current task
TRACE TRCINT!TRCDSP,<(SP),4(SP),SKDWRD,DSPTCB>
CMP 2(SP),DSPTCB ;check if interrupting self
BEQ 20$
SAVE R0
MOV 4(SP),R0 ;get the interrupting task tcb
CMPB TCPS(R0),SKDP ;compare priorities
BLOS 15$
;this one higher - schedule it
MOV R0,SKDWRD ;set reeskd flag
MOV TCPS(R0),SKDP
BISB #37,SKDP ;set up priority for comparing
15$: RESTOR R0 ;let the previous one ride
20$: MOV (SP)+,(SP) ;clean up stack and exit
RETURN
;all interrupts return through this function
.ENABL LSB
SKDCHK: TST SKDWRD ;check if scheduler pass required
BNE 10$ ;yes - go check interrupt level
5$: RTI ;no - just depart
10$: TSTB 2(SP) ;identify interrupted task by priority level
BMI 5$ ;must be an interrupt process(BR4=200)
TST DSPTCB ;not an interrupt process - check if task
BNE 15$
MOV #SKDINI,(SP) ;no - just the scheduler
MOV #BR7,2(SP) ;shut off the interrupts long enough to init
RTI ;force scheduler to restart
15$: ;yes - fall thru as though task volunteered
TRACE TRCLIN!TRCDSP,<R5,2(SP),SKDWRD,JIFCLK>
REESKD:
MOV 2(SP),-(SP) ;move wake loc and ps down on stack
MOV 2(SP),-(SP)
CLR 4(SP) ;stash args as if task were gentlemenly
CLR 6(SP) ;task is immediately runnable
.DSABL LSB
; SUBROUTINE TO WAIT UNTIL THE CONDITION SPECIFIED IN THE
; TCB HAS BEEN SATISFIED.
;EMT traps to here
; stack: wake location
; ps of caller
; wakeup time limit
; wake conditions - low byte
;interrupts are disabled
SKED: CMP R5,DSPTCB ;basic integrity check
BEQ 10$
STOPCD BUG ;can't allow this
10$: MOV (SP)+,TCPC(R5) ;SAVE PROGRAM COUNTER
MOV (SP)+,TCPS(R5) ;save the task ps
MOV (SP)+,TCTIM(R5) ;set wakeup time limit
BEQ 15$
BISB #EBTIME,(SP) ;set timer wakeup if non-zero time
15$: MOVB (SP)+,(R5) ;set wakeup events
BICB #EBTIME,TCEV(R5) ;task timer's always reset
TRACE TRCDSP,<R5,TCPC(R5),TCEW(R5)> ;trace hyber call and wakeup condtions
KGSAVE -(SP) ;save KG11 state
SAVE <R0,R1,R2,R3,R4>;save the task registers
MOV SP,TCSP(R5) ;SAVE STACK POINTER
;task state preserved now
SKDINI: ;enter here to init scheduler
CLR DSPTCB ;NO LONGER RUNNING A TASK
CLR SKDWRD ;note scheduler pass not needed
CLR SKDP ;allow any tasks to interrupt
MOV #PDL,SP ;SWITCH TO DISPATCHER STACK
CLR -(SP) ;SET UP STACK AS THOUGH FROM AN INTERRUPT
MOV #DISPATCH,-(SP) ;SO WE CAN CLEAR THE "T" BIT
20$: RTI ;DISMISS THE "INTERRUPT", I.E.,
; BRANCH TO DISPATCHER
; THIS IS THE MAIN ENTRY POINT AND THE RECYCLE POINT.
DISPATCH:
MOV TCBP1,R5 ;GET HIGHEST PRIORITY TASKS
CALL DISP
MOV TCBP2,R5 ;GET MEDIUM PRIORITY TCBS
CALL DISP
MOV TCBP3,R5 ;GET LOWEST PRIORITY TCBS
CALL DISP
JSR PC,DSPIDL ;DO IDLE TIME CODE
BR DISPATCH ; AND CHECK ALL TCBS AGAIN.
; SUBROUTINE TO TEST A TCB TO SEE IF THE TASK IS DISPATCHABLE.
; IF THE TASK IS DISPATCHABLE WE DISPATCH TO IT, OTHERWISE
; WE RETURN.
;
; R5/ptr to a tcb
DISP: TST R5 ;check for empty list
5$: BNE 6$ ;more to check
RETURN
6$: CLR R0 ;get the wakeup conditions
BISB TCWK(R5),R0
BEQ 15$ ;none => runnable
MOVB TCEV(R5),R1 ;get signalled events
COM R1
BIC #177400,R1
BIC R1,R0 ;flush those which haven't happened
BNE 10$ ;anything left have happened and cause wakeup
MOV TCHAIN(R5),R5 ;check rest of tasks on this chain
BR 5$
10$: MTPS #BR7 ;shut off world long enough to check current events
MOV R0,TCWKEV(R5) ;task is runnable
BICB R0,TCEV(R5) ;these events are now ancient history
BR 20$
;special case - do not mung task's last wake events in case he hasn't had a
; chance to check them yet!
15$: MTPS #BR7
20$: MOV R5,DSPTCB ; REMEMBER THE TCB
MOV TCPS(R5),SKDP
BIS #37,SKDP ;set task priority up for schedluer interrupts
TRACE TRCDSP,<R5,(R5),TCWKEV(R5)>;trace dispatch of task and reasons
MOV TCSP(R5),SP ;LOAD THE TASK'S STACK
RESTOR <R4,R3,R2,R1,R0>;restore task regs
KGLOAD (SP)+ ;restore KG11 status
MOV TCPS(R5),-(SP) ; AT TASK'S PRIORITY LEVEL
MOV TCPC(R5),-(SP) ;CREATE A PSEUDO-INTERRUPT
RTI ;GO RUN THE TASK.
; SUBROUTINE CALLED BY THE DISPATCHER WHEN ALL TASKS ARE WAITING.
DSPIDL: CMP DSPCLK,JIFCLK ;IS THE DISPATCHER CLOCK UP TO DATE?
BEQ 17$ ;NO - NUTHIN TODO
; HERE WHEN THE CLOCK HAS TICKED.
12$: MOV JIFCLK,R0 ;catch up to real time
SUB DSPCLK,R0
MOV JIFCLK,DSPCLK
ADD R0,DSPSEC
CMP R0,BSYMAX ;track max busy time between idle loop
BLE 13$
MOV R0,BSYMAX
13$: CMP DSPSEC,#JIFSEC ;REACHED ONE SECOND?
BLT 17$ ;NO.
SUB #JIFSEC,DSPSEC ;YES, CLEAR SECONDS COUNTER
INC DSPUPT ;INCREMENT UP TIME
BNE 14$
INC DSPUPT+2 ;ADD CARRY TO HIGH-ORDER WORD
14$: CMP DLGONE,#-6 ;CHECK FOR TEN DOWN TOO LONG
BGT 16$ ;NOT 5 SECONDS, JUST UPDATE STATUS
; HERE ONCE A SECOND AFTER THE 10 HAS BEEN GONE FOR A WHILE.
CALL INITDL ;TRY TO INITIALIZE THE DL10
; HERE ONCE A SECOND ANYHOW
16$:
17$: RETURN
; SUBROUTINE TO UPDATE THE CLOCKS IN A LIST OF TASKS
TSKTIK: ;update all task timers - called from CLKINT
MOV TCBP1,R5 ;GET HIGH PRIORITY TASKS
JSR PC,DSPUDC ;UPDATE THEIR CLOCKS
MOV TCBP2,R5 ;GET MEDIUM PRIORITY TASKS
JSR PC,DSPUDC ;UPDATE THEIR CLOCKS
MOV TCBP3,R5 ;GET LOW PRIORITY TASKS
CALL DSPUDC
MOV #NLINES,R0 ;check line timers
MOV #LINTBL,R1
10$: MOV (R1)+,R4 ;get an lcb
BEQ 15$ ;not created
TST LB.ALR(R4)
BEQ 15$ ;alarm not enabled
BIT #LS.ENB,(R4)
BEQ 14$ ;line not enabled
DEC LB.ALR(R4) ;count down alarm
BGT 15$ ;not expired yet
14$: CLR LB.ALR(R4) ;set alarm expired
MOV LB.TC1(R4),R5 ;get BSC task
BEQ 15$ ;none???
SIGNAL R5,EBALR ;signal alarm event
15$: SOB R0,10$
RETURN
DSPUDC: ;update all timers on R5/list of tasks
TST R5 ;ANY TASKS?
11$: BNE 12$ ;YES.
RTS PC ;NO, DONE WITH THIS LIST
12$: TST TCTIM(R5) ;HAS THIS TASK A TIMER?
BEQ 14$ ;NO.
DEC TCTIM(R5) ;YES, DECREMENT IT.
BNE 13$ ;BRANCH IF TIME NOT YET UP
14$: BIT #EBTIME,(R5) ;IS TASK WAITING FOR TIMER?
BEQ 13$ ;NO, IGNORE IT.
SIGNAL R5,EBTIME ;signal task timer expired
13$: MOV TCHAIN(R5),R5 ;GET NEXT TCB
BR 11$ ; AND TEST IT.