Skip to content

refactor: now_unix_secs/nanos + LockExt::lock_ignore_poison - #356

Merged
yogthos merged 4 commits into
mainfrom
refactor/volume-idioms-time-lock
Jun 2, 2026
Merged

refactor: now_unix_secs/nanos + LockExt::lock_ignore_poison#356
yogthos merged 4 commits into
mainfrom
refactor/volume-idioms-time-lock

Conversation

@yogthos

@yogthos yogthos commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Round C of the duplication consolidation (epic dirge-9l12, dirge-xhoo) — the volume idioms.

#4 time_util — the SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_*()).unwrap_or(0) idiom was hand-rolled ~16× (secs + nanos). Hoisted to crate::time_util::now_unix_secs() / now_unix_nanos(); converted the uniform multi-line sites. Variant forms (file-mtime timestamps, subsec_nanos() as u64, non-.map error handling) are genuinely different and left as-is — only now_unix_secs/now_unix_nanos were actually needed (dropped the unused millis helper rather than ship dead code).

LockExt::lock_ignore_poison — the cryptic .lock().unwrap_or_else(|e| e.into_inner()) poison-recovery idiom appeared 123 times across 43 files. Replaced with a named LockExt::lock_ignore_poison() extension method (crate::sync_util) so the intent — dirge never relies on lock poisoning for correctness — is legible at every call site instead of buried in a closure. All sites are std::sync::Mutex; behavior identical.

2456 default / 2550 all-features tests pass (incl. a new poison-recovery test that verifies the guard is recovered after a panic-while-locked); clean under -D warnings in both configs. One Round D PR (text/transcript helpers) remains.

Yogthos added 4 commits June 2, 2026 17:54
…dirge-xhoo]

#4 time_util: SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_X())
.unwrap_or(0) was hand-rolled ~16 times (secs + nanos). Hoisted to
crate::time_util::now_unix_secs() / now_unix_nanos(); converted the uniform
multi-line sites. The variant forms (file-mtime, subsec_nanos as u64,
non-.map error handling) are genuinely different and left as-is.

#lock: the cryptic .lock().unwrap_or_else(|e| e.into_inner()) poison-recovery
idiom appeared 123 times across 43 files. Replaced with a named
LockExt::lock_ignore_poison() extension method (crate::sync_util) so the
intent ('dirge never relies on poison') is legible at every call site.
All sites are std::sync::Mutex; behavior identical.

2456 default / 2550 all-features tests pass (incl. a new poison-recovery
test); clean under -D warnings in both default + all-features.
…figs

The windows-default config (--no-default-features) gates out the feature
blocks (mcp/plugin/lsp/…) that hold many lock_ignore_poison() call sites,
leaving the LockExt import unused there. The trait is genuinely
conditionally-used per feature set, so annotate the imports. Verified with
cargo build --no-default-features --features windows-default.
…HECK global

The two tests that mutate the process-global DAP_PERM_CHECK static used
per-statement locks, so under parallel execution no_perm_check_when_none
could set None between dap_perm_check_roundtrips' write and read-back —
failing read_back.is_some() intermittently. Both tests now hold the global's
mutex for their whole body (one critical section), serializing them on that
lock so they can't interleave. Uses lock_ignore_poison for poison-robustness.
Stress-ran 25x clean.
…ner) stragglers

The single-line perl in the prior commit missed the multi-line form
(.lock() and .unwrap_or_else() on separate lines) — ~32 sites. Converted
them to lock_ignore_poison() too (+ LockExt import in the 3 files that had
ONLY the multi-line form). The 3 remaining unwrap_or_else(into_inner) sites
are RwLock .read()/.write() (notifications.rs) — a different lock type, left
as-is (not worth a second ext-trait for 3 sites). All configs build clean.
@yogthos
yogthos merged commit 7997e94 into main Jun 2, 2026
10 checks passed
@yogthos
yogthos deleted the refactor/volume-idioms-time-lock branch June 2, 2026 22:14
allen-munsch pushed a commit to allen-munsch/dirge that referenced this pull request Jun 3, 2026
…de#356)

* refactor: now_unix_secs/nanos + LockExt::lock_ignore_poison helpers [dirge-xhoo]

#4 time_util: SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_X())
.unwrap_or(0) was hand-rolled ~16 times (secs + nanos). Hoisted to
crate::time_util::now_unix_secs() / now_unix_nanos(); converted the uniform
multi-line sites. The variant forms (file-mtime, subsec_nanos as u64,
non-.map error handling) are genuinely different and left as-is.

#lock: the cryptic .lock().unwrap_or_else(|e| e.into_inner()) poison-recovery
idiom appeared 123 times across 43 files. Replaced with a named
LockExt::lock_ignore_poison() extension method (crate::sync_util) so the
intent ('dirge never relies on poison') is legible at every call site.
All sites are std::sync::Mutex; behavior identical.

2456 default / 2550 all-features tests pass (incl. a new poison-recovery
test); clean under -D warnings in both default + all-features.

* fix: allow(unused_imports) on LockExt imports for minimal feature configs

The windows-default config (--no-default-features) gates out the feature
blocks (mcp/plugin/lsp/…) that hold many lock_ignore_poison() call sites,
leaving the LockExt import unused there. The trait is genuinely
conditionally-used per feature set, so annotate the imports. Verified with
cargo build --no-default-features --features windows-default.

* test(dap): fix flaky dap_perm_check_roundtrips race on the DAP_PERM_CHECK global

The two tests that mutate the process-global DAP_PERM_CHECK static used
per-statement locks, so under parallel execution no_perm_check_when_none
could set None between dap_perm_check_roundtrips' write and read-back —
failing read_back.is_some() intermittently. Both tests now hold the global's
mutex for their whole body (one critical section), serializing them on that
lock so they can't interleave. Uses lock_ignore_poison for poison-robustness.
Stress-ran 25x clean.

* refactor: convert remaining multi-line .lock().unwrap_or_else(into_inner) stragglers

The single-line perl in the prior commit missed the multi-line form
(.lock() and .unwrap_or_else() on separate lines) — ~32 sites. Converted
them to lock_ignore_poison() too (+ LockExt import in the 3 files that had
ONLY the multi-line form). The 3 remaining unwrap_or_else(into_inner) sites
are RwLock .read()/.write() (notifications.rs) — a different lock type, left
as-is (not worth a second ext-trait for 3 sites). All configs build clean.

---------

Co-authored-by: Yogthos <yogthos@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant