?? process.asm
字號:
include process.a
StdGrp group stdlib,stddata
stddata segment para public 'sldata'
wp equ <word ptr>
DefaultPCB pcb <>
DefaultCortn pcb <>
ProcessID dw 0
ReadyQ dd DefaultPCB
LastRdyQ dd DefaultPCB
CurCoroutine dd DefaultCortn ;Points at the currently executing
; coroutine.
TimerIntVect dd ?
SaveSP dw ? ;Temp holding location for fork.
SaveSS dw ? ;Temp holding location for fork.
stddata ends
stdlib segment para public 'slcode'
assume cs:stdgrp
; Special case to handle MASM 6.0 vs. all other assemblers:
; If not MASM 5.1 or MASM 6.0, set the version to 5.00:
ifndef @version
@version equ 500
endif
;
;
;
;============================================================================
; Process package.
; These routines handle multitasking/multiprogramming in the standard
; library.
;============================================================================
;
;
; sl_prcsinit- Initializes the process manager. By default, this guy
; assumes the use of the 1/18 second timer. At some future
; date I may add support for the AT msec timer.
;
; Warning: This code patches into several interrupts. If
; you call this routine in your program, you must call the
; sl_prcsquit routine before your program terminates. Other-
; wise the system will crash shortly thereafter.
public sl_prcsinit
;
sl_prcsinit proc far
assume ds:stdgrp
push ds
push es
push ax
push bx
push cx
push dx
mov ax, StdGrp
mov ds, ax
; Okay, set up this code as the first (and only) process currently in the
; ready queue:
mov ax, offset StdGrp:DefaultPCB
mov wp StdGrp:ReadyQ, ax
mov wp StdGrp:LastRdyQ, ax
mov ax, ds
mov wp StdGrp:ReadyQ+2, ax
mov wp StdGrp:LastRdyQ+2, ax
xor ax, ax
mov ProcessID, ax ;Start process IDs at 0
mov wp StdGrp:DefaultPCB.NextProc, ax
mov wp StdGrp:DefaultPCB.NextProc[2], ax
mov wp StdGrp:DefaultPCB.CPUTime+2, ax
mov wp StdGrp:DefaultPCB.CPUTime+2, 1
mov ah, 2ah ;Get the date.
int 21h
mov wp StdGrp:DefaultPCB.StartingDate, cx
mov wp StdGrp:DefaultPCB.StartingDate+2, dx
mov ah, 2ch ;Get the time.
int 21h
mov wp StdGrp:DefaultPCB.StartingTime, cx
mov wp StdGrp:DefaultPCB.StartingTime+2, dx
mov ax, 3508h ;Timer interrupt vector.
int 21h
mov wp StdGrp:TimerIntVect, bx
mov wp StdGrp:TimerIntVect+2, es
mov ax, 2508h ;Patch the dispatcher into the
mov dx, seg StdGrp:TimerISR ; timer interrupt.
mov ds, dx
mov dx, offset StdGrp:TimerISR
int 21h
pop dx
pop cx
pop bx
pop ax
pop es
pop ds
ret
sl_prcsinit endp
assume ds:nothing
; sl_prcsquit- This code restores the interrupt vectors patched by the
; sl_prcsinit routine. This routine *must* be called before
; you exit your program or the system will crash shortly
; thereafter.
public sl_prcsquit
sl_prcsquit proc far
assume ds:StdGrp
push ds
push es
push ax
mov ax, StdGrp
mov ds, ax
mov ax, 0
mov es, ax
; Cannot call DOS to restore this vector because this call might
; occur in a critical error or break handler routine.
pushf
cli
mov ax, word ptr StdGrp:TimerIntVect
mov es:[8*4], ax
mov ax, word ptr StdGrp:TimerIntVect+2
mov es:[8*4 + 2], ax
popf
pop ax
pop es
pop ds
ret
sl_prcsquit endp
assume ds:nothing
; sl_fork- Starts a new process. On entry, ES:DI points at a PCB.
; This routine initializes that process and adds it to the
; ready queue.
;
; WARNING: This routine assumes that the only information to
; copy off the stack is a far return address (to FORK). When
; fork returns there will be nothing sitting on the stack of
; the new process. Therefore, you should not call fork from
; inside a procedure if you expect the child process to return
; to the called procedure.
;
; This code assumes that you've initialized the ssSave and
; spSave fields of the new PCB with the address of a stack
; for that new process.
;
; This guy returns with AX=0 and BX=<ChildProcessID> to the
; parent process. It returns AX=<ChildProcessID> and BX=0
; to the child process.
public sl_fork
sl_fork proc far
assume ds:stdgrp
push bp
mov bp, sp
pushf
push ds
push cx
push dx
mov ax, stdgrp
mov ds, ax
if @version ge 600
; Initialize various fields in the new PCB:
; Start with the register. Remember, AX contains the process ID for the
; child process, BX contains zero for the child process. AX contains zero
; for the parent process, and BX contains the child process ID for the
; parent process.
;
; SS:SP should already be set up on entry (by the caller).
inc StdGrp:ProcessID ;Grab a new process ID.
mov ax, StdGrp:ProcessID
mov es:[di].pcb.regax, ax
mov es:[di].pcb.PrcsID, ax
mov wp es:[di].pcb.regbx, 0
mov es:[di].pcb.regcx, cx
mov es:[di].pcb.regdx, dx
mov ax, 0[bp] ;Get bp value off stack.
mov es:[di].pcb.regbp, ax
mov es:[di].pcb.regsi, si
mov es:[di].pcb.regdi, di
mov ax, [bp-4] ;Get ds value off stack.
mov es:[di].pcb.regds, ax
mov es:[di].pcb.reges, es
sti ;Must have interrupts on!
pushf
cli ;But the rest is a critical
pop ax ; section.
mov es:[di].pcb.regflags, ax
; The return address should be the return address for fork:
mov ax, 2[bp] ;Get return offset
mov es:[di].pcb.regip, ax
mov ax, 4[bp] ;Get return segment
mov es:[di].pcb.regcs, ax
; Set up accounting information (CPU time):
mov wp es:[di].pcb.CPUTime, 0
mov wp es:[di+2].pcb.CPUTime, 0
mov ah, 2ah ;Get the date.
int 21h
mov wp es:[di].pcb.StartingDate, cx
mov wp es:[di].pcb.StartingDate+2, dx
mov ah, 2ch ;Get the time.
int 21h
mov wp es:[di].pcb.StartingTime, cx
mov wp es:[di].pcb.StartingTime+2, dx
; Okay, now move the new PCB onto the ready queue (interrupts must be off
; while we're doing this!). Place this guy in the ready queue after the
; current process so it gets a time slice real soon.
cli
push es
push di
les di, StdGrp:ReadyQ
mov cx, wp es:[di].pcb.NextProc
mov dx, wp es:[di+2].pcb.NextProc
pop ax
mov wp es:[di].pcb.NextProc, ax
pop ax
mov wp es:[di+2].pcb.NextProc, ax
les di, es:[di].pcb.NextProc ;Pt ES:DI @ new prcs.
mov wp es:[di].pcb.NextProc, cx ;Link in prev 2nd
mov wp es:[di+2].pcb.NextProc, dx ; process.
; If there was only one process on the ready queue prior to adding this
; process, point the LastRdyQ pointer at the new process.
mov ax, wp StdGrp:ReadyQ
cmp ax, wp StdGrp:LastRdyQ
jne RdyNELast
mov ax, wp StdGrp:ReadyQ+2
cmp ax, wp StdGrp:LastRdyQ+2
jne RdyNELast
mov wp StdGrp:LastRdyQ, di
mov wp StdGrp:LastRdyQ+2, es
; Okay, return back to the calling code with AX=0 to denote that this is
; the parent routine returning. It also returns the child process ID in
; the BX register.
RdyNELast: xor ax, ax
mov bx, StdGrp:ProcessID
else ;TASM or MASM pre-6.0
inc StdGrp:ProcessID
mov ax, StdGrp:ProcessID
mov es:[di].regax, ax
mov es:[di].PrcsID, ax
mov wp es:[di].regbx, 0
mov es:[di].regcx, cx
mov es:[di].regdx, dx
mov ax, 0[bp]
mov es:[di].regbp, ax
mov es:[di].regsi, si
mov es:[di].regdi, di
mov ax, [bp-4]
mov es:[di].regds, ax
mov es:[di].reges, es
sti
pushf
cli
pop ax
mov es:[di].regflags, ax
mov ax, 2[bp]
mov es:[di].regip, ax
mov ax, 4[bp]
mov es:[di].regcs, ax
mov wp es:[di].CPUTime, 0
mov wp es:[di+2].CPUTime, 0
mov ah, 2ah
int 21h
mov wp es:[di].StartingDate, cx
mov wp es:[di].StartingDate+2, dx
mov ah, 2ch
int 21h
mov wp es:[di].StartingTime, cx
mov wp es:[di].StartingTime+2, dx
cli
push es
push di
les di, StdGrp:ReadyQ
mov cx, wp es:[di].NextProc
mov dx, wp es:[di+2].NextProc
pop ax
mov wp es:[di].NextProc, ax
pop ax
mov wp es:[di+2].NextProc, ax
les di, es:[di].NextProc
mov wp es:[di].NextProc, cx
mov wp es:[di+2].NextProc, dx
mov ax, wp StdGrp:ReadyQ
cmp ax, wp StdGrp:LastRdyQ
jne RdyNELast
mov ax, wp StdGrp:ReadyQ+2
cmp ax, wp StdGrp:LastRdyQ+2
jne RdyNELast
mov wp StdGrp:LastRdyQ, di
mov wp StdGrp:LastRdyQ+2, es
RdyNELast: xor ax, ax
mov bx, StdGrp:ProcessID
endif
pop dx
pop cx
pop ds
popf
pop bp
ret
sl_fork endp
assume ds:nothing
; sl_Die- Terminate the current process. If this is not the only
; process in the ready queue, then this code removes the current
; process from the ready queue and transfers control to the
; next process in the Ready Queue. Since the current process
; is not the the ready queue, this action effectively kills
; the current process.
;
; This routine will *not* delete the current process from the
; ready queue if it is the *only* process in the ready queue.
; In such an event, this code returns to the caller with the
; carry flag set (it returns this way because sl_Kill can call
; this routine and sl_Kill requires the carry set if an error
; occurs).
public sl_Die
sl_Die proc far
assume ds:StdGrp
pushf ;Push registers onto the stack just
push ds ; in case there is an error return.
push di
mov di, StdGrp
mov ds, di
cli ;Critical region ahead!
if @version ge 600
les di, StdGrp:ReadyQ
cmp wp es:[di].pcb.NextProc+2, 0
jne GoodDIE
; YIKES! The caller is trying to delete the only process in the ReadyQ.
; We can't let that happen, so return an error down here.
pop di
pop ds
stc
ret
; Okay, this DIE operation can proceed. Handle that down here.
GoodDIE: mov ax, wp es:[di].pcb.NextProc
mov wp StdGrp:ReadyQ, ax
mov ax, wp es:[di].pcb.NextProc+2
mov wp StdGrp:ReadyQ+2, ax
; The following code, which passes control to the new "current process"
; must look exactly like the code at the tail end of the dispatcher!
; In particular, the values pushed at the beginning of this routine are
; history. They are on a different stack, which will not be accessed again,
; so we do not need to worry about them.
les di, StdGrp:ReadyQ
inc wp es:[di].pcb.CPUTime
jne NoHOIncCPU
inc wp es:[di+2].pcb.CPUTime
NoHOIncCPU: mov ss, es:[di].pcb.regss
mov sp, es:[di].pcb.regsp
push es:[di].pcb.regflags
push es:[di].pcb.regcs
push es:[di].pcb.regip
mov ax, es:[di].pcb.regax
mov bx, es:[di].pcb.regbx
mov cx, es:[di].pcb.regcx
mov dx, es:[di].pcb.regdx
mov bp, es:[di].pcb.regbp
mov si, es:[di].pcb.regsi
mov ds, es:[di].pcb.regds
push es:[di].pcb.regdi
mov es, es:[di].pcb.reges
pop di
iret
else
les di, StdGrp:ReadyQ
cmp wp es:[di].NextProc+2, 0
jne GoodDIE
pop di
pop ds
stc
ret
GoodDIE: mov ax, wp es:[di].NextProc
mov wp StdGrp:ReadyQ, ax
mov ax, wp es:[di].NextProc+2
mov wp StdGrp:ReadyQ+2, ax
les di, StdGrp:ReadyQ
inc wp es:[di].CPUTime
jne NoHOIncCPU
inc wp es:[di+2].CPUTime
NoHOIncCPU: mov ss, es:[di].regss
mov sp, es:[di].regsp
push es:[di].regflags
push es:[di].regcs
push es:[di].regip
mov ax, es:[di].regax
mov bx, es:[di].regbx
mov cx, es:[di].regcx
mov dx, es:[di].regdx
mov bp, es:[di].regbp
mov si, es:[di].regsi
mov ds, es:[di].regds
push es:[di].regdi
mov es, es:[di].reges
pop di
iret
endif
sl_DIE endp
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -