diff options
| author | user <user@clank> | 2026-07-16 00:12:43 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-16 00:12:43 +0200 |
| commit | 19a2b63bab71b796ee456b3ae8bec1a2ab297158 (patch) | |
| tree | 49b1effd335d47e859002903caea337fea27e1b9 /src/syscall.asm | |
| parent | kernel: implement exec() (diff) | |
| download | gbos-19a2b63bab71b796ee456b3ae8bec1a2ab297158.tar.gz gbos-19a2b63bab71b796ee456b3ae8bec1a2ab297158.tar.xz gbos-19a2b63bab71b796ee456b3ae8bec1a2ab297158.zip | |
kernel: complete the process lifecycle (exit/wait/reap + bank free list)
- exit(): zombie + status, reparent orphans to init, wake blocked parent,
schedule away forever (resources reclaimed by the reaper)
- wait(): scan for a zombie child; reap (free cart-RAM bank + PCB slot) and
return pid/code; block PS_BLOCKED + yield if children still live; $FF if none
- cart-RAM banks are now a free list (wBankUsed bitmap): AllocRamBank/FreeRamBank
- scheduler: FindNextReady returns carry when nothing runnable; yield idles
instead of blindly picking slot 0
- helpers: FindPcbByPid, ReparentToInit
- demo: init forks 3 workers -> exec -> exit(pid) -> wait/reap => wwwR2R3R4!
verified bank recycling with 6 workers over 3 banks (w2w3w4w5w6w7)
- README: document the lifecycle + syscall status
Diffstat (limited to 'src/syscall.asm')
| -rw-r--r-- | src/syscall.asm | 150 |
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 |
