; ============================================================================= ; tasks.asm - init exercises the full process lifecycle. ; ; init fork()s three children; each child exec()s PROG_WORKER, which prints 'w' ; and exit()s with its pid as the status. init then wait()s in a loop, printing ; 'R' + the reaped pid digit for each child, until wait() returns $FF (no more ; children), then prints '!' and idles. This drives fork + exec + exit + wait + ; zombie reaping + cart-RAM bank recycling. ; ; The fork counter lives at $A000 (bottom of init's own RAM bank) because the ; register file does not survive a fork() call. ; ============================================================================= INCLUDE "include/gbos.inc" DEF ASCII0 EQU $30 ; '0', added to a pid to print it as a digit DEF CH_R EQU $52 ; 'R' DEF CH_BANG EQU $21 ; '!' SECTION "tasks", ROM0 TaskInit:: ld a, 3 ld [$A000], a ; children left to spawn .forkloop ld c, SYS_FORK rst $30 or a jr z, .child ; A==0 -> we are the child ; parent: one more child spawned ld a, [$A000] dec a ld [$A000], a jr nz, .forkloop .waitloop ld c, SYS_WAIT rst $30 ; A = reaped pid (B = code), or $FF if none left cp $FF jr z, .done ; print 'R' then the reaped pid as a digit push af ld a, CH_R ld [$FF01], a ld a, $81 ld [$FF02], a pop af add ASCII0 ld [$FF01], a ld a, $81 ld [$FF02], a jr .waitloop .done ld a, CH_BANG ld [$FF01], a ld a, $81 ld [$FF02], a .idle ld c, SYS_YIELD rst $30 jr .idle .child ld b, PROG_WORKER ld c, SYS_EXEC rst $30 ; never returns