feat: build out sched
This commit is contained in:
1 parent
1a8cd39270
commit
785e147d44
1 file changed
+77
@@ -452,6 +452,83 @@ WaitScanResult threadJoinAnyChild(uint32 parentId, uint32* outId, int64* outCode
|
||||
so a parent genuinely blocked in userWaitAny wakes the instant ANY of
|
||||
its children exits, not just one it named specifically. */
|
||||
void threadExit(uint64 code);
|
||||
|
||||
/* Exit code threadKill assigns its victim -- named after SIGKILL (9), the
|
||||
nearest real-world equivalent, though this kernel has no signal delivery
|
||||
at all: threadKill is a hard, unconditional termination, not something a
|
||||
target thread can catch, mask, or clean up after (see threadKill). */
|
||||
#define threadKilledExitCode 9u
|
||||
|
||||
/* Unconditionally terminates thread `id` from OUTSIDE it -- the only way to
|
||||
ever get back a process that is genuinely stuck (e.g. blocked forever in
|
||||
a syscall-level pipe read with no writer ever coming, now that
|
||||
sysRead/sysWrite can really block, see pipe.h/vfs.h). Works on a thread
|
||||
in any of Runnable/Sleeping/Blocked: its state is simply set straight to
|
||||
threadDead with exitCode threadKilledExitCode, exactly as if it had
|
||||
called threadExit(threadKilledExitCode) itself, and whoever is (or later
|
||||
becomes) threadJoin()ing it wakes up and reaps it normally -- there is no
|
||||
"half-dead" state and no cleanup callback, since a mid-syscall thread has
|
||||
no user-mode cleanup path to run anyway. Returns false, changing nothing,
|
||||
for id 0 (idle), an out-of-range id, an already-Dead/never-created slot,
|
||||
or (implicitly, since only the CPU's one currently-executing thread is
|
||||
ever threadRunning) the caller's own id -- a syscall handler always runs
|
||||
as its OWN thread, which is Running, not Runnable/Sleeping/Blocked, at
|
||||
the moment it would try to kill itself, so self-kill is naturally
|
||||
rejected without a special-case check. Real termination (sysExit) is
|
||||
still how a thread should ever end itself. Also raises sigChld against
|
||||
the victim's parentId, exactly like threadExit does -- a killed child
|
||||
is still a dead child as far as its parent's SIGCHLD is concerned, the
|
||||
same way real kill(2)ing a child still generates SIGCHLD to its real
|
||||
parent. Also wakes the victim's parent's OWN slot as a wait channel,
|
||||
exactly like threadExit does -- a parent parked in userWaitAny does not
|
||||
care whether a child exited on its own or was killed, same as real
|
||||
waitpid(-1) does not distinguish the two either. */
|
||||
bool threadKill(uint32 id);
|
||||
|
||||
/* Job control (signal.h): unconditionally moves thread `id` -- Runnable,
|
||||
Running (including the caller itself, unlike threadKill which naturally
|
||||
excludes self-targeting), Sleeping, or Blocked -- into threadStopped.
|
||||
Idempotent if `id` is already Stopped (matches real kill(pid, SIGSTOP)
|
||||
succeeding again on an already-stopped process). Safe on a
|
||||
Sleeping/Blocked thread for the same reason threadKill already is: every
|
||||
such thread is parked mid-retry-loop right after its own halt() (see
|
||||
pipeReadBlocking/pipeWriteBlocking, or the restart-syscall pattern
|
||||
syscall.c's sysRead/sysWrite/sysWait use), so simply not being picked by
|
||||
schedule() again until threadContinue moves it back is enough -- no
|
||||
wait-channel state is lost, since that retry loop re-checks its own
|
||||
condition from scratch every time it runs at all. Returns false,
|
||||
changing nothing, for id 0 (idle -- stopping it would wedge the whole
|
||||
machine the instant nothing else was runnable), an out-of-range id, or
|
||||
an already-Dead/never-created slot. */
|
||||
bool threadStop(uint32 id);
|
||||
|
||||
/* Job control (signal.h): moves thread `id` from threadStopped back to
|
||||
threadRunnable. Returns false, changing nothing, if `id` is out of
|
||||
range or not currently Stopped (matches real SIGCONT delivered to a
|
||||
process that was never stopped -- a harmless no-op at the process-state
|
||||
level; signal.c's sigRaise still delivers the signal itself/runs a
|
||||
handler regardless of this return value). */
|
||||
bool threadContinue(uint32 id);
|
||||
|
||||
/* Real Unix's interruptible sleep/EINTR: forces thread `id` from
|
||||
threadSleeping or threadBlocked straight to threadRunnable, early --
|
||||
before its sleep timer expires or its wait-channel condition is ever
|
||||
satisfied -- so the NEXT schedule() eventually resumes it, letting
|
||||
isr.c's deliverPendingSignals (which only ever runs at a return-to-ring3
|
||||
point) actually reach a thread that would otherwise never naturally
|
||||
produce one. Called only by signal.c's sigRaise, and only for a signal it
|
||||
has already determined would genuinely be delivered (not blocked, not
|
||||
ignored) if this thread resumed right now -- callers must not use this to
|
||||
wake a thread for an unrelated reason. Deliberately excludes
|
||||
threadStopped (only threadContinue, an explicit SIGCONT, may ever move a
|
||||
Stopped thread -- the same asymmetry schedWakeChannel already has, for
|
||||
the same reason: job control's "stopped means stopped" must survive an
|
||||
ordinary signal arriving too). Returns false, changing nothing, for an
|
||||
out-of-range id or any state other than Sleeping/Blocked (Runnable/
|
||||
Running need no forcing; Stopped/Dead/Unused have nothing to wake, or
|
||||
must not be woken this way at all). */
|
||||
bool threadWakeForSignal(uint32 id);
|
||||
|
||||
void threadSleep(uint64 milliseconds);
|
||||
void threadSetBrk(uint32 id, uint64 brk);
|
||||
uint64 currentThreadSbrk(int64 increment);
|
||||
|
||||
Reference in new issue
Block a user