kobako 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +217 -10
- data/Cargo.lock +139 -141
- data/README.md +96 -574
- data/ROADMAP.md +2 -1
- data/crates/kobako-runtime/CHANGELOG.md +269 -1
- data/crates/kobako-runtime/Cargo.toml +25 -15
- data/crates/kobako-runtime/README.md +7 -3
- data/crates/kobako-runtime/src/dispatch.rs +1 -1
- data/crates/kobako-runtime/src/endpoint/buffer.rs +192 -0
- data/crates/kobako-runtime/src/endpoint/capture.rs +115 -0
- data/crates/kobako-runtime/src/endpoint/dispatch.rs +253 -0
- data/crates/kobako-runtime/src/endpoint/invoke.rs +194 -0
- data/crates/kobako-runtime/src/endpoint/memory_cap.rs +238 -0
- data/crates/kobako-runtime/src/endpoint.rs +166 -0
- data/crates/kobako-runtime/src/filesystem/bind/fid.rs +82 -0
- data/crates/kobako-runtime/src/filesystem/{directory/spelling.rs → bind/lookup.rs} +91 -49
- data/crates/kobako-runtime/src/filesystem/bind/walk.rs +249 -0
- data/crates/kobako-runtime/src/filesystem/bind.rs +2665 -0
- data/crates/kobako-runtime/src/filesystem/overlay/file.rs +89 -0
- data/crates/kobako-runtime/src/filesystem/overlay/inode.rs +106 -0
- data/crates/kobako-runtime/src/filesystem/overlay/path.rs +285 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/copy_up.rs +135 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/dir.rs +263 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/namei.rs +135 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack/readdir.rs +57 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack.rs +227 -734
- data/crates/kobako-runtime/src/filesystem/overlay.rs +2649 -1135
- data/crates/kobako-runtime/src/filesystem/path.rs +2 -41
- data/crates/kobako-runtime/src/filesystem/pipe.rs +221 -0
- data/crates/kobako-runtime/src/filesystem/rdir.rs +101 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/tmpfile.rs +32 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/whiteout.rs +85 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs/xattr.rs +22 -0
- data/crates/kobako-runtime/src/filesystem/tmpfs.rs +1985 -0
- data/crates/kobako-runtime/src/filesystem/wrap.rs +224 -0
- data/crates/kobako-runtime/src/filesystem.rs +21 -387
- data/crates/kobako-runtime/src/hashtable.rs +44 -0
- data/crates/kobako-runtime/src/lib.rs +11 -6
- data/crates/kobako-runtime/src/locking/seqlock.rs +66 -0
- data/crates/kobako-runtime/src/locking.rs +218 -0
- data/crates/kobako-runtime/src/mount.rs +31 -104
- data/crates/kobako-runtime/src/profile.rs +137 -1
- data/crates/kobako-runtime/src/sched.rs +210 -0
- data/crates/kobako-runtime/src/security.rs +696 -0
- data/crates/kobako-runtime/src/vfs/attr.rs +162 -0
- data/crates/kobako-runtime/src/vfs/cred.rs +334 -0
- data/crates/kobako-runtime/src/vfs/dentry.rs +1412 -0
- data/crates/kobako-runtime/src/vfs/errno.rs +153 -0
- data/crates/kobako-runtime/src/vfs/file.rs +1915 -0
- data/crates/kobako-runtime/src/vfs/inode.rs +429 -0
- data/crates/kobako-runtime/src/vfs/kern_path.rs +217 -0
- data/crates/kobako-runtime/src/vfs/mount.rs +59 -0
- data/crates/kobako-runtime/src/vfs/namei.rs +5708 -0
- data/crates/kobako-runtime/src/vfs/openat2.rs +116 -0
- data/crates/kobako-runtime/src/vfs/path.rs +64 -0
- data/crates/kobako-runtime/src/vfs/readdir.rs +163 -0
- data/crates/kobako-runtime/src/vfs/stat.rs +157 -0
- data/crates/kobako-runtime/src/vfs/super_block.rs +122 -0
- data/crates/kobako-runtime/src/vfs/utimes.rs +289 -0
- data/crates/kobako-runtime/src/vfs.rs +60 -0
- data/crates/kobako-runtime/tests/linux_baseline/calls.rs +171 -0
- data/crates/kobako-runtime/tests/linux_baseline/concurrent.rs +276 -0
- data/crates/kobako-runtime/tests/linux_baseline/kobako.rs +323 -0
- data/crates/kobako-runtime/tests/linux_baseline/linux-baseline-expected.txt +16 -0
- data/crates/kobako-runtime/tests/linux_baseline/linux.rs +449 -0
- data/crates/kobako-runtime/tests/linux_baseline/main.rs +611 -0
- data/crates/kobako-runtime/tests/linux_baseline/permissions.rs +236 -0
- data/crates/kobako-transport/CHANGELOG.md +8 -2
- data/crates/kobako-transport/Cargo.toml +3 -3
- data/crates/kobako-transport/README.md +6 -5
- data/crates/kobako-transport/src/envelope/bytes.rs +33 -25
- data/crates/kobako-transport/src/envelope/call.rs +5 -5
- data/crates/kobako-transport/src/envelope/compile_reply.rs +2 -2
- data/crates/kobako-transport/src/envelope/error_record.rs +3 -3
- data/crates/kobako-transport/src/envelope/fault.rs +2 -2
- data/crates/kobako-transport/src/envelope/outcome.rs +3 -3
- data/crates/kobako-transport/src/envelope/preamble.rs +12 -12
- data/crates/kobako-transport/src/envelope/reply.rs +2 -2
- data/crates/kobako-transport/src/envelope/request.rs +2 -2
- data/crates/kobako-transport/src/envelope/run.rs +1 -1
- data/crates/kobako-transport/src/envelope/unsupported.rs +2 -2
- data/crates/kobako-transport/src/envelope.rs +2 -2
- data/crates/kobako-wasmtime/CHANGELOG.md +154 -8
- data/crates/kobako-wasmtime/Cargo.toml +15 -14
- data/crates/kobako-wasmtime/README.md +9 -5
- data/crates/kobako-wasmtime/src/abi.rs +12 -20
- data/crates/kobako-wasmtime/src/ambient.rs +1 -2
- data/crates/kobako-wasmtime/src/cache.rs +5 -5
- data/crates/kobako-wasmtime/src/config.rs +22 -7
- data/crates/kobako-wasmtime/src/descriptors.rs +133 -100
- data/crates/kobako-wasmtime/src/driver.rs +29 -96
- data/crates/kobako-wasmtime/src/exports.rs +5 -16
- data/crates/kobako-wasmtime/src/guest.rs +38 -0
- data/crates/kobako-wasmtime/src/imports.rs +14 -8
- data/crates/kobako-wasmtime/src/instance_pre.rs +3 -3
- data/crates/kobako-wasmtime/src/invocation.rs +26 -46
- data/crates/kobako-wasmtime/src/lib.rs +1 -4
- data/crates/kobako-wasmtime/src/limiter.rs +6 -230
- data/crates/kobako-wasmtime/src/preview1/differential/mount.rs +69 -46
- data/crates/kobako-wasmtime/src/preview1/differential.rs +121 -7
- data/crates/kobako-wasmtime/src/preview1/errno.rs +74 -206
- data/crates/kobako-wasmtime/src/preview1/fd.rs +1248 -500
- data/crates/kobako-wasmtime/src/preview1/memory.rs +117 -150
- data/crates/kobako-wasmtime/src/preview1/mount_view/wrap.rs +211 -0
- data/crates/kobako-wasmtime/src/preview1/mount_view.rs +1939 -672
- data/crates/kobako-wasmtime/src/preview1/path.rs +230 -349
- data/crates/kobako-wasmtime/src/preview1/poll.rs +148 -100
- data/crates/kobako-wasmtime/src/preview1/sock.rs +6 -23
- data/crates/kobako-wasmtime/src/preview1/testsuite-expected.txt +6 -0
- data/crates/kobako-wasmtime/src/preview1/testsuite.rs +157 -0
- data/crates/kobako-wasmtime/src/preview1.rs +464 -413
- data/crates/kobako-wasmtime/src/trap.rs +9 -9
- data/crates/kobako-wasmtime/src/wasi.rs +53 -37
- data/crates/kobako-wasmtime/tests/{guest_file.rs → integration/guest_file.rs} +232 -201
- data/crates/kobako-wasmtime/tests/integration/main.rs +29 -0
- data/crates/kobako-wasmtime/tests/{preamble_flags.rs → integration/preamble_flags.rs} +1 -1
- data/crates/kobako-wasmtime/tests/{snippet_compile.rs → integration/snippet_compile.rs} +1 -1
- data/crates/kobako-wasmtime/tests/{unanswered_call.rs → integration/unanswered_call.rs} +1 -1
- data/crates/kobako-wasmtime/tests/{unsupported_call.rs → integration/unsupported_call.rs} +1 -1
- data/crates/kobako-wasmtime/witx/typenames.witx +750 -0
- data/crates/kobako-wasmtime/witx/wasi_snapshot_preview1.witx +441 -0
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +1 -1
- data/ext/kobako/src/runtime/bridge.rs +1 -1
- data/ext/kobako/src/runtime/errors.rs +1 -1
- data/ext/kobako/src/runtime/escape.rs +28 -14
- data/ext/kobako/src/runtime/filesystem/grants.rs +21 -5
- data/ext/kobako/src/runtime/filesystem/ruby.rs +464 -156
- data/ext/kobako/src/runtime/filesystem.rs +109 -137
- data/ext/kobako/src/runtime/gvl.rs +43 -8
- data/ext/kobako/src/runtime/snapshot.rs +1 -1
- data/ext/kobako/src/runtime.rs +6 -1
- data/lib/kobako/catalog/extensions.rb +5 -5
- data/lib/kobako/catalog/flags.rb +2 -2
- data/lib/kobako/catalog/handles.rb +6 -6
- data/lib/kobako/catalog/mount.rb +2 -10
- data/lib/kobako/catalog/services.rb +2 -2
- data/lib/kobako/catalog/snippets.rb +7 -7
- data/lib/kobako/catalog.rb +1 -1
- data/lib/kobako/codec/decoder.rb +10 -10
- data/lib/kobako/codec/ext_types.rb +3 -5
- data/lib/kobako/codec/handle_walk.rb +4 -6
- data/lib/kobako/codec/nesting.rb +7 -7
- data/lib/kobako/codec/utils.rb +1 -1
- data/lib/kobako/codec/value_budget.rb +3 -3
- data/lib/kobako/context.rb +5 -5
- data/lib/kobako/filesystem.rb +44 -13
- data/lib/kobako/payload/arguments.rb +2 -2
- data/lib/kobako/pool.rb +4 -4
- data/lib/kobako/sandbox.rb +28 -28
- data/lib/kobako/sandbox_options.rb +2 -3
- data/lib/kobako/snippet/bytecode.rb +1 -1
- data/lib/kobako/snippet/source.rb +1 -1
- data/lib/kobako/transport/dispatcher.rb +5 -5
- data/lib/kobako/transport/exposure.rb +2 -2
- data/lib/kobako/transport/reflection.rb +7 -7
- data/lib/kobako/transport/run.rb +5 -5
- data/lib/kobako/transport/yielder.rb +1 -1
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +34 -0
- data/release-please-config.json +1 -0
- data/sig/kobako/catalog/extensions.rbs +3 -3
- data/sig/kobako/catalog/handles.rbs +3 -3
- data/sig/kobako/catalog/mount.rbs +0 -4
- data/sig/kobako/catalog/services.rbs +1 -1
- data/sig/kobako/catalog/snippets.rbs +3 -3
- data/sig/kobako/catalog.rbs +1 -1
- data/sig/kobako/codec/decoder.rbs +1 -1
- data/sig/kobako/codec/handle_walk.rbs +1 -1
- data/sig/kobako/codec/nesting.rbs +2 -2
- data/sig/kobako/codec/utils.rbs +1 -1
- data/sig/kobako/codec/value_budget.rbs +1 -1
- data/sig/kobako/codec.rbs +1 -2
- data/sig/kobako/context.rbs +1 -1
- data/sig/kobako/filesystem.rbs +19 -14
- data/sig/kobako/guest_yielder.rbs +1 -1
- data/sig/kobako/payload/arguments.rbs +1 -1
- data/sig/kobako/pool.rbs +2 -2
- data/sig/kobako/runtime.rbs +1 -1
- data/sig/kobako/sandbox.rbs +3 -5
- data/sig/kobako/sandbox_options.rbs +1 -1
- data/sig/kobako/transport/dispatcher.rbs +2 -2
- data/sig/kobako/transport/exposure.rbs +1 -1
- data/sig/kobako/transport/reflection.rbs +2 -2
- data/sig/kobako/transport/run.rbs +3 -3
- data/sig/kobako/transport.rbs +1 -1
- metadata +67 -19
- data/crates/kobako-runtime/src/filesystem/directory.rs +0 -1082
- data/crates/kobako-runtime/src/filesystem/memory.rs +0 -1100
- data/crates/kobako-runtime/src/filesystem/overlay/exclusive.rs +0 -88
- data/crates/kobako-runtime/src/filesystem/temporary.rs +0 -167
- data/crates/kobako-wasmtime/src/capture.rs +0 -96
- data/crates/kobako-wasmtime/src/dispatch.rs +0 -125
- data/crates/kobako-wasmtime/src/guest_mem.rs +0 -271
- data/crates/kobako-wasmtime/src/io.rs +0 -89
- data/crates/kobako-wasmtime/src/preview1/args.rs +0 -60
- data/crates/kobako-wasmtime/src/preview1/beneath.rs +0 -188
- /data/crates/kobako-wasmtime/tests/{compile_posture.rs → integration/compile_posture.rs} +0 -0
- /data/crates/kobako-wasmtime/tests/{support → integration/support}/mod.rs +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
//! Who is running and how it waits, beneath every lock, as Linux's
|
|
2
|
+
//! `kernel/sched` is: a lock asks only for its wait to happen, so nothing
|
|
3
|
+
//! above it knows what waiting means to the frontend. A run past its deadline,
|
|
4
|
+
//! or one its frontend interrupted, stops waiting, as a fatal signal ends
|
|
5
|
+
//! Linux's killable waits, so one Sandbox holding a lock never holds another's
|
|
6
|
+
//! thread past that one's own end.
|
|
7
|
+
|
|
8
|
+
use std::cell::RefCell;
|
|
9
|
+
use std::sync::atomic::{AtomicBool, Ordering};
|
|
10
|
+
use std::sync::{Arc, OnceLock};
|
|
11
|
+
use std::thread::{self, ThreadId};
|
|
12
|
+
use std::time::{Duration, Instant};
|
|
13
|
+
|
|
14
|
+
/// How a thread waits for a lock another thread holds. A frontend whose
|
|
15
|
+
/// threads share a lock of their own, as Ruby's threads share the GVL,
|
|
16
|
+
/// gives that lock up for the wait, or a holder that needs it to finish
|
|
17
|
+
/// never could.
|
|
18
|
+
pub trait Blocking: Send + Sync {
|
|
19
|
+
/// Run `wait`, which returns once the lock is taken.
|
|
20
|
+
fn wait(&self, wait: &mut dyn FnMut());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static BLOCKING: OnceLock<Box<dyn Blocking>> = OnceLock::new();
|
|
24
|
+
|
|
25
|
+
/// Have every thread of this process wait through `blocking`, as a frontend
|
|
26
|
+
/// says once at startup; a later one is handed back, as
|
|
27
|
+
/// `register_filesystem` refuses a second. Without one a thread just waits.
|
|
28
|
+
pub fn register_blocking(blocking: Box<dyn Blocking>) -> Result<(), Box<dyn Blocking>> {
|
|
29
|
+
BLOCKING.set(blocking)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Run `wait` as this process's threads wait, as a lock's slow path calls
|
|
33
|
+
/// `schedule`.
|
|
34
|
+
pub(crate) fn schedule(wait: &mut dyn FnMut()) {
|
|
35
|
+
match BLOCKING.get() {
|
|
36
|
+
Some(blocking) => blocking.wait(wait),
|
|
37
|
+
None => wait(),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
thread_local! {
|
|
42
|
+
static CURRENT: ThreadId = thread::current().id();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Who is running, as Linux's `current`.
|
|
46
|
+
pub(crate) fn current() -> ThreadId {
|
|
47
|
+
CURRENT.with(|current| *current)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// A thread as its frontend may interrupt it from another thread, as a signal
|
|
51
|
+
/// reaches a Linux task.
|
|
52
|
+
#[derive(Clone, Default)]
|
|
53
|
+
pub struct Task {
|
|
54
|
+
interrupted: Arc<AtomicBool>,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
impl Task {
|
|
58
|
+
/// The calling thread.
|
|
59
|
+
pub fn current() -> Self {
|
|
60
|
+
TASK.with(|task| task.borrow().task.clone())
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Have every wait of the run this thread carries out stop, as a fatal
|
|
64
|
+
/// signal ends a killable wait; it holds until that run ends.
|
|
65
|
+
pub fn interrupt(&self) {
|
|
66
|
+
self.interrupted.store(true, Ordering::SeqCst);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// The task this thread carries out, as Linux's `current`, and when its run is
|
|
71
|
+
/// to stop.
|
|
72
|
+
#[derive(Default)]
|
|
73
|
+
struct Current {
|
|
74
|
+
task: Task,
|
|
75
|
+
deadline: Option<Instant>,
|
|
76
|
+
/// How many runs the thread is inside, one within another where a
|
|
77
|
+
/// Filesystem's own call starts another.
|
|
78
|
+
depth: usize,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
thread_local! {
|
|
82
|
+
static TASK: RefCell<Current> = RefCell::default();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/// Run `run` as a run that stops waiting once `deadline` passes or its thread
|
|
86
|
+
/// is interrupted, as a Linux task stops a killable wait on a fatal signal. A
|
|
87
|
+
/// run within another keeps the outer one's interrupt.
|
|
88
|
+
pub fn run_task<T>(deadline: Option<Instant>, run: impl FnOnce() -> T) -> T {
|
|
89
|
+
/// Puts back the deadline of the run around this one, however `run` ends,
|
|
90
|
+
/// and lets an interrupt go once no run is left.
|
|
91
|
+
struct Outer(Option<Instant>);
|
|
92
|
+
|
|
93
|
+
impl Drop for Outer {
|
|
94
|
+
fn drop(&mut self) {
|
|
95
|
+
TASK.with(|task| {
|
|
96
|
+
let mut running = task.borrow_mut();
|
|
97
|
+
running.deadline = self.0;
|
|
98
|
+
running.depth -= 1;
|
|
99
|
+
if running.depth == 0 {
|
|
100
|
+
running.task.interrupted.store(false, Ordering::SeqCst);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let _outer = Outer(TASK.with(|task| {
|
|
107
|
+
let mut running = task.borrow_mut();
|
|
108
|
+
running.depth += 1;
|
|
109
|
+
std::mem::replace(&mut running.deadline, deadline)
|
|
110
|
+
}));
|
|
111
|
+
run()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Whether the calling thread's run is to stop waiting, as Linux's
|
|
115
|
+
/// `fatal_signal_pending(current)` answers.
|
|
116
|
+
pub(crate) fn fatal_signal_pending() -> bool {
|
|
117
|
+
TASK.with(|task| {
|
|
118
|
+
let running = task.borrow();
|
|
119
|
+
running.task.interrupted.load(Ordering::SeqCst)
|
|
120
|
+
|| running.deadline.is_some_and(|at| Instant::now() >= at)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// The most a wait sleeps before it looks again whether its run is to stop.
|
|
125
|
+
const MAX_SLEEP: Duration = Duration::from_millis(10);
|
|
126
|
+
|
|
127
|
+
/// How long a wait sleeps before it looks again whether its run is to stop:
|
|
128
|
+
/// never past its deadline.
|
|
129
|
+
pub(crate) fn sleep_slice() -> Duration {
|
|
130
|
+
TASK.with(|task| match task.borrow().deadline {
|
|
131
|
+
Some(at) => at.saturating_duration_since(Instant::now()).min(MAX_SLEEP),
|
|
132
|
+
None => MAX_SLEEP,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/// A process has one Blocking, so a test counts only the waits of the thread
|
|
137
|
+
/// that asked to.
|
|
138
|
+
#[cfg(test)]
|
|
139
|
+
pub(crate) mod testing {
|
|
140
|
+
use std::cell::RefCell;
|
|
141
|
+
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
142
|
+
use std::sync::Arc;
|
|
143
|
+
use std::time::{Duration, Instant};
|
|
144
|
+
|
|
145
|
+
/// The longest a test waits for another thread, so what never arrives fails
|
|
146
|
+
/// the test instead of hanging the suite.
|
|
147
|
+
pub(crate) const MAX_WAIT: Duration = Duration::from_secs(10);
|
|
148
|
+
|
|
149
|
+
/// Wait until `arrived`, failing the test with `what` past `MAX_WAIT`.
|
|
150
|
+
pub(crate) fn wait_until(what: &str, mut arrived: impl FnMut() -> bool) {
|
|
151
|
+
let started = Instant::now();
|
|
152
|
+
while !arrived() {
|
|
153
|
+
assert!(
|
|
154
|
+
started.elapsed() < MAX_WAIT,
|
|
155
|
+
"{what} did not happen within {MAX_WAIT:?}"
|
|
156
|
+
);
|
|
157
|
+
std::thread::yield_now();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// What the thread `handle` runs answers, failing the test with `what` past
|
|
162
|
+
/// `MAX_WAIT`, so a thread stuck on a lock fails rather than hangs.
|
|
163
|
+
pub(crate) fn join<T>(what: &str, handle: std::thread::JoinHandle<T>) -> T {
|
|
164
|
+
wait_until(what, || handle.is_finished());
|
|
165
|
+
handle
|
|
166
|
+
.join()
|
|
167
|
+
.unwrap_or_else(|_| panic!("{what} must not panic"))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// What the scoped thread `handle` runs answers, as `join` waits for one.
|
|
171
|
+
pub(crate) fn join_scoped<T>(what: &str, handle: std::thread::ScopedJoinHandle<'_, T>) -> T {
|
|
172
|
+
wait_until(what, || handle.is_finished());
|
|
173
|
+
handle
|
|
174
|
+
.join()
|
|
175
|
+
.unwrap_or_else(|_| panic!("{what} must not panic"))
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// What `run` answers, each wait for a lock in it ending past `MAX_WAIT`, so a
|
|
179
|
+
/// test thread waiting on a lock itself fails rather than hangs.
|
|
180
|
+
pub(crate) fn within_max_wait<T>(run: impl FnOnce() -> T) -> T {
|
|
181
|
+
super::run_task(Some(Instant::now() + MAX_WAIT), run)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
use super::{Blocking, BLOCKING};
|
|
185
|
+
|
|
186
|
+
thread_local! {
|
|
187
|
+
static COUNTS: RefCell<Option<Arc<AtomicUsize>>> = const { RefCell::new(None) };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
struct CountsWaits;
|
|
191
|
+
|
|
192
|
+
impl Blocking for CountsWaits {
|
|
193
|
+
fn wait(&self, wait: &mut dyn FnMut()) {
|
|
194
|
+
COUNTS.with(|counts| {
|
|
195
|
+
if let Some(counts) = counts.borrow().as_ref() {
|
|
196
|
+
counts.fetch_add(1, Ordering::SeqCst);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
wait();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// Counts each wait this thread makes through the registered Blocking.
|
|
204
|
+
pub(crate) fn count_waits() -> Arc<AtomicUsize> {
|
|
205
|
+
BLOCKING.get_or_init(|| Box::new(CountsWaits));
|
|
206
|
+
let counts = Arc::<AtomicUsize>::default();
|
|
207
|
+
COUNTS.with(|held| *held.borrow_mut() = Some(counts.clone()));
|
|
208
|
+
counts
|
|
209
|
+
}
|
|
210
|
+
}
|