feat: flesh out sched
This commit is contained in:
1 parent
f31dd38429
commit
c571c0af1f
1 file changed
+179
-1
+179
-1
@@ -9,8 +9,186 @@
|
||||
#include "console.h"
|
||||
#include "paging.h"
|
||||
#include "vfs.h"
|
||||
#include "prioq.h"
|
||||
#include "elf.h"
|
||||
#include "keyboard.h"
|
||||
#include "pipe.h"
|
||||
#include "pidfd.h"
|
||||
#include "signal.h"
|
||||
|
||||
#define maxThreads 16
|
||||
/* Bumped from 24: boot now spawns 22 kernel/user threads before the
|
||||
scheduler even starts (kmain.c) -- several of which (workerA/workerB,
|
||||
schedVerify, pipeProducer/pipeConsumer) park in an infinite halt() loop
|
||||
rather than ever calling threadExit, so their slots are never freed for
|
||||
reuse -- plus a handful more spawned at runtime by those boot programs
|
||||
themselves (fifomaster's fiforeader/fifowriter, killtest's killvictim,
|
||||
proctest's spawntarget/argtest) that can be alive at the same time as
|
||||
their still-running parent. 24 was exactly enough before namedreader/
|
||||
namedwriter's fifo-rendezvous demo added two more boot-time processes;
|
||||
with them, every one of those later spawns (fifomaster's, killtest's,
|
||||
proctest's own) started failing with the table genuinely full. The
|
||||
free-slot reuse machinery below (allocSlot/threadReap) also needs
|
||||
headroom above whatever boot needs to demonstrate exhaustion+reuse in
|
||||
tests without permanently eating into threads real boot needs.
|
||||
consolereader1/2+their injector and sigtest+its two short-lived,
|
||||
promptly-reaped children (signal.h's demo) landed since without needing
|
||||
another bump -- 32 held across dozens of stress runs, but with exactly
|
||||
zero slots of headroom left over: boot-time spawns alone (kmain.c) had
|
||||
already reached the full 32 the moment sigtest's own spawnUser call
|
||||
returned, before any of killtest's/fifomaster's/proctest's own
|
||||
runtime-spawned children (killvictim, fifowriter, spawntarget, argtest)
|
||||
ever got a chance to exist. That razor-thin margin turned into a real,
|
||||
observed race the moment jobtest+jobtarget (job control's live demo,
|
||||
signal.h) landed as two more boot/runtime processes: every one of those
|
||||
OTHER programs' children now had to wait for exactly one freed slot
|
||||
(killvictim's, once threadReap'd) to fight over, and fifomaster's
|
||||
fifowriter won that fight at the exact moment killtest was mid-way
|
||||
through its own "kill an already-reaped pid must fail" check --
|
||||
recycling killvictim's just-freed pid number into fifowriter's very much
|
||||
alive one, so killtest's second userKill(victim) call genuinely
|
||||
succeeded (against fifowriter, not "nothing") when it expected -1.
|
||||
Not a scheduling-timing flake (see ci-test.sh's documented host-load
|
||||
flakiness elsewhere): a deterministic consequence of table pressure,
|
||||
reproduced identically across repeated runs until this bump. Restored
|
||||
real headroom (bump to 40, not just the 2 jobtest/jobtarget need) so a
|
||||
future addition does not immediately re-create the same zero-margin
|
||||
situation. nesttest/nesttarget and eintrtest/eintrtarget (4 more
|
||||
boot/runtime processes, signal.h's nested-delivery and early-wake demos)
|
||||
fit under 40 with zero bump needed -- confirmed as the exact high-water
|
||||
mark (`[sched] 40 threads total`), i.e. zero slots of headroom left
|
||||
over again. restarttest/restarttarget (2 more, signal.h's SA_RESTART/
|
||||
EINTR demo) would immediately hit the same razor-thin-margin class of
|
||||
bug FALA 16's maxThreads bump above already fixed once, so bumped ahead
|
||||
of that this time (40 -> 48) instead of waiting to observe it.
|
||||
Confirmed as the exact high-water mark yet again once restarttest/
|
||||
restarttarget actually landed (`[sched] 48 threads total`, checked live
|
||||
before touching anything this fala) -- zero slots of headroom left over,
|
||||
same story as 40 was before it. masktest/masktarget (2 more, signal.h's
|
||||
sa_mask-defers-then-delivers live demo) would immediately re-create the
|
||||
exact same class of bug, so bumped ahead of that again (48 -> 56)
|
||||
instead of waiting to observe it, same reasoning as every bump above.
|
||||
Confirmed as the exact high-water mark yet again once masktest/
|
||||
masktarget landed (`[sched] 56 threads total`, checked live before
|
||||
touching anything this fala) -- zero slots of headroom left over.
|
||||
sigchldtest/sigchldchild (2 more, sched.c's new parentId/SIGCHLD-on-exit
|
||||
live demo) would immediately re-create the exact same class of bug, so
|
||||
bumped ahead of that again (56 -> 64) instead of waiting to observe it,
|
||||
same reasoning as every bump above. Confirmed as the exact high-water
|
||||
mark yet again once sigchldtest/sigchldchild landed (`[sched] 64 threads
|
||||
total`, checked live before touching anything this fala) -- zero slots
|
||||
of headroom left over. waitanytest/waitanyfast/waitanyslow (3 more,
|
||||
sched.c's new threadJoinAnyChild/userWaitAny live demo) would
|
||||
immediately re-create the exact same class of bug, so bumped ahead of
|
||||
that again (64 -> 72) instead of waiting to observe it, same reasoning
|
||||
as every bump above. Confirmed as the exact high-water mark yet again
|
||||
once waitanytest/waitanyfast/waitanyslow landed (`[sched] 72 threads
|
||||
total`, checked live before touching anything this fala) -- zero slots
|
||||
of headroom left over. stopchldtest/stopchldtarget (2 more, sched.c's
|
||||
new threadStop/threadContinue SIGCHLD-on-stop/SIGCHLD-on-continue live
|
||||
demo) would immediately re-create the exact same class of bug, so
|
||||
bumped ahead of that again (72 -> 80) instead of waiting to observe it,
|
||||
same reasoning as every bump above. Confirmed as the exact high-water
|
||||
mark yet again once stopchldtest/stopchldtarget landed (`[sched] 80
|
||||
threads total`, checked live before touching anything this fala) --
|
||||
zero slots of headroom left over. nodefertest (1 more, signal.h's new
|
||||
sigFlagNoDefer live demo -- unlike every pair above, self-contained, no
|
||||
spawned counterpart) would immediately re-create the exact same class
|
||||
of bug, so bumped ahead of that again (80 -> 88) instead of waiting to
|
||||
observe it, same reasoning as every bump above. alarmtest/alarmdefault
|
||||
(2 more, sched.c's new threadSetAlarm/schedule()-expiry-scan real
|
||||
SIGALRM live demo) would immediately re-create the exact same class of
|
||||
bug, so bumped ahead of that again (88 -> 96) instead of waiting to
|
||||
observe it, same reasoning as every bump above. siginfotest/
|
||||
siginfotarget (2 more, signal.h's new sigFlagSigInfo/SigInfo live demo)
|
||||
would immediately re-create the exact same class of bug, so bumped ahead
|
||||
of that again (96 -> 104) instead of waiting to observe it, same
|
||||
reasoning as every bump above. Confirmed as the exact high-water mark
|
||||
yet again once siginfotest/siginfotarget landed (`[sched] 104 threads
|
||||
total`, checked live before touching anything this fala) -- zero slots
|
||||
of headroom left over. pgroupfg/pgroupbg (2 more, sched.c's new pgid/
|
||||
process-group live demo, plus a third kernel-only injector thread,
|
||||
kmain.c's pgroupInjectorThread) would immediately re-create the exact
|
||||
same class of bug, so bumped ahead of that again (104 -> 112) instead of
|
||||
waiting to observe it, same reasoning as every bump above. Confirmed as
|
||||
the exact high-water mark yet again once pgroupfg/pgroupbg landed
|
||||
(`[sched] 112 threads total`, checked live before touching anything this
|
||||
fala) -- zero slots of headroom left over. jobctlfg/jobctlbg (2 more,
|
||||
jobctl.c's new generic by-path spawn+real-job-control helper, loaded on
|
||||
demand by the shell's own `NAME [ARGS] [&]` fallback rather than eagerly
|
||||
at boot like everything above -- the first two user programs in this
|
||||
kernel never once named in a kmain.c spawnUser call), plus a third
|
||||
kernel-only driver thread (kmain.c's jobctlDriverThread, which types
|
||||
commands at the real shell through the same injected-keystroke mechanism
|
||||
pgroupInjectorThread already uses) would immediately re-create the exact
|
||||
same class of bug, so bumped ahead of that again (112 -> 120) instead of
|
||||
waiting to observe it, same reasoning as every bump above. polltest (1
|
||||
more, boot-time driver for the new sysPoll multiplexed-fd wait) plus
|
||||
pollwriter (1 more, runtime-spawned by polltest itself, mirroring
|
||||
alarmtest/alarmdefault's shape) would immediately re-create the exact
|
||||
same class of bug, so bumped ahead of that again (120 -> 128) instead of
|
||||
waiting to observe it, same reasoning as every bump above. pipesrc/
|
||||
pipesink (2 more, jobctl.c's new real shell pipeline demo, loaded on
|
||||
demand exactly like jobctlfg/jobctlbg rather than boot-time spawnUser),
|
||||
plus a third kernel-only driver thread (kmain.c's pipelineDriverThread,
|
||||
which types the pipeline command at the real shell through the same
|
||||
injected-keystroke mechanism jobctlDriverThread already uses) would
|
||||
immediately re-create the exact same class of bug, so bumped ahead of
|
||||
that again (128 -> 136) instead of waiting to observe it, same reasoning
|
||||
as every bump above. redirwriter (1 more, jobctl.c's new file
|
||||
redirection demo, run TWICE by kmain.c's redirDriverThread against the
|
||||
same on-demand-loaded binary -- but each run is its own spawn+exit, so
|
||||
only ONE of its process-table slots is ever live at a time) plus
|
||||
redirreader (1 more, same on-demand-loading pattern as pipesrc/pipesink
|
||||
above), plus a third kernel-only driver thread (kmain.c's
|
||||
redirDriverThread, which types the redirected commands at the real
|
||||
shell through the same injected-keystroke mechanism jobctlDriverThread/
|
||||
pipelineDriverThread already use) would immediately re-create the exact
|
||||
same class of bug, so bumped ahead of that again (136 -> 144) instead of
|
||||
waiting to observe it, same reasoning as every bump above. stderrwriter
|
||||
(1 more, jobctl.c's new stderr (fd 2) redirection demo, run TWICE by
|
||||
kmain.c's stderrDriverThread against the same on-demand-loaded binary --
|
||||
the exact same "only ONE of its process-table slots is ever live at a
|
||||
time" shape redirwriter already has for `>`/`>>`) plus stderrreader (1
|
||||
more, same on-demand-loading pattern as redirreader above), plus a third
|
||||
kernel-only driver thread (kmain.c's stderrDriverThread, which types the
|
||||
`2>`/`2>>`-redirected commands at the real shell through the same
|
||||
injected-keystroke mechanism redirDriverThread already uses) would
|
||||
immediately re-create the exact same class of bug, so bumped ahead of
|
||||
that again (144 -> 152) instead of waiting to observe it, same reasoning
|
||||
as every bump above. selfstoptest (boot-time spawned, self-directed
|
||||
SIGSTOP live demo) plus selfstoptarget (1 more, runtime-spawned by
|
||||
selfstoptest, the same *test / *target relationship jobtest/jobtarget
|
||||
already have) are two more concurrently live threads, so bumped again
|
||||
(152 -> 160) for the same headroom reason as every bump above. herestest
|
||||
(1 more, jobctl.c's new here-string `<<<` stdin demo, on-demand-loaded
|
||||
exactly like redirreader/stderrreader above -- no writer counterpart
|
||||
binary at all, since the "writer" is the shell's own kernel thread, not
|
||||
another spawned process) plus a third kernel-only driver thread (kmain.c's
|
||||
hereDriverThread, which types the here-string command at the real shell
|
||||
through the same injected-keystroke mechanism redirDriverThread/
|
||||
stderrDriverThread already use) would immediately re-create the exact
|
||||
same class of bug, so bumped ahead of that again (160 -> 168) instead of
|
||||
waiting to observe it, same reasoning as every bump above. hcat (1 more,
|
||||
jobctl.c's new jobctlSpawnPipedHereString demo -- a here-string stdin AND
|
||||
a piped stdout on the same process at once, on-demand-loaded exactly like
|
||||
herestest above) plus hsink (1 more, same on-demand-loading pattern as
|
||||
pipesink above), plus a third kernel-only driver thread (kmain.c's
|
||||
hereStringPipelineDriverThread, which types the here-string-into-pipeline
|
||||
command at the real shell through the same injected-keystroke mechanism
|
||||
pipelineDriverThread/hereDriverThread already use) would immediately
|
||||
re-create the exact same class of bug, so bumped ahead of that again
|
||||
(168 -> 176) instead of waiting to observe it, same reasoning as every
|
||||
bump above. pipecat (1 more, shell.c's new runPipelineStages demo -- the
|
||||
first process in this kernel with two DIFFERENT real inter-process pipes
|
||||
on its own stdio at once, a genuine middle pipeline stage rather than a
|
||||
here-string-plus-pipe like hcat above), plus a third kernel-only driver
|
||||
thread (kmain.c's threeStagePipelineDriverThread, which types the
|
||||
three-stage pipeline command at the real shell through the same
|
||||
injected-keystroke mechanism pipelineDriverThread/hereStringPipelineDriverThread
|
||||
already use) would immediately re-create the exact same class of bug, so
|
||||
bumped ahead of that again (176 -> 184) instead of waiting to observe it,
|
||||
same reasoning as every bump above. cwdtest (boot-time spawned, real
|
||||
per-process working directory live demo -- sched.h's new Thread.cwd)
|
||||
#define threadStackSize 16384
|
||||
|
||||
static Thread threads[maxThreads];
|
||||
|
||||
Reference in new issue
Block a user