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 + -
显示快捷键?