1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! `TerminalWaker`: a cheap cross-thread handle that interrupts a blocking
//! `Terminal::read`, making the read return [`super::TermRead::Wake`].
//!
//! OWNER: KERNEL. This is REACT's loop primitive (cycle-1 request 6): the
//! reactive scheduler's `set_wake_callback` closure calls `wake()` whenever
//! a job is posted from another thread, so the event loop never needs a
//! tick timer to notice cross-thread work.
//!
//! Contract:
//! - `wake()` is cheap, non-blocking, panic-free and callable from any
//! thread (including while a `read` is mid-poll on the terminal thread).
//! - Wakes COALESCE: any number of `wake()` calls between two reads
//! guarantee at least one `TermRead::Wake`, not one per call. Consumers
//! drain all pending work per wake (the reactive scheduler already does).
//! - A waker outliving its terminal is harmless: `wake()` becomes a no-op
//! against a closed channel (platform notes in the backends).
//!
//! The concrete transport is platform-owned (unix: a dedicated self-pipe
//! polled beside the tty; windows: an auto-reset event in the wait set).
//! This type is deliberately just an `Arc<dyn Fn>` so test terminals
//! (REDTEAM's CaptureTerm) can mint one from any closure via
//! [`TerminalWaker::new`].
use fmt;
use Arc;
/// Cross-thread wake handle for a blocking [`crate::term::Terminal`]
/// read; see the module docs for the coalescing contract.
///
/// ```
/// use abstracttui::term::TerminalWaker;
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// use std::sync::Arc;
///
/// // Scripted terminals (and the reactive scheduler) mint wakers from
/// // any thread-safe closure; platform terminals hand out their own.
/// let hits = Arc::new(AtomicUsize::new(0));
/// let h = hits.clone();
/// let waker = TerminalWaker::new(move || { h.fetch_add(1, Ordering::SeqCst); });
///
/// let for_thread = waker.clone(); // Clone + Send + Sync
/// std::thread::spawn(move || for_thread.wake()).join().unwrap();
/// assert_eq!(hits.load(Ordering::SeqCst), 1);
/// ```