SchOS/.claude/memory/schunix-sockets-and-evdev.md
Nexoniarz a1c965da1e include: one folder per subsystem, and includes that name it
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
2026-10-23 15:05:12 +02:00

52 lines
2.7 KiB
Markdown

---
name: schunix-sockets-and-evdev
description: "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"
metadata:
node_type: memory
type: project
originSessionId: 9d8a2aef-bcf0-47a0-96c6-f706efab4a95
modified: 2026-08-05T07:12:20.950Z
---
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]].