@@ -8,42 +8,45 @@ pub use crate::runtime::event_driver::yield_driver::*;
88use crate :: runtime:: graph:: Graph ;
99use crate :: runtime:: scheduler:: Scheduler ;
1010use crate :: runtime:: { Clock , CycleTime } ;
11- use ahash:: { HashSet , HashSetExt } ;
11+ use crossbeam_queue:: ArrayQueue ;
12+ use derive_builder:: Builder ;
1213use petgraph:: prelude:: NodeIndex ;
1314use std:: io;
1415use std:: sync:: Arc ;
1516use std:: time:: Duration ;
1617
17- const MINIMUM_TIMER_PRECISION : std:: time:: Duration = std:: time:: Duration :: from_millis ( 1 ) ;
18- const IO_CAPACITY : usize = 1024 ;
19- const EVENT_CAPACITY : usize = 1024 ;
18+ const MINIMUM_TIMER_PRECISION : Duration = Duration :: from_millis ( 1 ) ;
2019
2120/// A handle for waking a node from external threads or contexts.
2221///
2322/// `Notifier` provides a thread-safe way to schedule a node for execution
2423/// from outside the main event loop. Useful for integrating with external
2524/// libraries, user input, or cross-thread communication.
2625pub struct Notifier {
27- raw_events : Arc < spin :: Mutex < HashSet < NodeIndex > > > ,
26+ notifications : Arc < ArrayQueue < NodeIndex > > ,
2827 waker : Arc < mio:: Waker > ,
2928 node_index : NodeIndex ,
3029}
3130
3231impl Clone for Notifier {
3332 fn clone ( & self ) -> Self {
34- Self :: new ( self . raw_events . clone ( ) , self . waker . clone ( ) , self . node_index )
33+ Self :: new (
34+ self . notifications . clone ( ) ,
35+ self . waker . clone ( ) ,
36+ self . node_index ,
37+ )
3538 }
3639}
3740
3841impl Notifier {
3942 /// Creates a new notifier handle (internal use only).
4043 const fn new (
41- raw_events : Arc < spin :: Mutex < HashSet < NodeIndex > > > ,
44+ notifications : Arc < ArrayQueue < NodeIndex > > ,
4245 waker : Arc < mio:: Waker > ,
4346 node_index : NodeIndex ,
4447 ) -> Self {
4548 Self {
46- raw_events ,
49+ notifications ,
4750 waker,
4851 node_index,
4952 }
@@ -53,13 +56,27 @@ impl Notifier {
5356 ///
5457 /// This method is thread-safe and can be called from any thread.
5558 /// The node will be scheduled on the next polling cycle.
59+ ///
60+ /// Note: we assume that notification events will coalesce,
61+ /// so we only attempt to write to the notification queue.
5662 #[ inline( always) ]
5763 pub fn notify ( & self ) {
58- self . raw_events . lock ( ) . insert ( self . node_index ) ;
64+ self . notifications . push ( self . node_index ) . ok ( ) ;
5965 self . waker . wake ( ) . ok ( ) ;
6066 }
6167}
6268
69+ /// Driver configuration options.
70+ #[ derive( Builder ) ]
71+ pub struct EventDriverConfig {
72+ #[ builder( default = 256 ) ]
73+ pub notification_capacity : usize ,
74+ #[ builder( default = 1024 ) ]
75+ pub io_capacity : usize ,
76+ #[ builder( default = 16 ) ]
77+ pub poll_limit : usize ,
78+ }
79+
6380/// Unified event management system that coordinates all event sources.
6481///
6582/// The `EventDriver` orchestrates the three core event types in the runtime:
@@ -80,23 +97,32 @@ pub struct EventDriver {
8097 /// Processes immediate yield requests
8198 yield_driver : YieldDriver ,
8299
83- /// Tracks deduplicated raw events that have been received
84- raw_events : Arc < spin:: Mutex < HashSet < NodeIndex > > > ,
100+ /// Notification queue tracking events on node indices
101+ notifications : Arc < ArrayQueue < NodeIndex > > ,
102+
103+ /// Poll limit for pulling node indices off of
104+ /// the notifications queue
105+ poll_limit : usize ,
85106}
86107
87108impl EventDriver {
88109 /// Creates a new event driver with default I/O capacity.
89110 pub ( crate ) fn new ( ) -> Self {
90- Self :: with_capacity ( IO_CAPACITY )
111+ Self :: with_config (
112+ EventDriverConfigBuilder :: default ( )
113+ . build ( )
114+ . expect ( "expected default builder" ) ,
115+ )
91116 }
92117
93- /// Creates a new event driver with the specified I/O event capacity.
94- pub ( crate ) fn with_capacity ( capacity : usize ) -> Self {
118+ /// Creates a new event driver with the specified notification capacity.
119+ pub ( crate ) fn with_config ( cfg : EventDriverConfig ) -> Self {
95120 Self {
96- io_driver : IoDriver :: with_capacity ( capacity ) ,
121+ io_driver : IoDriver :: with_capacity ( cfg . io_capacity ) ,
97122 timer_driver : TimerDriver :: new ( ) ,
98123 yield_driver : YieldDriver :: new ( ) ,
99- raw_events : Arc :: new ( spin:: Mutex :: new ( HashSet :: with_capacity ( EVENT_CAPACITY ) ) ) ,
124+ notifications : Arc :: new ( ArrayQueue :: new ( cfg. notification_capacity ) ) ,
125+ poll_limit : cfg. poll_limit ,
100126 }
101127 }
102128
@@ -118,7 +144,11 @@ impl EventDriver {
118144 /// Creates a new `Notifier` to inform the event driver of a raw event.
119145 #[ inline( always) ]
120146 pub fn register_notifier ( & self , node_index : NodeIndex ) -> Notifier {
121- Notifier :: new ( self . raw_events . clone ( ) , self . io_driver . waker ( ) , node_index)
147+ Notifier :: new (
148+ self . notifications . clone ( ) ,
149+ self . io_driver . waker ( ) ,
150+ node_index,
151+ )
122152 }
123153
124154 /// Polls all event sources and schedules ready nodes.
@@ -140,13 +170,15 @@ impl EventDriver {
140170 timeout : Option < Duration > ,
141171 epoch : usize ,
142172 ) -> io:: Result < CycleTime > {
143- {
144- let mut raw_events = self . raw_events . lock ( ) ;
145- raw_events. drain ( ) . for_each ( |node_idx| {
146- if let Some ( depth) = graph. can_schedule ( node_idx, epoch) {
147- scheduler. schedule ( node_idx, depth) . ok ( ) ;
173+ for _ in 0 ..self . poll_limit {
174+ match self . notifications . pop ( ) {
175+ None => break ,
176+ Some ( node_idx) => {
177+ if let Some ( depth) = graph. can_schedule ( node_idx, epoch) {
178+ scheduler. schedule ( node_idx, depth) . ok ( ) ;
179+ }
148180 }
149- } ) ;
181+ }
150182 }
151183
152184 let cycle_time = clock. cycle_time ( ) ;
0 commit comments