diff --git a/Cargo.lock b/Cargo.lock index 6ab5821..5603b67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.16.15" +version = "0.16.16" dependencies = [ "anyhow", "async-stream", @@ -1686,7 +1686,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.16.15" +version = "0.16.16" dependencies = [ "anyhow", "base64", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.16.15" +version = "0.16.16" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index bad1d6e..1e3dcc8 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.16.15" +version = "0.16.16" edition = "2024" [dependencies] diff --git a/common/Cargo.toml b/common/Cargo.toml index 75d8f34..5ac381d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.16.15" +version = "0.16.16" edition = "2024" build = "build.rs" diff --git a/scripts/manual/browser_consumer_probe.py b/scripts/manual/browser_consumer_probe.py index c45ec8d..04f8e5f 100755 --- a/scripts/manual/browser_consumer_probe.py +++ b/scripts/manual/browser_consumer_probe.py @@ -23,7 +23,7 @@ class ProbeState: self.output_path = output_path self.status_path = status_path self.duration_seconds = duration_seconds - self.lock = threading.Lock() + self.lock = threading.RLock() self.start_token = 0 self.status = { "booted_at": time.time(), diff --git a/scripts/manual/local_av_stimulus.py b/scripts/manual/local_av_stimulus.py index 266a3b6..e896e88 100755 --- a/scripts/manual/local_av_stimulus.py +++ b/scripts/manual/local_av_stimulus.py @@ -43,7 +43,7 @@ class StimulusState: def __init__(self, status_path: Path, args: argparse.Namespace) -> None: self.status_path = status_path self.args = args - self.lock = threading.Lock() + self.lock = threading.RLock() self.start_token = 0 self.status = { "booted_at": time.time(), diff --git a/server/Cargo.toml b/server/Cargo.toml index 3fb79f4..b322450 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.16.15" +version = "0.16.16" edition = "2024" autobins = false diff --git a/testing/tests/client_manual_sync_script_contract.rs b/testing/tests/client_manual_sync_script_contract.rs index bdcaa45..cbe8400 100644 --- a/testing/tests/client_manual_sync_script_contract.rs +++ b/testing/tests/client_manual_sync_script_contract.rs @@ -124,3 +124,17 @@ fn local_stimulus_matches_sync_analyzer_pulse_contract() { ); } } + +#[test] +fn manual_probe_python_servers_use_reentrant_state_locks() { + const BROWSER_CONSUMER: &str = include_str!("../../scripts/manual/browser_consumer_probe.py"); + for (name, script) in [ + ("local stimulus", LOCAL_STIMULUS), + ("browser consumer", BROWSER_CONSUMER), + ] { + assert!( + script.contains("threading.RLock()"), + "{name} server request handlers call snapshot while holding state lock; use RLock to avoid /start deadlocks" + ); + } +}