|
1 | 1 | # Linux backend |
2 | 2 |
|
3 | | -The Linux backend stores data in an anonymous `memfd` and uses a Linux |
4 | | -abstract Unix-domain socket as a descriptor broker. The broker is a control |
5 | | -plane used only when opening a view. Once mapped, all frame reads and writes |
6 | | -access memory directly. |
| 3 | +The Linux backend stores data in a sealed `memfd`. An abstract Unix-domain |
| 4 | +socket broker distributes the descriptor when a process opens the mapping; |
| 5 | +the data path remains memory-mapped. |
7 | 6 |
|
8 | | -## Requirements |
9 | | - |
10 | | -The fspy channel reserves a large logical region so intercepted processes can |
11 | | -append without coordinating a resize. The Linux backend must: |
12 | | - |
13 | | -- avoid the container's `/dev/shm` mount limit, |
14 | | -- avoid allocating the mapping's full logical size up front, |
15 | | -- let another process open the mapping from a serialized identifier, |
16 | | -- support clients that run in preload code before `main`, |
17 | | -- keep data writes free of per-record syscalls, and |
18 | | -- preserve already-open views when the owner stops accepting new views. |
19 | | - |
20 | | -The |
21 | | -[`constrained_dev_shm`](../../../vite_task_bin/tests/e2e_snapshots/fixtures/constrained_dev_shm/) |
22 | | -fixture captures the key constraint. It mounts a one-page `/dev/shm` and |
23 | | -forces file-access tracking to write beyond that mount's capacity. |
| 7 | +The design must avoid `/dev/shm` quotas, allocate a large logical mapping on |
| 8 | +demand, support synchronous opens from preload code, and stop new opens when |
| 9 | +the owner is dropped without invalidating existing views. |
24 | 10 |
|
25 | 11 | ## Options considered |
26 | 12 |
|
27 | | -| Option | Decision | |
28 | | -| --- | --- | |
29 | | -| POSIX `shm_open` | Rejected. Linux normally places the object on `/dev/shm`, so container tmpfs limits can fault mapped writes even when the host has enough memory. | |
30 | | -| Memory-map a temporary file | Rejected. It introduces path discovery, cleanup, and possible disk writeback without providing a better identifier. | |
31 | | -| Inherit a `memfd` | Rejected. Every process would need to propagate the descriptor to later children and across `exec`, increasing descriptor-leak risk. | |
32 | | -| Send every record through a socket or pipe | Rejected. Every file-access record would require a syscall under concurrent writes. | |
33 | | -| `memfd` with descriptor broker | Selected. It avoids `/dev/shm`, preserves string-based discovery, and pays socket overhead only when a process opens a view. | |
| 13 | +| Option | Decision | |
| 14 | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- | |
| 15 | +| POSIX shared memory | Rejected because Linux backs it with `/dev/shm`. | |
| 16 | +| System V shared memory | Rejected because IPC namespace quotas affect availability and segment lifetime is not tied to descriptor ownership. | |
| 17 | +| Sparse temporary file | Rejected because dirty pages may reach disk and the file needs a separate lifetime protocol. | |
| 18 | +| `memfd` with descriptor broker | Selected. It avoids mount and IPC quotas while retaining descriptor-based lifetime. | |
34 | 19 |
|
35 | | -The broker is asynchronous so one descriptor transfer cannot stop it from |
36 | | -accepting another client. Opening remains synchronous because preload code may |
37 | | -run before an application provides an async runtime. Creating the owner |
38 | | -requires an ambient Tokio runtime to host the broker. |
| 20 | +The broker accepts and serves clients asynchronously. The client is |
| 21 | +synchronous because it can run before `main`; creating an owner therefore |
| 22 | +requires an ambient Tokio runtime only on the broker side. |
39 | 23 |
|
40 | 24 | ## Why not `shared_memory` |
41 | 25 |
|
42 | | -The `shared_memory` Unix backend creates mappings with POSIX `shm_open`. Its |
43 | | -API cannot accept an existing `memfd` or distribute that descriptor, so |
44 | | -wrapping it would retain the `/dev/shm` dependency. |
45 | | - |
46 | | -Extending or forking the general-purpose crate would add more surface than |
47 | | -fspy needs. The local backend only implements the descriptor, mapping, broker, |
48 | | -and lifetime behavior required by the channel contract. |
| 26 | +`shared_memory` uses POSIX `shm_open` on Linux and cannot construct a mapping |
| 27 | +from a `memfd`, so it retains the `/dev/shm` dependency. |
49 | 28 |
|
50 | 29 | ## Lifetime semantics |
51 | 30 |
|
52 | | -Dropping the owner stops the broker, so later opens fail. Descriptors already |
53 | | -delivered to other processes remain valid, and their mapped views stay usable |
54 | | -independently of the owner. Neither the `memfd` nor the abstract socket needs a |
55 | | -filesystem pathname or cleanup file. |
| 31 | +Dropping the owner stops the broker. Existing views remain valid; later opens |
| 32 | +fail. |
0 commit comments