3
3
//
4
4
// SPDX-License-Identifier: Apache-2.0
5
5
6
+ use std:: collections:: HashSet ;
6
7
use std:: fmt:: { Display , Formatter } ;
7
8
use std:: io:: { self , Result } ;
8
9
use std:: marker:: PhantomData ;
9
10
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
11
+ use std:: sync:: Mutex ;
10
12
11
- use vmm_sys_util:: epoll:: { ControlOperation , Epoll , EpollEvent , EventSet } ;
13
+ use mio:: event:: Event ;
14
+ use mio:: unix:: SourceFd ;
15
+ use mio:: { Events , Interest , Poll , Registry , Token } ;
12
16
use vmm_sys_util:: eventfd:: EventFd ;
13
17
14
18
use super :: backend:: VhostUserBackend ;
15
19
use super :: vring:: VringT ;
20
+ use bitflags:: bitflags;
16
21
17
22
/// Errors related to vring epoll event handling.
18
23
#[ derive( Debug ) ]
19
- pub enum VringEpollError {
24
+ pub enum VringPollError {
20
25
/// Failed to create epoll file descriptor.
21
- EpollCreateFd ( io:: Error ) ,
26
+ PollerCreate ( io:: Error ) ,
22
27
/// Failed while waiting for events.
23
- EpollWait ( io:: Error ) ,
28
+ PollerWait ( io:: Error ) ,
24
29
/// Could not register exit event
25
30
RegisterExitEvent ( io:: Error ) ,
26
31
/// Failed to read the event from kick EventFd.
27
32
HandleEventReadKick ( io:: Error ) ,
28
33
/// Failed to handle the event from the backend.
29
34
HandleEventBackendHandling ( io:: Error ) ,
35
+ /// Failed to clone registry.
36
+ RegistryClone ( io:: Error ) ,
30
37
}
31
38
32
- impl Display for VringEpollError {
39
+ impl Display for VringPollError {
33
40
fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
34
41
match self {
35
- VringEpollError :: EpollCreateFd ( e) => write ! ( f, "cannot create epoll fd : {e}" ) ,
36
- VringEpollError :: EpollWait ( e) => write ! ( f, "failed to wait for epoll event: {e}" ) ,
37
- VringEpollError :: RegisterExitEvent ( e) => write ! ( f, "cannot register exit event: {e}" ) ,
38
- 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) => {
39
46
write ! ( f, "cannot read vring kick event: {e}" )
40
47
}
41
- VringEpollError :: HandleEventBackendHandling ( e) => {
42
- write ! ( f, "failed to handle epoll event: {e}" )
48
+ VringPollError :: HandleEventBackendHandling ( e) => {
49
+ write ! ( f, "failed to handle poll event: {e}" )
43
50
}
51
+ VringPollError :: RegistryClone ( e) => write ! ( f, "cannot clone poller's registry: {e}" ) ,
44
52
}
45
53
}
46
54
}
47
55
48
- impl std:: error:: Error for VringEpollError { }
56
+ impl std:: error:: Error for VringPollError { }
49
57
50
58
/// Result of vring epoll operations.
51
- pub type VringEpollResult < T > = std:: result:: Result < T , VringEpollError > ;
59
+ pub type VringEpollResult < T > = std:: result:: Result < T , VringPollError > ;
60
+
61
+ bitflags ! {
62
+ #[ derive( Debug , PartialEq , PartialOrd ) ]
63
+ pub struct EventSet : u32 {
64
+ const READABLE = 1u32 ;
65
+ const WRITABLE = 2u32 ;
66
+ }
67
+ }
68
+
69
+ impl From < EventSet > for Interest {
70
+ fn from ( value : EventSet ) -> Self {
71
+ let mut interest = None ;
72
+ if value == EventSet :: READABLE {
73
+ interest = interest
74
+ . map ( |interest| Interest :: READABLE | interest)
75
+ . or ( Some ( Interest :: READABLE ) ) ;
76
+ }
77
+ if value == EventSet :: WRITABLE {
78
+ interest = interest
79
+ . map ( |interest| Interest :: WRITABLE | interest)
80
+ . or ( Some ( Interest :: WRITABLE ) ) ;
81
+ }
82
+ interest. expect ( "Unknown EventSet" )
83
+ }
84
+ }
85
+
86
+ impl From < & Event > for EventSet {
87
+ fn from ( value : & Event ) -> Self {
88
+ let mut event_set = EventSet :: empty ( ) ;
89
+ if value. is_readable ( ) {
90
+ event_set |= EventSet :: READABLE ;
91
+ }
92
+ if value. is_writable ( ) {
93
+ event_set |= EventSet :: WRITABLE ;
94
+ }
95
+ event_set
96
+ }
97
+ }
52
98
53
99
/// Epoll event handler to manage and process epoll events for registered file descriptor.
54
100
///
@@ -57,7 +103,11 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
57
103
/// - remove registered file descriptors from the epoll fd
58
104
/// - run the event loop to handle pending events on the epoll fd
59
105
pub struct VringEpollHandler < T : VhostUserBackend > {
60
- epoll : Epoll ,
106
+ poller : Mutex < Poll > ,
107
+ registry : Registry ,
108
+ // Record the registered fd.
109
+ // Because in mio, consecutive calls to register is unspecified behavior.
110
+ fd_set : Mutex < HashSet < RawFd > > ,
61
111
backend : T ,
62
112
vrings : Vec < T :: Vring > ,
63
113
thread_id : usize ,
@@ -84,22 +134,32 @@ where
84
134
vrings : Vec < T :: Vring > ,
85
135
thread_id : usize ,
86
136
) -> VringEpollResult < Self > {
87
- let epoll = Epoll :: new ( ) . map_err ( VringEpollError :: EpollCreateFd ) ?;
137
+ let poller = Poll :: new ( ) . map_err ( VringPollError :: PollerCreate ) ?;
88
138
let exit_event_fd = backend. exit_event ( thread_id) ;
139
+ let fd_set = Mutex :: new ( HashSet :: new ( ) ) ;
89
140
141
+ let registry = poller
142
+ . registry ( )
143
+ . try_clone ( )
144
+ . map_err ( VringPollError :: RegistryClone ) ?;
90
145
if let Some ( exit_event_fd) = & exit_event_fd {
91
146
let id = backend. num_queues ( ) ;
92
- epoll
93
- . ctl (
94
- ControlOperation :: Add ,
95
- exit_event_fd. as_raw_fd ( ) ,
96
- EpollEvent :: new ( EventSet :: IN , id as u64 ) ,
147
+
148
+ registry
149
+ . register (
150
+ & mut SourceFd ( & exit_event_fd. as_raw_fd ( ) ) ,
151
+ Token ( id) ,
152
+ Interest :: READABLE ,
97
153
)
98
- . map_err ( VringEpollError :: RegisterExitEvent ) ?;
154
+ . map_err ( VringPollError :: RegisterExitEvent ) ?;
155
+
156
+ fd_set. lock ( ) . unwrap ( ) . insert ( exit_event_fd. as_raw_fd ( ) ) ;
99
157
}
100
158
101
159
Ok ( VringEpollHandler {
102
- epoll,
160
+ poller : Mutex :: new ( poller) ,
161
+ registry,
162
+ fd_set,
103
163
backend,
104
164
vrings,
105
165
thread_id,
@@ -135,13 +195,27 @@ where
135
195
}
136
196
137
197
pub ( crate ) fn register_event ( & self , fd : RawFd , ev_type : EventSet , data : u64 ) -> Result < ( ) > {
138
- self . epoll
139
- . ctl ( ControlOperation :: Add , fd, EpollEvent :: new ( ev_type, data) )
198
+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
199
+ if fd_set. contains ( & fd) {
200
+ return Err ( io:: Error :: from_raw_os_error ( libc:: EEXIST ) ) ;
201
+ }
202
+ self . registry
203
+ . register ( & mut SourceFd ( & fd) , Token ( data as usize ) , ev_type. into ( ) )
204
+ . map_err ( std:: io:: Error :: other) ?;
205
+ fd_set. insert ( fd) ;
206
+ Ok ( ( ) )
140
207
}
141
208
142
- pub ( crate ) fn unregister_event ( & self , fd : RawFd , ev_type : EventSet , data : u64 ) -> Result < ( ) > {
143
- self . epoll
144
- . ctl ( ControlOperation :: Delete , fd, EpollEvent :: new ( ev_type, data) )
209
+ pub ( crate ) fn unregister_event ( & self , fd : RawFd , _ev_type : EventSet , _data : u64 ) -> Result < ( ) > {
210
+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
211
+ if !fd_set. contains ( & fd) {
212
+ return Err ( io:: Error :: from_raw_os_error ( libc:: ENOENT ) ) ;
213
+ }
214
+ self . registry
215
+ . deregister ( & mut SourceFd ( & fd) )
216
+ . map_err ( |e| std:: io:: Error :: other ( format ! ( "Failed to deregister fd {}: {}" , fd, e) ) ) ?;
217
+ fd_set. remove ( & fd) ;
218
+ Ok ( ( ) )
145
219
}
146
220
147
221
/// Run the event poll loop to handle all pending events on registered fds.
@@ -150,49 +224,28 @@ where
150
224
/// associated with the backend.
151
225
pub ( crate ) fn run ( & self ) -> VringEpollResult < ( ) > {
152
226
const EPOLL_EVENTS_LEN : usize = 100 ;
153
- let mut events = vec ! [ EpollEvent :: new( EventSet :: empty( ) , 0 ) ; EPOLL_EVENTS_LEN ] ;
154
-
155
- ' epoll: loop {
156
- let num_events = match self . epoll . wait ( -1 , & mut events[ ..] ) {
157
- Ok ( res) => res,
158
- Err ( e) => {
159
- if e. kind ( ) == io:: ErrorKind :: Interrupted {
160
- // It's well defined from the epoll_wait() syscall
161
- // documentation that the epoll loop can be interrupted
162
- // before any of the requested events occurred or the
163
- // timeout expired. In both those cases, epoll_wait()
164
- // returns an error of type EINTR, but this should not
165
- // be considered as a regular error. Instead it is more
166
- // appropriate to retry, by calling into epoll_wait().
167
- continue ;
168
- }
169
- return Err ( VringEpollError :: EpollWait ( e) ) ;
170
- }
171
- } ;
172
-
173
- for event in events. iter ( ) . take ( num_events) {
174
- let evset = match EventSet :: from_bits ( event. events ) {
175
- Some ( evset) => evset,
176
- None => {
177
- let evbits = event. events ;
178
- println ! ( "epoll: ignoring unknown event set: 0x{evbits:x}" ) ;
179
- continue ;
180
- }
181
- } ;
182
-
183
- let ev_type = event. data ( ) as u16 ;
184
-
185
- // handle_event() returns true if an event is received from the exit event fd.
186
- if self . handle_event ( ev_type, evset) ? {
187
- break ' epoll;
227
+
228
+ let mut events = Events :: with_capacity ( EPOLL_EVENTS_LEN ) ;
229
+ ' poll: loop {
230
+ self . poller
231
+ . lock ( )
232
+ . unwrap ( )
233
+ . poll ( & mut events, None )
234
+ . map_err ( VringPollError :: PollerWait ) ?;
235
+
236
+ for event in events. iter ( ) {
237
+ let token = event. token ( ) ;
238
+
239
+ if self . handle_event ( token. 0 as u16 , event. into ( ) ) ? {
240
+ break ' poll;
188
241
}
189
242
}
190
243
}
191
244
192
245
Ok ( ( ) )
193
246
}
194
247
195
- fn handle_event ( & self , device_event : u16 , evset : EventSet ) -> VringEpollResult < bool > {
248
+ fn handle_event ( & self , device_event : u16 , event : EventSet ) -> VringEpollResult < bool > {
196
249
if self . exit_event_fd . is_some ( ) && device_event as usize == self . backend . num_queues ( ) {
197
250
return Ok ( true ) ;
198
251
}
@@ -201,7 +254,7 @@ where
201
254
let vring = & self . vrings [ device_event as usize ] ;
202
255
let enabled = vring
203
256
. read_kick ( )
204
- . map_err ( VringEpollError :: HandleEventReadKick ) ?;
257
+ . map_err ( VringPollError :: HandleEventReadKick ) ?;
205
258
206
259
// If the vring is not enabled, it should not be processed.
207
260
if !enabled {
@@ -210,16 +263,16 @@ where
210
263
}
211
264
212
265
self . backend
213
- . handle_event ( device_event, evset , & self . vrings , self . thread_id )
214
- . map_err ( VringEpollError :: HandleEventBackendHandling ) ?;
266
+ . handle_event ( device_event, event , & self . vrings , self . thread_id )
267
+ . map_err ( VringPollError :: HandleEventBackendHandling ) ?;
215
268
216
269
Ok ( false )
217
270
}
218
271
}
219
272
220
273
impl < T : VhostUserBackend > AsRawFd for VringEpollHandler < T > {
221
274
fn as_raw_fd ( & self ) -> RawFd {
222
- self . epoll . as_raw_fd ( )
275
+ self . poller . lock ( ) . unwrap ( ) . as_raw_fd ( )
223
276
}
224
277
}
225
278
@@ -244,29 +297,32 @@ mod tests {
244
297
245
298
let eventfd = EventFd :: new ( 0 ) . unwrap ( ) ;
246
299
handler
247
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
300
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 3 )
248
301
. unwrap ( ) ;
249
302
// Register an already registered fd.
250
303
handler
251
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
304
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 3 )
252
305
. unwrap_err ( ) ;
253
306
// Register an invalid data.
254
307
handler
255
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 1 )
308
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 1 )
256
309
. unwrap_err ( ) ;
257
310
258
311
handler
259
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
312
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 3 )
260
313
. unwrap ( ) ;
261
314
// unregister an already unregistered fd.
262
315
handler
263
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
316
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 3 )
264
317
. unwrap_err ( ) ;
265
318
// unregister an invalid data.
266
319
handler
267
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 1 )
320
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: READABLE , 1 )
268
321
. unwrap_err ( ) ;
269
322
// Check we retrieve the correct file descriptor
270
- assert_eq ! ( handler. as_raw_fd( ) , handler. epoll. as_raw_fd( ) ) ;
323
+ assert_eq ! (
324
+ handler. as_raw_fd( ) ,
325
+ handler. poller. lock( ) . unwrap( ) . as_raw_fd( )
326
+ ) ;
271
327
}
272
328
}
0 commit comments