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.
48 lines
2.5 KiB
Markdown
48 lines
2.5 KiB
Markdown
---
|
|
name: schunix-shm-and-mmap
|
|
description: Shared memory and file-backed mmap work now; the rule is that pages a process does not own must never reach kfree
|
|
metadata:
|
|
node_type: memory
|
|
type: project
|
|
originSessionId: a665e14b-86bd-4b41-a228-51377f3e9225
|
|
modified: 2026-08-04T18:45:47.215Z
|
|
---
|
|
|
|
**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 were `NO_LINUX`**, so a musl-linked program
|
|
never reached them at all; they now carry Linux's numbers (29/30/67).
|
|
- `mmap` of a regular file reads the contents in. It used to silently return
|
|
zeroed anonymous pages -- success-shaped, and wrong. **Writable `MAP_SHARED`
|
|
on a file returns `-ENODEV`** rather 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. Use
|
|
`vm_unmap_norelease()` for device memory and shared segments.
|
|
- `freevm()` frees any mapped page below `PHYSTOP`. 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 both `exit()`
|
|
and `exec()` -- and in exec it must run **before** the `memset(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]].
|