1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
; =============================================================================
; 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
|