feat: build out syscall
This commit is contained in:
1 parent
aad9d4ece8
commit
8f295c1d20
1 file changed
+173
+173
@@ -617,6 +617,179 @@ uint64 syscallDispatch(Registers* regs)
|
||||
int64 rawPid = (int64)regs->rdi;
|
||||
bool ok;
|
||||
if (rawPid > 0)
|
||||
ok = threadKill((uint32)rawPid);
|
||||
else
|
||||
ok = threadKillGroup(rawPid == 0 ? currentThread()->pgid : (uint32)(-rawPid));
|
||||
regs->rax = ok ? 0 : (uint64)-1;
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysSigSend: {
|
||||
/* Same pid>0/pid==0/pid<0 convention as sysKill just above, this
|
||||
time through sigRaiseGroup (signal.h) for the two group cases --
|
||||
see that function's own doc comment for why every per-target
|
||||
special case (SIGKILL/SIGSTOP/SIGCONT bypasses, early-wake,
|
||||
SigInfo) still applies exactly as it already does for a plain,
|
||||
single-target send. */
|
||||
int64 rawPid = (int64)regs->rdi;
|
||||
int signum = (int)regs->rsi;
|
||||
uint32 senderPid = currentThreadId();
|
||||
bool isGroup = (rawPid <= 0);
|
||||
uint32 targetPgid = isGroup ? (rawPid == 0 ? currentThread()->pgid : (uint32)(-rawPid)) : 0;
|
||||
|
||||
/* siCodeUser/senderPid: a real userSigSend always has a genuine
|
||||
sending process, unlike sched.c's own kernel-internal raises
|
||||
(SIGALRM/SIGCHLD) or keyboard.c's terminal-generated ones --
|
||||
exactly real Unix's own SI_USER, si_pid the caller's own pid,
|
||||
exactly like real kill(2). */
|
||||
bool ok = isGroup
|
||||
? sigRaiseGroup(targetPgid, signum, siCodeUser, (int)senderPid)
|
||||
: sigRaiseInfo((uint32)rawPid, signum, siCodeUser, (int)senderPid, 0);
|
||||
regs->rax = ok ? 0 : (uint64)-1;
|
||||
|
||||
/* Every OTHER outcome of sigRaise/sigRaiseGroup either changes
|
||||
nothing about the CALLING thread's own state (a signal aimed at
|
||||
someone else) or, for an ordinary catchable signal aimed at
|
||||
self, is already caught by isrDispatch's unconditional
|
||||
deliverPendingSignals call right after this handler returns
|
||||
(see isr.c) -- self-signaling sigUsr1 and having its handler
|
||||
fire before ever reaching userspace again already works today
|
||||
without any special case here. SIGSTOP against the caller's own
|
||||
pid (or a group that includes it) is the one exception:
|
||||
threadStop (called from sigRaise above, once per group member
|
||||
for the group case) already flipped this very thread's state
|
||||
away from Running, but sigRaise/sysSigSend never touch
|
||||
sigPending for it (see signal.h), so deliverPendingSignals'
|
||||
pending-bit scan would find nothing and simply hand `regs`
|
||||
straight back -- returning to ring 3 and continuing to run a
|
||||
thread the scheduler no longer considers Runnable, until the
|
||||
next timer tick eventually notices. Explicit reschedule here
|
||||
closes that gap, the same "flip state, then let schedule() do
|
||||
the actual waiting" pattern sysSleep/sysExit already use for
|
||||
their own self-directed state changes. The group case checks
|
||||
targetPgid against the caller's OWN pgid rather than an exact id
|
||||
match, since the caller itself -- not just some other member --
|
||||
is who this reschedule is actually about. */
|
||||
bool selfTargeted = isGroup ? (targetPgid == currentThread()->pgid) : ((uint32)rawPid == senderPid);
|
||||
if (ok && signum == sigStop && selfTargeted)
|
||||
return schedule((uint64)regs);
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysSigAction:
|
||||
regs->rax = sigSetHandler(currentThread(), (int)regs->rdi, regs->rsi, regs->rdx, regs->r10);
|
||||
return (uint64)regs;
|
||||
case sysSigProcMask:
|
||||
regs->rax = sigProcMask(currentThread(), (int)regs->rdi, regs->rsi);
|
||||
return (uint64)regs;
|
||||
case sysSigReturn:
|
||||
sigOnSigReturn(currentThread(), regs);
|
||||
return (uint64)regs;
|
||||
case sysAlarm:
|
||||
regs->rax = threadSetAlarm(regs->rdi);
|
||||
return (uint64)regs;
|
||||
case sysSetpgid: {
|
||||
/* Real setpgid(2)'s own "0 means self"/"0 means use pid itself as
|
||||
the new group id" resolution -- threadSetPgid (sched.h) takes an
|
||||
already-fully-resolved value, exactly like threadSetBrk/
|
||||
threadSetAlarm above do for THEIR raw syscall arguments. */
|
||||
uint32 pid = (regs->rdi == 0) ? currentThreadId() : (uint32)regs->rdi;
|
||||
uint32 pgid = (regs->rsi == 0) ? pid : (uint32)regs->rsi;
|
||||
regs->rax = threadSetPgid(pid, pgid) ? 0 : (uint64)-1;
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysGetpgid: {
|
||||
uint32 pid = (regs->rdi == 0) ? currentThreadId() : (uint32)regs->rdi;
|
||||
uint32 pgid = threadPgid(pid);
|
||||
regs->rax = (pgid == threadInvalidId) ? (uint64)-1 : (uint64)pgid;
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysNice: {
|
||||
/* Real setpriority(PRIO_PROCESS, ...)'s own "0 means the caller
|
||||
itself" convention, same resolution shape as sysSetpgid's `pid`
|
||||
argument just above -- rdi/pid, rsi/weight, straight through to
|
||||
threadSetPriority (sched.h), which now does the SAME id==0/
|
||||
out-of-range/Dead-or-Unused rejection threadSetPgid already did
|
||||
(see that function's own updated doc comment for why it had to
|
||||
catch up once this syscall made it reachable from ring 3). */
|
||||
uint32 pid = (regs->rdi == 0) ? currentThreadId() : (uint32)regs->rdi;
|
||||
uint32 weight = (uint32)regs->rsi;
|
||||
regs->rax = threadSetPriority(pid, weight) ? 0 : (uint64)-1;
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysGetPriority: {
|
||||
uint32 pid = (regs->rdi == 0) ? currentThreadId() : (uint32)regs->rdi;
|
||||
uint32 weight = threadPriority(pid);
|
||||
regs->rax = (weight == 0) ? (uint64)-1 : (uint64)weight;
|
||||
return (uint64)regs;
|
||||
}
|
||||
case sysTime:
|
||||
/* Real time(2)'s job: seconds since the Unix epoch, off the real
|
||||
CMOS RTC (rtc.c) -- the first syscall in this kernel answering
|
||||
"what day is it" instead of "how long since boot" (sysSleep,
|
||||
userAlarm). No arguments, nothing to validate. */
|
||||
regs->rax = (uint64)rtcNow();
|
||||
return (uint64)regs;
|
||||
case sysSetFgPgrp:
|
||||
/* Real tcsetpgrp(3)'s job -- names which process group keyboard.c's
|
||||
real Ctrl-C/Ctrl-Z (SIGINT/SIGTSTP) is scoped to next. No
|
||||
permission check at all (this kernel has no notion of "the
|
||||
controlling terminal of MY session" to check ownership against,
|
||||
the same honest, documented omission threadSetPgid's own doc
|
||||
comment already gives for setpgid's session check) -- any
|
||||
process can claim the foreground for any pgid, including one it
|
||||
is not even a member of. */
|
||||
keyboardSetForegroundPgid((uint32)regs->rdi);
|
||||
regs->rax = 0;
|
||||
return (uint64)regs;
|
||||
case sysGetFgPgrp:
|
||||
regs->rax = (uint64)keyboardForegroundPgid();
|
||||
return (uint64)regs;
|
||||
case sysPoll: {
|
||||
/* Real poll(2): rdi/PollFd array, rsi/nfds, rdx/timeoutMs (signed,
|
||||
-1 = wait forever, 0 = report current readiness without ever
|
||||
blocking, like every real poll(2) implementation). Flat address
|
||||
space (this kernel's honest fork()-less design, see doSpawn's own
|
||||
comment) means the array can be read and written in place, the
|
||||
same way sysStat writes straight into its caller's FbStat*
|
||||
without a separate copy-out step. */
|
||||
uint64 nfds = regs->rsi;
|
||||
int64 timeoutMs = (int64)regs->rdx;
|
||||
if (nfds > maxPollFds || !userRangeOk(regs->rdi, nfds * sizeof(PollFd))) {
|
||||
regs->rax = (uint64)-1;
|
||||
return (uint64)regs;
|
||||
}
|
||||
PollFd* userFds = (PollFd*)regs->rdi;
|
||||
Thread* self = currentThread();
|
||||
|
||||
/* First entry into this call (not a retry re-executing after a
|
||||
park below) picks the deadline once and remembers it in
|
||||
pollDeadline -- a later retry must NOT recompute it from the
|
||||
still-unchanged rdx, or a poll that keeps almost-but-not-quite
|
||||
finding a ready fd could have its effective timeout pushed out
|
||||
indefinitely instead of counting down real elapsed time. */
|
||||
if (!self->pollActive && timeoutMs != 0) {
|
||||
self->pollActive = true;
|
||||
if (timeoutMs < 0) {
|
||||
self->pollDeadline = 0;
|
||||
} else {
|
||||
uint64 ticks = ((uint64)timeoutMs * (uint64)pitFrequency()) / 1000;
|
||||
if (ticks == 0)
|
||||
ticks = 1;
|
||||
self->pollDeadline = pitTicks() + ticks;
|
||||
}
|
||||
}
|
||||
|
||||
int64 ready = 0;
|
||||
for (uint64 i = 0; i < nfds; i++) {
|
||||
int16 revents = 0;
|
||||
if (vfsPollReady(userFds[i].fd, userFds[i].events, &revents))
|
||||
ready++;
|
||||
userFds[i].revents = revents;
|
||||
}
|
||||
|
||||
bool expired = self->pollActive && self->pollDeadline != 0 &&
|
||||
pitTicks() >= self->pollDeadline;
|
||||
if (ready > 0 || timeoutMs == 0 || expired) {
|
||||
self->pollActive = false;
|
||||
default:
|
||||
regs->rax = (uint64)-1;
|
||||
return (uint64)regs;
|
||||
|
||||
Reference in new issue
Block a user