1use std::sync::Weak;
11use std::time::Duration;
12
13use crate::graph::{GraphInner, NodeId};
14
15mod delegating;
16mod platform;
17mod stats;
18mod thread_pool;
19
20pub use delegating::DelegatingExecutor;
21pub(crate) use stats::ExecutorStatsSnapshot;
22pub use thread_pool::ThreadPool;
23
24pub const DEFAULT_EXECUTOR_NAME: &str = "default";
33
34pub enum Executor {
40 Pool(ThreadPool),
42 Delegating(DelegatingExecutor),
44}
45
46impl Executor {
47 pub fn name(&self) -> &str {
48 match self {
49 Self::Pool(pool) => pool.name(),
50 Self::Delegating(delegating) => delegating.name(),
51 }
52 }
53
54 pub fn is_delegating(&self) -> bool {
56 matches!(self, Self::Delegating(_))
57 }
58
59 pub fn num_threads(&self) -> usize {
61 match self {
62 Self::Pool(pool) => pool.num_threads(),
63 Self::Delegating(_) => 0,
64 }
65 }
66
67 pub fn affinity(&self) -> &[usize] {
69 match self {
70 Self::Pool(pool) => pool.affinity(),
71 Self::Delegating(_) => &[],
72 }
73 }
74
75 pub fn priority(&self) -> i32 {
77 match self {
78 Self::Pool(pool) => pool.priority(),
79 Self::Delegating(_) => 0,
80 }
81 }
82
83 pub fn start(&self, graph: Weak<GraphInner>) {
85 if let Self::Pool(pool) = self {
86 pool.start(graph);
87 }
88 }
89
90 pub fn submit(&self, node: NodeId) -> bool {
92 match self {
93 Self::Pool(pool) => pool.submit(node),
94 Self::Delegating(delegating) => delegating.submit(node),
95 }
96 }
97
98 pub fn submit_source_wake(&self, node: NodeId, generation: u64, delay: Duration) -> bool {
99 match self {
100 Self::Pool(pool) => pool.submit_source_wake(node, generation, delay),
101 Self::Delegating(_) => false,
102 }
103 }
104
105 pub fn pending(&self) -> usize {
106 match self {
107 Self::Pool(pool) => pool.pending(),
108 Self::Delegating(delegating) => delegating.pending(),
109 }
110 }
111
112 pub fn shutdown(&self) {
114 if let Self::Pool(pool) = self {
115 pool.shutdown();
116 }
117 }
118
119 pub fn take_delegated(&self) -> Option<NodeId> {
121 match self {
122 Self::Pool(_) => None,
123 Self::Delegating(delegating) => delegating.take(),
124 }
125 }
126
127 pub fn complete_delegated(&self, execution: Option<Duration>) {
128 if let Self::Delegating(delegating) = self {
129 delegating.complete(execution);
130 }
131 }
132
133 pub(crate) fn stats(&self) -> ExecutorStatsSnapshot {
134 match self {
135 Self::Pool(pool) => pool.stats(),
136 Self::Delegating(delegating) => delegating.stats(),
137 }
138 }
139
140 pub(crate) fn has_pending_work(&self) -> bool {
141 match self {
142 Self::Pool(pool) => pool.has_pending_work(),
143 Self::Delegating(delegating) => delegating.has_pending_work(),
144 }
145 }
146
147 pub(crate) fn queued_nodes(&self) -> Vec<NodeId> {
148 match self {
149 Self::Pool(pool) => pool.queued_nodes(),
150 Self::Delegating(delegating) => delegating.queued_nodes(),
151 }
152 }
153
154 pub fn clear_delegated(&self) {
156 if let Self::Delegating(delegating) = self {
157 delegating.clear();
158 }
159 }
160
161 pub fn reset_run_state(&self) {
162 match self {
163 Self::Pool(pool) => {
164 pool.clear_delayed();
165 pool.reset_stats();
166 }
167 Self::Delegating(delegating) => {
168 delegating.clear();
169 delegating.reset_stats();
170 }
171 }
172 }
173
174 pub fn clear_delayed(&self) {
175 if let Self::Pool(pool) = self {
176 pool.clear_delayed();
177 }
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn delegating_submit_survives_shutdown() {
187 let executor = Executor::Delegating(DelegatingExecutor::new("host"));
188 executor.shutdown();
189 assert!(
190 executor.submit(1),
191 "委托执行器没有『已关停』状态 —— 宿主线程不由引擎拉起,也无从 join"
192 );
193 }
194
195 #[test]
196 fn executor_kinds_report_their_shape() {
197 let pool = Executor::Pool(ThreadPool::new("cpu", 4, vec![2, 3], 10));
198 let host = Executor::Delegating(DelegatingExecutor::new(DEFAULT_EXECUTOR_NAME));
199
200 assert!(!pool.is_delegating());
201 assert_eq!(pool.name(), "cpu");
202 assert_eq!(pool.num_threads(), 4);
203 assert_eq!(pool.affinity(), &[2, 3]);
204 assert_eq!(pool.priority(), 10);
205 assert_eq!(pool.take_delegated(), None);
206
207 assert!(host.is_delegating());
208 assert_eq!(host.name(), DEFAULT_EXECUTOR_NAME);
209 assert_eq!(host.num_threads(), 0);
210 assert!(host.affinity().is_empty());
211 assert_eq!(host.priority(), 0);
212 host.submit(5);
213 assert_eq!(host.take_delegated(), Some(5));
214 }
215}