Claude Code keeps per-project memory at <home>/.claude/projects/<key>/,
where <key> is the project's absolute path with every separator and the
drive colon turned into a dash. That makes it both rename-fragile and
machine-specific, and this project has hit each of those once:
- D:\DEV\Schunix -> D:\DEV\SchOS changed the key, and 43 memories were
invisible until moved across by hand.
- Development happens from Windows and from Linux, and each looks in a
different place for the same checkout.
Committing .claude/memory/ fixes both -- git carries it across renames
and between hosts -- and `import` puts it wherever the local machine
expects. .claude/settings.local.json stays ignored: those are per-machine
permissions.
The colon maps to a dash rather than being dropped. Deleting it gives
D-DEV-SchOS, which matches nothing and silently finds zero memories; that
was the first attempt. On Git Bash the key comes from `cygpath -w`,
because Claude Code is a Windows program and sees D:\DEV\SchOS, not
/d/DEV/SchOS.
2.5 KiB
| name | description | metadata | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| schunix-shm-and-mmap | Shared memory and file-backed mmap work now; the rule is that pages a process does not own must never reach kfree |
|
Shared memory and file-backed mmap were implemented on 2026-08-04, in
kernel/sys/sys_mem.c. These were the two syscall gaps blocking a display
server: without shm, every frame is a copy through a pipe.
shmget/shmat/shmdt— up to 16 segments of 2 MB. Pages are allocated up front and zeroed (a fresh segment handing out the last tenant's bytes would leak them between processes). A segment lives until its last attachment goes. Their table.inc entries wereNO_LINUX, so a musl-linked program never reached them at all; they now carry Linux's numbers (29/30/67).mmapof a regular file reads the contents in. It used to silently return zeroed anonymous pages -- success-shaped, and wrong. WritableMAP_SHAREDon a file returns-ENODEVrather than faking it: its whole contract is that stores reach the file, and there is no page cache that could make that true.
The rule that matters: pages a process does not own must never reach kfree(). Three places had to learn it, and each was a real hazard:
vm_unmap_range()kfree's everything it unmaps. Usevm_unmap_norelease()for device memory and shared segments.freevm()frees any mapped page belowPHYSTOP. The framebuffer survived only by accident (0xfd000000 is above PHYSTOP); shm pages are kalloc'd and sit below it.proc_release_shared()runs before freevm in bothexit()andexec()-- and in exec it must run before thememset(proc->vma), which erases the record of which mappings were shared.fork()must map the same physical pages and bump the attachment count.copy_vma_range()'s share branch now copies the parent's PTEs rather than special-casing the framebuffer address.
struct vma's is_fb became no_free + shmid for this reason.
Test with shmtest (cmd/shmtest, nine checks) — it forks and has the
child write where the parent reads, which is the only convincing proof. Run
via pwsh -File tools/bootcheck.ps1 -Tty.
Still missing for a GUI: raw keyboard/mouse events that bypass the tty line
discipline, and unix domain sockets (socket() is still a NO_LINUX stub).
See schunix-console-tty and schunix-framebuffer-device.