aboutsummaryrefslogtreecommitdiffstats
path: root/src/syscall.asm
diff options
context:
space:
mode:
Diffstat (limited to 'src/syscall.asm')
-rw-r--r--src/syscall.asm150
1 files changed, 139 insertions, 11 deletions
diff --git a/src/syscall.asm b/src/syscall.asm
index fd1b213..4b8771c 100644
--- a/src/syscall.asm
+++ b/src/syscall.asm
@@ -41,7 +41,7 @@ SyscallTable:
dw sys_nosys ; 4 OPEN (TODO)
dw sys_nosys ; 5 CLOSE (TODO)
dw sys_exec ; 6 EXEC
- dw sys_nosys ; 7 WAIT (TODO)
+ dw sys_wait ; 7 WAIT
dw sys_getpid ; 8 GETPID
dw sys_nosys ; 9 KILL (TODO)
dw sys_nosys ; 10 BRK (TODO)
@@ -91,17 +91,21 @@ sys_yield:
ret
; -----------------------------------------------------------------------------
-; sys_exit(code=B) -- mark zombie and schedule away forever.
+; sys_exit(code=B) -- become a zombie awaiting reap; never returns.
+; - store exit code, set PS_ZOMBIE
+; - reparent any children to init (so they can still be waited on)
+; - wake our parent if it is blocked in wait()
+; - schedule away forever (RAM bank + PCB slot are freed by the reaper)
; -----------------------------------------------------------------------------
sys_exit:
- ; mark current PCB as zombie, store exit code
+ ; PROC_STATE = PS_ZOMBIE
ld a, [wCurProc]
ld l, a
ld a, [wCurProc+1]
- ld h, a ; HL = &PCB
+ ld h, a
ld a, PS_ZOMBIE
- ld [hl], a ; PROC_STATE
- ; PROC_EXIT is at offset PROC_EXIT
+ ld [hl], a
+ ; PROC_EXIT = B
ld a, [wCurProc]
add PROC_EXIT
ld l, a
@@ -109,9 +113,133 @@ sys_exit:
adc 0
ld h, a
ld a, b
- ld [hl], a ; exit code
- ; never return to this task
+ ld [hl], a
+ ; stash my pid + parent pid
+ ld a, [wCurProc]
+ add PROC_PID
+ ld l, a
+ ld a, [wCurProc+1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ ld [wExitMyPid], a
+ ld a, [wCurProc]
+ add PROC_PARENT
+ ld l, a
+ ld a, [wCurProc+1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ ld [wExitParentPid], a
+ ; hand any children to init
+ call ReparentToInit
+ ; wake our parent if it's blocked in wait()
+ ld a, [wExitParentPid]
+ call FindPcbByPid ; DE=&parent PCB, CF if gone
+ jr c, .gone
+ ld a, [de]
+ cp PS_BLOCKED
+ jr nz, .gone
+ ld a, PS_READY
+ ld [de], a
+.gone
+ ; never run this process again
+.dead
call SchedYield
- ; if we somehow come back (no other ready task), spin
-.halt
- jr .halt
+ jr .dead
+
+; -----------------------------------------------------------------------------
+; sys_wait() -- reap a zombie child.
+; out: A = child pid, B = exit code; or A = $FF if we have no children.
+; Blocks (PS_BLOCKED) until a child becomes a zombie.
+; -----------------------------------------------------------------------------
+sys_wait:
+ ld a, [wCurProc]
+ add PROC_PID
+ ld l, a
+ ld a, [wCurProc+1]
+ adc 0
+ ld h, a
+ ld a, [hl]
+ ld [wWaitMyPid], a
+.retry
+ ld c, 0 ; slot cursor
+ ld b, 0 ; "any child exists" flag
+.scan
+ ld a, c
+ call PcbPtr ; DE=&PCB[c] (preserves BC)
+ ld a, [de]
+ cp PS_FREE
+ jr z, .next
+ ; parent == my pid ?
+ ld h, d
+ ld l, e
+ ld a, l
+ add PROC_PARENT
+ ld l, a
+ ld a, h
+ adc 0
+ ld h, a
+ ld a, [wWaitMyPid]
+ cp [hl]
+ jr nz, .next
+ ld b, 1 ; we have at least one child
+ ld a, [de] ; state (DE still = base)
+ cp PS_ZOMBIE
+ jr z, .reap
+.next
+ inc c
+ ld a, c
+ cp MAX_PROCS
+ jr c, .scan
+ ; finished scan: any children?
+ ld a, b
+ or a
+ jr z, .nochild
+ ; children exist but none are zombies: block and yield, then retry
+ ld a, [wCurProc]
+ ld l, a
+ ld a, [wCurProc+1]
+ ld h, a
+ ld a, PS_BLOCKED
+ ld [hl], a
+ call SchedYield
+ ld a, [wCurProc]
+ ld l, a
+ ld a, [wCurProc+1]
+ ld h, a
+ ld a, PS_READY
+ ld [hl], a
+ jr .retry
+.reap
+ ; DE = &zombie child PCB
+ ld h, d
+ ld l, e
+ inc hl ; ->PROC_PID
+ ld a, [hl]
+ ld [wWaitRetPid], a
+ ld a, e
+ add PROC_EXIT
+ ld l, a
+ ld a, d
+ adc 0
+ ld h, a
+ ld a, [hl]
+ ld [wWaitRetCode], a
+ ld a, e
+ add PROC_RAMB
+ ld l, a
+ ld a, d
+ adc 0
+ ld h, a
+ ld a, [hl]
+ call FreeRamBank ; recycle the child's cart-RAM bank
+ ld a, PS_FREE
+ ld [de], a ; free the PCB slot
+ ld a, [wWaitRetCode]
+ ld b, a
+ ld a, [wWaitRetPid]
+ ret
+.nochild
+ ld a, $FF
+ ret