docs(daemon): correct snapshot worker lock, transient page and geometry comments
- commit
- 1c519666fec1f9c5d562e9216abfa12ff7791ba6
- author
- brice · · 2026-10-08 09:01 UTC
- committer
- brice · · 2026-10-08 09:31 UTC
- parent
- 525159d
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +9 -5
M internal/usecase/daemon/client.go +1 -0
| @@ -238,6 +238,7 @@ func (ac *attachedClient) geometrySnapshot() domain.Geometry { | |||
| 238 | 238 | if ac.geometry.Valid() { | |
| 239 | 239 | return ac.geometry | |
| 240 | 240 | } | |
| 241 | + | // Pixels only describe a valid cell size; never hand them out without one. | |
| 241 | 242 | return domain.Geometry{Size: ac.geometry.Size} | |
| 242 | 243 | } | |
| 243 | 244 | ||
| @@ -238,6 +238,7 @@ func (ac *attachedClient) geometrySnapshot() domain.Geometry { | |||||
| 238 | if ac.geometry.Valid() { | 238 | if ac.geometry.Valid() { | ||
| 239 | return ac.geometry | 239 | return ac.geometry | ||
| 240 | } | 240 | } | ||
| 241 | + | // Pixels only describe a valid cell size; never hand them out without one. | |||
| 241 | return domain.Geometry{Size: ac.geometry.Size} | 242 | return domain.Geometry{Size: ac.geometry.Size} | ||
| 242 | } | 243 | } | ||
| 243 | 244 | ||||
M internal/usecase/daemon/render_pipeline.go +2 -1
| @@ -59,7 +59,8 @@ type composeCacheInput struct { | |||
| 59 | 59 | // the same commit/spare rotation as the cached frame, so a page is only ever | |
| 60 | 60 | // written by a composition whose input scratch owns it. Neither slot may hold | |
| 61 | 61 | // a page shared with a cached frame (frame, copyViewport.frame) or with another | |
| 62 | - | // slot; they are filled only by copyFrameInto, which allocates a fresh page. | |
| 62 | + | // slot; they are filled only by copyFrameInto, whose first fill clones, so a | |
| 63 | + | // slot never shares a page with a cached frame. | |
| 63 | 64 | type transientFrames struct { | |
| 64 | 65 | // overlay receives the toast-decorated or modal-decorated copy of the base | |
| 65 | 66 | // frame. Toasts and modals never both clone, so they share the slot. | |
| @@ -59,7 +59,8 @@ type composeCacheInput struct { | |||||
| 59 | // the same commit/spare rotation as the cached frame, so a page is only ever | 59 | // the same commit/spare rotation as the cached frame, so a page is only ever | ||
| 60 | // written by a composition whose input scratch owns it. Neither slot may hold | 60 | // written by a composition whose input scratch owns it. Neither slot may hold | ||
| 61 | // a page shared with a cached frame (frame, copyViewport.frame) or with another | 61 | // a page shared with a cached frame (frame, copyViewport.frame) or with another | ||
| 62 | - | // slot; they are filled only by copyFrameInto, which allocates a fresh page. | 62 | + | // slot; they are filled only by copyFrameInto, whose first fill clones, so a |
| 63 | + | // slot never shares a page with a cached frame. | |||
| 63 | type transientFrames struct { | 64 | type transientFrames struct { | ||
| 64 | // overlay receives the toast-decorated or modal-decorated copy of the base | 65 | // overlay receives the toast-decorated or modal-decorated copy of the base | ||
| 65 | // frame. Toasts and modals never both clone, so they share the slot. | 66 | // frame. Toasts and modals never both clone, so they share the slot. | ||
M internal/usecase/daemon/snapshot_worker_state.go +6 -4
| @@ -9,10 +9,12 @@ import ( | |||
| 9 | 9 | // other durable writers joined with it (maintenance and restoration), so | |
| 10 | 10 | // WaitDurableWriters can read all three completion signals under one lock. | |
| 11 | 11 | // | |
| 12 | - | // Lock position: mu is a leaf with respect to Daemon.mu. No code path acquires | |
| 13 | - | // Daemon.mu, a session lock, or a pane lock while holding it, and capture, | |
| 14 | - | // queue, and worker code never takes Daemon.mu. noticeMu is likewise a leaf and | |
| 15 | - | // is never held together with mu. | |
| 12 | + | // Lock position: mu is a leaf with respect to Daemon.mu and the session (mu), | |
| 13 | + | // tab, and pane locks: no path acquires any of them while holding it, and | |
| 14 | + | // capture, queue, and worker code never takes Daemon.mu. The one nested lock is | |
| 15 | + | // a session's snapshotMu, taken under mu by enqueueFinalSnapshotCapture; see | |
| 16 | + | // the lock-ordering notes in client.go. noticeMu is a leaf and is never held | |
| 17 | + | // together with mu. | |
| 16 | 18 | // | |
| 17 | 19 | // The zero value is usable for tests that build &Daemon{}: nil maps are | |
| 18 | 20 | // allocated lazily by the enqueue paths, and a nil jobs channel never becomes | |
| @@ -9,10 +9,12 @@ import ( | |||||
| 9 | // other durable writers joined with it (maintenance and restoration), so | 9 | // other durable writers joined with it (maintenance and restoration), so | ||
| 10 | // WaitDurableWriters can read all three completion signals under one lock. | 10 | // WaitDurableWriters can read all three completion signals under one lock. | ||
| 11 | // | 11 | // | ||
| 12 | - | // Lock position: mu is a leaf with respect to Daemon.mu. No code path acquires | 12 | + | // Lock position: mu is a leaf with respect to Daemon.mu and the session (mu), |
| 13 | - | // Daemon.mu, a session lock, or a pane lock while holding it, and capture, | 13 | + | // tab, and pane locks: no path acquires any of them while holding it, and |
| 14 | - | // queue, and worker code never takes Daemon.mu. noticeMu is likewise a leaf and | 14 | + | // capture, queue, and worker code never takes Daemon.mu. The one nested lock is |
| 15 | - | // is never held together with mu. | 15 | + | // a session's snapshotMu, taken under mu by enqueueFinalSnapshotCapture; see |
| 16 | + | // the lock-ordering notes in client.go. noticeMu is a leaf and is never held | |||
| 17 | + | // together with mu. | |||
| 16 | // | 18 | // | ||
| 17 | // The zero value is usable for tests that build &Daemon{}: nil maps are | 19 | // The zero value is usable for tests that build &Daemon{}: nil maps are | ||
| 18 | // allocated lazily by the enqueue paths, and a nil jobs channel never becomes | 20 | // allocated lazily by the enqueue paths, and a nil jobs channel never becomes | ||