Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2.7 KiB
| name | description | metadata | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| schunix-sockets-and-evdev | Unix domain sockets and /dev/input evdev both work; the one lock rule, the names-not-in-the-VFS tradeoff, and where the syscall numbers went |
|
Unix domain sockets (kernel/net/unix.c, include/net/socket.h, kernel/sys/sys_net.c)
and raw input events (kernel/dev/input.c, include/dev/input.h) are both done and
verified — tools\bootcheck.ps1 -Sock and -Evdev.
One lock for the whole socket table, deliberately. A pipe gets a lock per
pipe because every operation touches one object; a socket operation touches
two, and per-socket locks need an ordering rule every path obeys or they
deadlock. Worse, a reader testing peer_closed under its own lock while the
closer sets it under the peer's has no interlock and sleeps through its own
wakeup. Don't "optimise" this into per-socket locks.
Socket names live in a table, not the filesystem. ls -l /tmp/schcom will
not show an s and unlink() of a socket path returns ENOENT. Fixing it
properly means a new inode type through both filesystems, iget, dirlookup and
stat — a VFS change, not a socket change. Everything that matters works.
connect() deliberately does not wait for accept(). A queued connection
is already established on Unix; blocking would deadlock any server that
connects to itself.
The syscalls had real Linux numbers assigned (41/49/50/43/42 and friends).
They were NO_LINUX stubs before, which meant a musl program calling
socket() got "bad syscall" from the ABI translation and never reached the
stub at all — same trap as schunix-shm-and-mmap. shutdown is registered
as sockshutdown because Schunix already has a native shutdown that powers
the machine off.
evdev: /dev/input/event0 (keyboard) and event1 (mouse), major 7, Linux
struct input_event layout. Fed by the PS/2 keyboard, the PS/2 mouse and USB
HID. The console keeps its own path — both consumers see every key, so keys
pressed during a test also land on the shell's input line.
Two things that are not obvious:
- Below 0x54 a Linux keycode is the AT set-1 scancode, so the PS/2 path
needs no table. USB HID does need one (
hid_keycode[]), because HID numbers keys by position and the AT set numbers them by matrix wiring order. - A full event ring drops the oldest event. Dropping the newest is the obvious choice and it is wrong: the event most likely lost is a key release, and a lost release leaves the key held down forever.
See also schunix-console-tty, schunix-framebuffer-device, schunix-verify-by-driving-shell.