process.asm
来自「汇编编程艺术」· 汇编 代码 · 共 1,414 行 · 第 1/3 页
ASM
1,414 行
; sl_kill- Terminates some other process. If this call kills the current
; process, it effectively becomes a "die" call. On entry, AX
; must contain the process ID of the process to kill.
; Returns carry set if no such process exists. Returns carry
; clear if it killed the process. It is your responsibility
; to ensure all resources in use by the killed process are
; freed.
;
; Note that this routine may *not* return if it kills
; itself (see sl_Die for more details).
public sl_kill
sl_kill proc far
assume ds:StdGrp
pushf
push ds
push es
push ax
push bx
push cx
push di
mov di, StdGrp
mov ds, di
cli ;Critical region ahead!
if @version ge 600
les di, StdGrp:ReadyQ ;See if this is a die oper-
cmp ax, es:[di].pcb.PrcsID ; ation.
jne DoKill
pop di
pop cx
pop bx
pop ax
pop es
pop ds
popf
jmp sl_Die
; If it's not the current process, search for the process in the ready queue.
DoKill: cmp wp es:[di].pcb.NextProc+2, 0 ;Error if not
je BadKill ; present in rdy Q.
mov bx, di
mov cx, es
les di, es:[di].pcb.NextProc
cmp ax, es:[di].pcb.PrcsID
jne DoKill
; Okay, remove the PCB pointed at by ES:DI from the ready queue. Note that
; CX:BX points at the previous entry in the queue.
StopHere:
mov ax, wp es:[di].pcb.NextProc+2
mov di, wp es:[di].pcb.NextProc
xchg di, bx
mov es, cx
mov wp es:[di].pcb.NextProc, bx
mov wp es:[di].pcb.NextProc+2, ax
else
les di, StdGrp:ReadyQ
cmp ax, es:[di].PrcsID
jne DoKill
pop di
pop cx
pop bx
pop ax
pop es
pop ds
popf
jmp sl_Die
DoKill: cmp wp es:[di].NextProc+2, 0
je BadKill
mov bx, di
mov cx, es
les di, es:[di].NextProc
cmp ax, es:[di].PrcsID
jne DoKill
StopHere:
mov ax, wp es:[di].NextProc+2
mov di, wp es:[di].NextProc
xchg di, bx
mov es, cx
mov wp es:[di].NextProc, bx
mov wp es:[di].NextProc+2, ax
endif
pop di
pop cx
pop bx
pop ax
pop es
pop ds
popf
clc
ret
BadKill: pop di
pop cx
pop bx
pop ax
pop es
pop ds
popf
stc
ret
sl_Kill endp
;============================================================================
;
; sl_Yield- Cause the current process to give up the remainder of its
; time slice.
;
; *** This is the Dispatcher ***
;
; This guy is also responsible for switching to a new process whenever a
; timer interrupt comes along.
public sl_Yield
sl_Yield proc far
assume ds:StdGrp, es:StdGrp
pushf
cli
push ds
push di
; Save the state of the current process.
if @version ge 600
mov di, StdGrp
mov ds, di
lds di, StdGrp:ReadyQ ;Get ptr to current PCB.
mov [di].pcb.regax, ax
mov [di].pcb.regbx, bx
mov [di].pcb.regcx, cx
mov [di].pcb.regdx, dx
mov [di].pcb.regbp, bp
mov [di].pcb.regsi, si
mov [di].pcb.reges, es
pop [di].pcb.regdi
pop [di].pcb.regds
pop [di].pcb.regflags
pop [di].pcb.regip
pop [di].pcb.regcs
mov [di].pcb.regsp, sp
mov [di].pcb.regss, ss
; Adjust the CPU time for the process we've just stopped.
inc wp [di].pcb.CPUTime
jne NoHOCPUTime
inc wp [di+2].pcb.CPUTime
NoHOCPUTime:
; The following kludge takes care of the case where there is only one process
; active in the ready queue:
cmp wp [di].pcb.NextProc+2, 0
je RequeueDone
; If not the only entry, move it to the end of the ready queue here.
; Begin by storing a pointer to the current process in the NextProc field
; of the last process in the queue:
mov di, StdGrp
mov ds, di
les di, StdGrp:LastRdyQ
mov ax, wp StdGrp:ReadyQ
mov wp StdGrp:LastRdyQ, ax
mov wp es:[di].pcb.NextProc, ax
mov ax, wp StdGrp:ReadyQ+2
mov wp StdGrp:LastRdyQ+2, ax
mov wp es:[di].pcb.NextProc+2, ax
; Now get the next process in the chain after the current process and make
; it the new process to execute by placing it at the front of the ready queue:
les di, StdGrp:ReadyQ
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
xor ax, ax
mov wp es:[di].pcb.NextProc, ax
mov wp es:[di].pcb.NextProc+2, ax
RequeueDone:
; Okay, transfer control to the (possibly new) procedure at the front of the
; ready queue:
mov di, StdGrp
mov ds, di
lds di, StdGrp:ReadyQ
mov ss, [di].pcb.regss
mov sp, [di].pcb.regsp
push [di].pcb.regflags
push [di].pcb.regcs
push [di].pcb.regip
push [di].pcb.regdi
mov ax, [di].pcb.regax
mov bx, [di].pcb.regbx
mov cx, [di].pcb.regcx
mov dx, [di].pcb.regdx
mov bp, [di].pcb.regbp
mov si, [di].pcb.regsi
mov es, [di].pcb.reges
mov ds, [di].pcb.regds
pop di
iret
else
mov di, StdGrp
mov ds, di
lds di, StdGrp:ReadyQ
mov [di].regax, ax
mov [di].regbx, bx
mov [di].regcx, cx
mov [di].regdx, dx
mov [di].regbp, bp
mov [di].regsi, si
mov [di].reges, es
pop [di].regdi
pop [di].regds
pop [di].regflags
pop [di].regip
pop [di].regcs
mov [di].regsp, sp
mov [di].regss, ss
inc wp [di].CPUTime
jne NoHOCPUTime
inc wp [di+2].CPUTime
NoHOCPUTime:
cmp wp [di].NextProc+2, 0
je RequeueDone
mov di, StdGrp
mov ds, di
les di, StdGrp:LastRdyQ
mov ax, wp StdGrp:ReadyQ
mov wp StdGrp:LastRdyQ, ax
mov wp es:[di].NextProc, ax
mov ax, wp StdGrp:ReadyQ+2
mov wp StdGrp:LastRdyQ+2, ax
mov wp es:[di].NextProc+2, ax
les di, StdGrp:ReadyQ
mov ax, wp es:[di].NextProc
mov wp StdGrp:ReadyQ, ax
mov ax, wp es:[di].NextProc+2
mov wp StdGrp:ReadyQ+2, ax
xor ax, ax
mov wp es:[di].NextProc, ax
mov wp es:[di].NextProc+2, ax
RequeueDone:
mov di, StdGrp
mov ds, di
lds di, StdGrp:ReadyQ
mov ss, [di].regss
mov sp, [di].regsp
push [di].regflags
push [di].regcs
push [di].regip
push [di].regdi
mov ax, [di].regax
mov bx, [di].regbx
mov cx, [di].regcx
mov dx, [di].regdx
mov bp, [di].regbp
mov si, [di].regsi
mov es, [di].reges
mov ds, [di].regds
pop di
iret
endif
sl_Yield endp
assume ds:nothing, es:nothing
;============================================================================
;
; Coroutine support.
;
; COINIT- ES:DI contains the address of the current (default) process.
; COINIT will store away this address into the local CurCoroutine variable.
; Strictly speaking, you do not need to call this code as the system will
; use the "DefaultCortn" if you do not supply a PCB for the 1st process.
; However, this variable is not visible outside this file so all future
; references would have to be through the ES:DI value returned by COCALL.
public sl_coinit
sl_CoInit proc far
assume ds:StdGrp
push ax
push ds
mov ax, StdGrp
mov ds, ax
mov wp StdGrp:CurCoroutine, di
mov wp StdGrp:CurCoroutine+2, es
pop ds
pop ax
ret
sl_CoInit endp
; COCALL- transfers control to a coroutine. ES:DI contains the address
; of the PCB. This routine transfers control to that coroutine and then
; returns a pointer to the caller's PCB in ES:DI.
public sl_cocall
sl_cocall proc far
assume ds:StdGrp
pushf
push ds
push es ;Save these for later
push di
push ax
mov ax, StdGrp
mov ds, ax
cli ;Critical region ahead.
if @version ge 600
; Save the current process' state:
les di, StdGrp:CurCoroutine
pop es:[di].pcb.regax
mov es:[di].pcb.regbx, bx
mov es:[di].pcb.regcx, cx
mov es:[di].pcb.regdx, dx
mov es:[di].pcb.regsi, si
pop es:[di].pcb.regdi
mov es:[di].pcb.regbp, bp
pop es:[di].pcb.reges
pop es:[di].pcb.regds
pop es:[di].pcb.regflags
pop es:[di].pcb.regip
pop es:[di].pcb.regcs
mov es:[di].pcb.regsp, sp
mov es:[di].pcb.regss, ss
mov bx, es ;Save so we can return in
mov cx, di ; ES:DI later.
mov dx, es:[di].pcb.regdi
mov es, es:[di].pcb.reges
mov di, dx ;Point es:di at new PCB
mov wp StdGrp:CurCoroutine, di
mov wp StdGrp:CurCoroutine+2, es
mov es:[di].pcb.regdi, cx ;The ES:DI return values.
mov es:[di].pcb.reges, bx
; Okay, switch to the new process:
mov ss, es:[di].pcb.regss
mov sp, es:[di].pcb.regsp
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 si, es:[di].pcb.regsi
mov bp, es:[di].pcb.regbp
mov ds, es:[di].pcb.regds
push es:[di].pcb.regflags
push es:[di].pcb.regcs
push es:[di].pcb.regip
push es:[di].pcb.regdi
mov es, es:[di].pcb.reges
pop di
iret
else
les di, StdGrp:CurCoroutine
pop es:[di].regax
mov es:[di].regbx, bx
mov es:[di].regcx, cx
mov es:[di].regdx, dx
mov es:[di].regsi, si
pop es:[di].regdi
mov es:[di].regbp, bp
pop es:[di].reges
pop es:[di].regds
pop es:[di].regflags
pop es:[di].regip
pop es:[di].regcs
mov es:[di].regsp, sp
mov es:[di].regss, ss
mov bx, es
mov cx, di
mov dx, es:[di].regdi
mov es, es:[di].reges
mov di, dx
mov wp StdGrp:CurCoroutine, di
mov wp StdGrp:CurCoroutine+2, es
mov es:[di].regdi, cx
mov es:[di].reges, bx
mov ss, es:[di].regss
mov sp, es:[di].regsp
mov ax, es:[di].regax
mov bx, es:[di].regbx
mov cx, es:[di].regcx
mov dx, es:[di].regdx
mov si, es:[di].regsi
mov bp, es:[di].regbp
mov ds, es:[di].regds
push es:[di].regflags
push es:[di].regcs
push es:[di].regip
push es:[di].regdi
mov es, es:[di].reges
pop di
iret
endif
sl_cocall endp
; CoCalll works just like cocall above, except the address of the pcb
; follows the call in the code stream rather than being passed in ES:DI.
; Note: this code does *not* return the caller's PCB address in ES:DI.
;
public sl_cocalll
sl_cocalll proc far
assume ds:StdGrp
push bp
mov bp, sp
pushf
push ds
push es
push di
push ax
mov ax, StdGrp
mov ds, ax
cli ;Critical region ahead.
if @version ge 600
; Save the current process' state:
les di, StdGrp:CurCoroutine
pop es:[di].pcb.regax
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?