Pseudo-terminals, and what tmux and htop needed around them

- /dev/ptmx and /dev/pts/N: Unix98 pairs with a full line discipline,
  window sizes, job control and hangup (kernel/dev/pty.c).
- The console speaks scroll regions, insert/delete line, SU/SD, RI/IND/NEL,
  DECSC/DECRC; swallows charset designations and private CSI sequences;
  and LF only returns the carriage under ONLCR.
- setsid() drops the controlling terminal, so a pane's pty becomes its ctty.
- pipe2() honours O_NONBLOCK and O_CLOEXEC (libevent's signal pipe).
- File modes are stored and enforced: chmod, fchmod(at), umask, creation
  modes; /tmp is 1777.
- /proc/stat has real user/system/idle; /proc/<pid>/task; kthread flag.
- SO_PEERCRED, IOV_MAX 1024.
- /proc/strace: name a program and its syscalls go to the kernel log.
- World gains htop, btop, tmux, mc, ncdu, fastfetch, games, X toys, NetSurf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-25 02:11:10 +01:00
commit fd9d392416
28 changed files with 1577 additions and 47 deletions

View file

@ -25,6 +25,10 @@ struct {
struct proc proc[NPROC];
} ptable;
// CPU time of every process already reaped, so that /proc/stat's busy time
// does not drop each time one is. Under ptable.lock, like the processes.
static uint64 reaped_utime, reaped_stime;
// Kernel stacks, one per ptable slot, statically.
//
// **They used to be a single kalloc() page**, and a measurement said that was
@ -313,6 +317,8 @@ found:
p->pending_signals = 0;
p->alarm_at = p->alarm_every = 0; // a child's timers start disarmed
p->utime = p->stime = p->cutime = p->cstime = 0;
p->strace = 0;
p->umask = 022;
// A recycled slot must not inherit a dead process's place in the queue --
// in either direction. sched_init_proc starts it at min_vruntime, which is
@ -509,6 +515,8 @@ fork(void)
np->fs_base = myproc()->fs_base;
safestrcpy(np->name, myproc()->name, sizeof(myproc()->name));
np->strace = myproc()->strace;
np->umask = myproc()->umask;
// The child inherits the parent's place in the queue, priority and all.
//
@ -746,6 +754,8 @@ waitpid(int pid, int *status, int options, uint64 *ut, uint64 *st)
// of processes rather than one generation deep.
myproc()->cutime += p->utime + p->cutime;
myproc()->cstime += p->stime + p->cstime;
reaped_utime += p->utime;
reaped_stime += p->stime;
// wait4()'s fourth argument wants the *child's* usage, not the
// parent's running total, so it has to be read here -- three lines
// further down the slot is UNUSED and these are zero.
@ -1786,6 +1796,11 @@ proc_setsid(void)
}
myproc()->sid = myproc()->pid;
myproc()->pgid = myproc()->pid;
// A new session starts with no controlling terminal; that is what lets the
// first terminal it opens become one. Keeping the old one meant a tmux pane
// still had tty1 as its /dev/tty, and zsh and htop drew straight onto the
// console underneath tmux instead of into their pane.
myproc()->ctty = 0;
r = myproc()->sid;
release(&ptable.lock);
return r;
@ -1913,6 +1928,7 @@ proc_snapshot(int idx, struct procinfo *out)
out->nivcsw = p->nivcsw;
safestrcpy(out->name, p->name, sizeof(out->name));
safestrcpy(out->exe, p->exe, sizeof(out->exe));
out->kthread = p->kfn != 0;
release(&ptable.lock);
return 0;
}
@ -2012,3 +2028,24 @@ proc_kill_init(void)
if (initproc)
initproc->killed = 1;
}
// Ticks spent in user and kernel mode by every process, living or reaped.
// What /proc/stat's busy columns are made of; the rest of the time was idle.
void
proc_cputime(uint64 *user, uint64 *sys)
{
struct proc *p;
uint64 u, s;
acquire(&ptable.lock);
u = reaped_utime;
s = reaped_stime;
for (p = ptable.proc; p < &ptable.proc[NPROC]; p++)
if (p->state != UNUSED) {
u += p->utime;
s += p->stime;
}
release(&ptable.lock);
*user = u;
*sys = s;
}