1use crate::{
6 affinity::cpu_has_core_else_panic,
7 barrier::{Barrier, NONE},
8 consumer::{event_poller::EventPoller, start_processor, start_processor_with_state, Consumer},
9 cursor::Cursor,
10 event_handler::{EventHandler, EventHandlerWithState},
11 producer::{multi::MultiProducerBarrier, single::SingleProducerBarrier},
12 ringbuffer::RingBuffer,
13 wait_strategies::WaitStrategy,
14};
15use core_affinity::CoreId;
16use crossbeam_utils::CachePadded;
17use std::sync::{atomic::AtomicI64, Arc};
18
19use self::{multi::MPBuilder, single::SPBuilder};
20
21pub mod multi;
22pub mod single;
23
24pub struct NC;
26pub struct SC;
28pub struct MC;
30
31pub fn build_single_producer<E, W, F>(
59 size: usize,
60 event_factory: F,
61 wait_strategy: W,
62) -> SPBuilder<NC, E, W, SingleProducerBarrier>
63where
64 F: FnMut() -> E,
65 E: 'static + Send + Sync,
66 W: 'static + WaitStrategy,
67{
68 let producer_barrier = Arc::new(SingleProducerBarrier::new());
69 let dependent_barrier = Arc::clone(&producer_barrier);
70 SPBuilder::new(
71 size,
72 event_factory,
73 wait_strategy,
74 producer_barrier,
75 dependent_barrier,
76 )
77}
78
79pub fn build_multi_producer<E, W, F>(
109 size: usize,
110 event_factory: F,
111 wait_strategy: W,
112) -> MPBuilder<NC, E, W, MultiProducerBarrier>
113where
114 F: FnMut() -> E,
115 E: 'static + Send + Sync,
116 W: 'static + WaitStrategy,
117{
118 let producer_barrier = Arc::new(MultiProducerBarrier::new(size));
119 let dependent_barrier = Arc::clone(&producer_barrier);
120 MPBuilder::new(
121 size,
122 event_factory,
123 wait_strategy,
124 producer_barrier,
125 dependent_barrier,
126 )
127}
128
129pub trait ProcessorSettings<E, W>: Sized
158where
159 W: WaitStrategy,
160{
161 #[doc(hidden)]
162 fn shared(&mut self) -> &mut Shared<E, W>;
163
164 fn pin_at_core(mut self, id: usize) -> Self {
167 self.shared().pin_at_core(id);
168 self
169 }
170
171 fn thread_name(mut self, name: &'static str) -> Self {
173 self.shared().thread_named(name);
174 self
175 }
176}
177
178trait Builder<E, W, B>: ProcessorSettings<E, W>
179where
180 E: 'static + Send + Sync,
181 B: 'static + Barrier,
182 W: 'static + WaitStrategy,
183{
184 fn add_event_handler<EH>(&mut self, event_handler: EH)
185 where
186 EH: 'static + EventHandler<E>,
187 {
188 let barrier = self.dependent_barrier();
189 let notifier = self.shared().notifier.clone();
190 let (cursor, consumer) = start_processor(event_handler, self.shared(), barrier, notifier);
191 self.shared().add_consumer_and_cursor(consumer, cursor);
192 }
193
194 fn get_event_poller(&mut self) -> EventPoller<E, B, W::Notifier> {
195 let cursor = Arc::new(Cursor::new(-1)); self.shared().add_cursor(Arc::clone(&cursor));
197 let notifier = self.shared().notifier.clone();
198
199 EventPoller::new(
200 Arc::clone(&self.shared().ring_buffer),
201 Arc::clone(&self.dependent_barrier()),
202 Arc::clone(&self.shared().shutdown_at_sequence),
203 cursor,
204 notifier,
205 )
206 }
207
208 fn add_event_handler_with_state<EH, S, IS>(&mut self, event_handler: EH, initialize_state: IS)
209 where
210 EH: 'static + EventHandlerWithState<E, S>,
211 IS: 'static + Send + FnOnce() -> S,
212 {
213 let barrier = self.dependent_barrier();
214 let notifier = self.shared().notifier.clone();
215 let (cursor, consumer) = start_processor_with_state(
216 event_handler,
217 self.shared(),
218 barrier,
219 initialize_state,
220 notifier,
221 );
222 self.shared().add_consumer_and_cursor(consumer, cursor);
223 }
224
225 fn dependent_barrier(&self) -> Arc<B>;
226}
227
228#[doc(hidden)]
229pub struct Shared<E, W>
230where
231 W: crate::wait_strategies::WaitStrategy,
232{
233 pub(crate) shutdown_at_sequence: Arc<CachePadded<AtomicI64>>,
234 pub(crate) ring_buffer: Arc<RingBuffer<E>>,
235 pub(crate) consumers: Vec<Consumer>,
236 current_consumer_cursors: Option<Vec<Arc<Cursor>>>,
237 pub(crate) notifier: W::Notifier,
238 pub(crate) wait_strategy: W,
239 pub(crate) thread_context: ThreadContext,
240}
241
242impl<E, W> Shared<E, W>
243where
244 W: crate::wait_strategies::WaitStrategy,
245{
246 fn new<F>(size: usize, event_factory: F, wait_strategy: W) -> Self
247 where
248 F: FnMut() -> E,
249 {
250 let notifier = wait_strategy.notifier();
251 let ring_buffer = Arc::new(RingBuffer::new(size, event_factory));
252 let shutdown_at_sequence = Arc::new(CachePadded::new(AtomicI64::new(NONE)));
253 let current_consumer_cursors = Some(vec![]);
254
255 Self {
256 ring_buffer,
257 notifier,
258 wait_strategy,
259 shutdown_at_sequence,
260 current_consumer_cursors,
261 consumers: vec![],
262 thread_context: ThreadContext::default(),
263 }
264 }
265
266 fn add_consumer_and_cursor(&mut self, consumer: Consumer, cursor: Arc<Cursor>) {
267 self.consumers.push(consumer);
268 self.add_cursor(cursor);
269 }
270
271 fn add_cursor(&mut self, cursor: Arc<Cursor>) {
272 self.current_consumer_cursors.as_mut().unwrap().push(cursor);
273 }
274
275 fn pin_at_core(&mut self, id: usize) {
276 cpu_has_core_else_panic(id);
277 self.thread_context.affinity = Some(CoreId { id });
278 }
279
280 fn thread_named(&mut self, name: &'static str) {
281 self.thread_context.name = Some(name.to_owned());
282 }
283}
284
285#[derive(Default)]
286pub(crate) struct ThreadContext {
287 affinity: Option<CoreId>,
288 name: Option<String>,
289 id: usize,
290}
291
292impl ThreadContext {
293 pub(crate) fn name(&mut self) -> String {
294 self.name
295 .take()
296 .or_else(|| {
297 self.id += 1;
298 Some(format!("processor-{}", self.id))
299 })
300 .unwrap()
301 }
302
303 pub(crate) fn affinity(&mut self) -> Option<CoreId> {
304 self.affinity.take()
305 }
306}