33//
44// SPDX-License-Identifier: Apache-2.0
55
6+ use std:: collections:: HashSet ;
67use std:: fmt:: { Display , Formatter } ;
78use std:: io:: { self , Result } ;
89use std:: marker:: PhantomData ;
910use std:: os:: fd:: IntoRawFd ;
1011use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
12+ use std:: sync:: Mutex ;
1113
12- use vmm_sys_util:: epoll:: { ControlOperation , Epoll , EpollEvent , EventSet } ;
14+ use mio:: event:: Event ;
15+ use mio:: unix:: SourceFd ;
16+ use mio:: { Events , Interest , Poll , Registry , Token } ;
1317use vmm_sys_util:: event:: EventNotifier ;
1418
1519use super :: backend:: VhostUserBackend ;
1620use super :: vring:: VringT ;
1721
1822/// Errors related to vring epoll event handling.
1923#[ derive( Debug ) ]
20- pub enum VringEpollError {
24+ pub enum VringPollError {
2125 /// Failed to create epoll file descriptor.
22- EpollCreateFd ( io:: Error ) ,
26+ PollerCreate ( io:: Error ) ,
2327 /// Failed while waiting for events.
24- EpollWait ( io:: Error ) ,
28+ PollerWait ( io:: Error ) ,
2529 /// Could not register exit event
2630 RegisterExitEvent ( io:: Error ) ,
2731 /// Failed to read the event from kick EventFd.
2832 HandleEventReadKick ( io:: Error ) ,
2933 /// Failed to handle the event from the backend.
3034 HandleEventBackendHandling ( io:: Error ) ,
35+ /// Failed to clone registry.
36+ RegistryClone ( io:: Error ) ,
3137}
3238
33- impl Display for VringEpollError {
39+ impl Display for VringPollError {
3440 fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
3541 match self {
36- VringEpollError :: EpollCreateFd ( e) => write ! ( f, "cannot create epoll fd : {e}" ) ,
37- VringEpollError :: EpollWait ( e) => write ! ( f, "failed to wait for epoll event: {e}" ) ,
38- VringEpollError :: RegisterExitEvent ( e) => write ! ( f, "cannot register exit event: {e}" ) ,
39- VringEpollError :: HandleEventReadKick ( e) => {
42+ VringPollError :: PollerCreate ( e) => write ! ( f, "cannot create poller : {e}" ) ,
43+ VringPollError :: PollerWait ( e) => write ! ( f, "failed to wait for poller event: {e}" ) ,
44+ VringPollError :: RegisterExitEvent ( e) => write ! ( f, "cannot register exit event: {e}" ) ,
45+ VringPollError :: HandleEventReadKick ( e) => {
4046 write ! ( f, "cannot read vring kick event: {e}" )
4147 }
42- VringEpollError :: HandleEventBackendHandling ( e) => {
43- write ! ( f, "failed to handle epoll event: {e}" )
48+ VringPollError :: HandleEventBackendHandling ( e) => {
49+ write ! ( f, "failed to handle poll event: {e}" )
4450 }
51+ VringPollError :: RegistryClone ( e) => write ! ( f, "cannot clone poller's registry: {e}" ) ,
4552 }
4653 }
4754}
4855
49- impl std:: error:: Error for VringEpollError { }
56+ impl std:: error:: Error for VringPollError { }
5057
5158/// Result of vring epoll operations.
52- pub type VringEpollResult < T > = std:: result:: Result < T , VringEpollError > ;
59+ pub type VringEpollResult < T > = std:: result:: Result < T , VringPollError > ;
60+
61+ #[ derive( Debug , Clone , Copy ) ]
62+ pub enum EventSet {
63+ Readable ,
64+ Writable ,
65+ All ,
66+ }
67+
68+ impl EventSet {
69+ fn to_interest ( self ) -> Interest {
70+ match self {
71+ EventSet :: Readable => Interest :: READABLE ,
72+ EventSet :: Writable => Interest :: WRITABLE ,
73+ EventSet :: All => Interest :: READABLE | Interest :: WRITABLE ,
74+ }
75+ }
76+ }
77+
78+ fn event_to_event_set ( evt : & Event ) -> Option < EventSet > {
79+ if evt. is_readable ( ) && evt. is_writable ( ) {
80+ return Some ( EventSet :: All ) ;
81+ }
82+ if evt. is_readable ( ) {
83+ return Some ( EventSet :: Readable ) ;
84+ }
85+ if evt. is_writable ( ) {
86+ return Some ( EventSet :: Writable ) ;
87+ }
88+ None
89+ }
5390
5491/// Epoll event handler to manage and process epoll events for registered file descriptor.
5592///
@@ -58,7 +95,11 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
5895/// - remove registered file descriptors from the epoll fd
5996/// - run the event loop to handle pending events on the epoll fd
6097pub struct VringEpollHandler < T : VhostUserBackend > {
61- epoll : Epoll ,
98+ poller : Mutex < Poll > ,
99+ registry : Registry ,
100+ // Record the registered fd.
101+ // Because in mio, consecutive calls to register is unspecified behavior.
102+ fd_set : Mutex < HashSet < RawFd > > ,
62103 backend : T ,
63104 vrings : Vec < T :: Vring > ,
64105 thread_id : usize ,
@@ -85,25 +126,35 @@ where
85126 vrings : Vec < T :: Vring > ,
86127 thread_id : usize ,
87128 ) -> VringEpollResult < Self > {
88- let epoll = Epoll :: new ( ) . map_err ( VringEpollError :: EpollCreateFd ) ?;
129+ let poller = Poll :: new ( ) . map_err ( VringPollError :: PollerCreate ) ?;
89130 let exit_event_fd = backend. exit_event ( thread_id) ;
131+ let fd_set = Mutex :: new ( HashSet :: new ( ) ) ;
90132
133+ let registry = poller
134+ . registry ( )
135+ . try_clone ( )
136+ . map_err ( VringPollError :: RegistryClone ) ?;
91137 let exit_event_fd = if let Some ( ( consumer, notifier) ) = exit_event_fd {
92138 let id = backend. num_queues ( ) ;
93- epoll
94- . ctl (
95- ControlOperation :: Add ,
96- consumer. into_raw_fd ( ) ,
97- EpollEvent :: new ( EventSet :: IN , id as u64 ) ,
139+
140+ registry
141+ . register (
142+ & mut SourceFd ( & consumer. as_raw_fd ( ) ) ,
143+ Token ( id) ,
144+ Interest :: READABLE ,
98145 )
99- . map_err ( VringEpollError :: RegisterExitEvent ) ?;
146+ . map_err ( VringPollError :: RegisterExitEvent ) ?;
147+
148+ fd_set. lock ( ) . unwrap ( ) . insert ( consumer. into_raw_fd ( ) ) ;
100149 Some ( notifier)
101150 } else {
102151 None
103152 } ;
104153
105154 Ok ( VringEpollHandler {
106- epoll,
155+ poller : Mutex :: new ( poller) ,
156+ registry,
157+ fd_set,
107158 backend,
108159 vrings,
109160 thread_id,
@@ -129,29 +180,37 @@ where
129180 ///
130181 /// If the event is triggered after this function has been called, the event will be silently
131182 /// dropped.
132- pub fn unregister_listener ( & self , fd : RawFd , ev_type : EventSet , data : usize ) -> Result < ( ) > {
183+ pub fn unregister_listener ( & self , fd : RawFd , data : usize ) -> Result < ( ) > {
133184 // `data` range [0...num_queues] is reserved for queues and exit event.
134185 if data <= self . backend . num_queues ( ) {
135186 Err ( io:: Error :: from_raw_os_error ( libc:: EINVAL ) )
136187 } else {
137- self . unregister_event ( fd, ev_type , data )
188+ self . unregister_event ( fd)
138189 }
139190 }
140191
141192 pub ( crate ) fn register_event ( & self , fd : RawFd , ev_type : EventSet , data : usize ) -> Result < ( ) > {
142- self . epoll . ctl (
143- ControlOperation :: Add ,
144- fd,
145- EpollEvent :: new ( ev_type, data as u64 ) ,
146- )
193+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
194+ if fd_set. contains ( & fd) {
195+ return Err ( io:: Error :: from_raw_os_error ( libc:: EEXIST ) ) ;
196+ }
197+ self . registry
198+ . register ( & mut SourceFd ( & fd) , Token ( data) , ev_type. to_interest ( ) )
199+ . map_err ( std:: io:: Error :: other) ?;
200+ fd_set. insert ( fd) ;
201+ Ok ( ( ) )
147202 }
148203
149- pub ( crate ) fn unregister_event ( & self , fd : RawFd , ev_type : EventSet , data : usize ) -> Result < ( ) > {
150- self . epoll . ctl (
151- ControlOperation :: Delete ,
152- fd,
153- EpollEvent :: new ( ev_type, data as u64 ) ,
154- )
204+ pub ( crate ) fn unregister_event ( & self , fd : RawFd ) -> Result < ( ) > {
205+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
206+ if !fd_set. contains ( & fd) {
207+ return Err ( io:: Error :: from_raw_os_error ( libc:: ENOENT ) ) ;
208+ }
209+ self . registry
210+ . deregister ( & mut SourceFd ( & fd) )
211+ . map_err ( |e| std:: io:: Error :: other ( format ! ( "Failed to deregister fd {fd}: {e}" ) ) ) ?;
212+ fd_set. remove ( & fd) ;
213+ Ok ( ( ) )
155214 }
156215
157216 /// Run the event poll loop to handle all pending events on registered fds.
@@ -160,41 +219,22 @@ where
160219 /// associated with the backend.
161220 pub ( crate ) fn run ( & self ) -> VringEpollResult < ( ) > {
162221 const EPOLL_EVENTS_LEN : usize = 100 ;
163- let mut events = vec ! [ EpollEvent :: new( EventSet :: empty( ) , 0 ) ; EPOLL_EVENTS_LEN ] ;
164-
165- ' epoll: loop {
166- let num_events = match self . epoll . wait ( -1 , & mut events[ ..] ) {
167- Ok ( res) => res,
168- Err ( e) => {
169- if e. kind ( ) == io:: ErrorKind :: Interrupted {
170- // It's well defined from the epoll_wait() syscall
171- // documentation that the epoll loop can be interrupted
172- // before any of the requested events occurred or the
173- // timeout expired. In both those cases, epoll_wait()
174- // returns an error of type EINTR, but this should not
175- // be considered as a regular error. Instead it is more
176- // appropriate to retry, by calling into epoll_wait().
177- continue ;
178- }
179- return Err ( VringEpollError :: EpollWait ( e) ) ;
180- }
181- } ;
182-
183- for event in events. iter ( ) . take ( num_events) {
184- let evset = match EventSet :: from_bits ( event. events ) {
185- Some ( evset) => evset,
186- None => {
187- let evbits = event. events ;
188- println ! ( "epoll: ignoring unknown event set: 0x{evbits:x}" ) ;
189- continue ;
190- }
191- } ;
192222
193- let ev_type = event. data ( ) ;
223+ let mut events = Events :: with_capacity ( EPOLL_EVENTS_LEN ) ;
224+ ' poll: loop {
225+ self . poller
226+ . lock ( )
227+ . unwrap ( )
228+ . poll ( & mut events, None )
229+ . map_err ( VringPollError :: PollerWait ) ?;
194230
195- // handle_event() returns true if an event is received from the exit event fd.
196- if self . handle_event ( ev_type as usize , evset) ? {
197- break ' epoll;
231+ for event in & events {
232+ let token = event. token ( ) ;
233+
234+ if let Some ( evt_set) = event_to_event_set ( event) {
235+ if self . handle_event ( token. 0 , evt_set) ? {
236+ break ' poll;
237+ }
198238 }
199239 }
200240 }
@@ -211,7 +251,7 @@ where
211251 let vring = & self . vrings [ device_event] ;
212252 let enabled = vring
213253 . read_kick ( )
214- . map_err ( VringEpollError :: HandleEventReadKick ) ?;
254+ . map_err ( VringPollError :: HandleEventReadKick ) ?;
215255
216256 // If the vring is not enabled, it should not be processed.
217257 if !enabled {
@@ -221,15 +261,15 @@ where
221261
222262 self . backend
223263 . handle_event ( device_event, evset, & self . vrings , self . thread_id )
224- . map_err ( VringEpollError :: HandleEventBackendHandling ) ?;
264+ . map_err ( VringPollError :: HandleEventBackendHandling ) ?;
225265
226266 Ok ( false )
227267 }
228268}
229269
230270impl < T : VhostUserBackend > AsRawFd for VringEpollHandler < T > {
231271 fn as_raw_fd ( & self ) -> RawFd {
232- self . epoll . as_raw_fd ( )
272+ self . poller . lock ( ) . unwrap ( ) . as_raw_fd ( )
233273 }
234274}
235275
@@ -254,29 +294,32 @@ mod tests {
254294
255295 let ( consumer, _notifier) = new_event_consumer_and_notifier ( EventFlag :: empty ( ) ) . unwrap ( ) ;
256296 handler
257- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
297+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 3 )
258298 . unwrap ( ) ;
259299 // Register an already registered fd.
260300 handler
261- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
301+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 3 )
262302 . unwrap_err ( ) ;
263303 // Register an invalid data.
264304 handler
265- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 1 )
305+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 1 )
266306 . unwrap_err ( ) ;
267307
268308 handler
269- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
309+ . unregister_listener ( consumer. as_raw_fd ( ) , 3 )
270310 . unwrap ( ) ;
271311 // unregister an already unregistered fd.
272312 handler
273- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
313+ . unregister_listener ( consumer. as_raw_fd ( ) , 3 )
274314 . unwrap_err ( ) ;
275315 // unregister an invalid data.
276316 handler
277- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 1 )
317+ . unregister_listener ( consumer. as_raw_fd ( ) , 1 )
278318 . unwrap_err ( ) ;
279319 // Check we retrieve the correct file descriptor
280- assert_eq ! ( handler. as_raw_fd( ) , handler. epoll. as_raw_fd( ) ) ;
320+ assert_eq ! (
321+ handler. as_raw_fd( ) ,
322+ handler. poller. lock( ) . unwrap( ) . as_raw_fd( )
323+ ) ;
281324 }
282325}
0 commit comments