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 ;
16
20
17
21
/// Errors related to vring epoll event handling.
18
22
#[ derive( Debug ) ]
19
- pub enum VringEpollError {
23
+ pub enum VringPollError {
20
24
/// Failed to create epoll file descriptor.
21
- EpollCreateFd ( io:: Error ) ,
25
+ PollerCreate ( io:: Error ) ,
22
26
/// Failed while waiting for events.
23
- EpollWait ( io:: Error ) ,
27
+ PollerWait ( io:: Error ) ,
24
28
/// Could not register exit event
25
29
RegisterExitEvent ( io:: Error ) ,
26
30
/// Failed to read the event from kick EventFd.
27
31
HandleEventReadKick ( io:: Error ) ,
28
32
/// Failed to handle the event from the backend.
29
33
HandleEventBackendHandling ( io:: Error ) ,
34
+ /// Failed to clone registry.
35
+ RegistryClone ( io:: Error ) ,
30
36
}
31
37
32
- impl Display for VringEpollError {
38
+ impl Display for VringPollError {
33
39
fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
34
40
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) => {
41
+ VringPollError :: PollerCreate ( e) => write ! ( f, "cannot create poller : {e}" ) ,
42
+ VringPollError :: PollerWait ( e) => write ! ( f, "failed to wait for poller event: {e}" ) ,
43
+ VringPollError :: RegisterExitEvent ( e) => write ! ( f, "cannot register exit event: {e}" ) ,
44
+ VringPollError :: HandleEventReadKick ( e) => {
39
45
write ! ( f, "cannot read vring kick event: {e}" )
40
46
}
41
- VringEpollError :: HandleEventBackendHandling ( e) => {
42
- write ! ( f, "failed to handle epoll event: {e}" )
47
+ VringPollError :: HandleEventBackendHandling ( e) => {
48
+ write ! ( f, "failed to handle poll event: {e}" )
43
49
}
50
+ VringPollError :: RegistryClone ( e) => write ! ( f, "cannot clone poller's registry: {e}" ) ,
44
51
}
45
52
}
46
53
}
47
54
48
- impl std:: error:: Error for VringEpollError { }
55
+ impl std:: error:: Error for VringPollError { }
49
56
50
57
/// Result of vring epoll operations.
51
- pub type VringEpollResult < T > = std:: result:: Result < T , VringEpollError > ;
58
+ pub type VringEpollResult < T > = std:: result:: Result < T , VringPollError > ;
59
+
60
+ pub enum EventSet {
61
+ Readable ,
62
+ Writable ,
63
+ All ,
64
+ }
65
+
66
+ impl EventSet {
67
+ fn to_interest ( & self ) -> Interest {
68
+ match self {
69
+ EventSet :: Readable => Interest :: READABLE ,
70
+ EventSet :: Writable => Interest :: WRITABLE ,
71
+ EventSet :: All => Interest :: READABLE | Interest :: WRITABLE ,
72
+ }
73
+ }
74
+ }
75
+
76
+ fn event_to_event_set ( evt : & Event ) -> Option < EventSet > {
77
+ if evt. is_readable ( ) && evt. is_writable ( ) {
78
+ return Some ( EventSet :: All ) ;
79
+ }
80
+ if evt. is_readable ( ) {
81
+ return Some ( EventSet :: Readable ) ;
82
+ }
83
+ if evt. is_writable ( ) {
84
+ return Some ( EventSet :: Writable ) ;
85
+ }
86
+ None
87
+ }
52
88
53
89
/// Epoll event handler to manage and process epoll events for registered file descriptor.
54
90
///
@@ -57,7 +93,11 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
57
93
/// - remove registered file descriptors from the epoll fd
58
94
/// - run the event loop to handle pending events on the epoll fd
59
95
pub struct VringEpollHandler < T : VhostUserBackend > {
60
- epoll : Epoll ,
96
+ poller : Mutex < Poll > ,
97
+ registry : Registry ,
98
+ // Record the registered fd.
99
+ // Because in mio, consecutive calls to register is unspecified behavior.
100
+ fd_set : Mutex < HashSet < RawFd > > ,
61
101
backend : T ,
62
102
vrings : Vec < T :: Vring > ,
63
103
thread_id : usize ,
@@ -84,22 +124,32 @@ where
84
124
vrings : Vec < T :: Vring > ,
85
125
thread_id : usize ,
86
126
) -> VringEpollResult < Self > {
87
- let epoll = Epoll :: new ( ) . map_err ( VringEpollError :: EpollCreateFd ) ?;
127
+ let poller = Poll :: new ( ) . map_err ( VringPollError :: PollerCreate ) ?;
88
128
let exit_event_fd = backend. exit_event ( thread_id) ;
129
+ let fd_set = Mutex :: new ( HashSet :: new ( ) ) ;
89
130
131
+ let registry = poller
132
+ . registry ( )
133
+ . try_clone ( )
134
+ . map_err ( VringPollError :: RegistryClone ) ?;
90
135
if let Some ( exit_event_fd) = & exit_event_fd {
91
136
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 ) ,
137
+
138
+ registry
139
+ . register (
140
+ & mut SourceFd ( & exit_event_fd. as_raw_fd ( ) ) ,
141
+ Token ( id) ,
142
+ Interest :: READABLE ,
97
143
)
98
- . map_err ( VringEpollError :: RegisterExitEvent ) ?;
144
+ . map_err ( VringPollError :: RegisterExitEvent ) ?;
145
+
146
+ fd_set. lock ( ) . unwrap ( ) . insert ( exit_event_fd. as_raw_fd ( ) ) ;
99
147
}
100
148
101
149
Ok ( VringEpollHandler {
102
- epoll,
150
+ poller : Mutex :: new ( poller) ,
151
+ registry,
152
+ fd_set,
103
153
backend,
104
154
vrings,
105
155
thread_id,
@@ -135,13 +185,31 @@ where
135
185
}
136
186
137
187
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) )
188
+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
189
+ if fd_set. contains ( & fd) {
190
+ return Err ( io:: Error :: from_raw_os_error ( libc:: EEXIST ) ) ;
191
+ }
192
+ self . registry
193
+ . register (
194
+ & mut SourceFd ( & fd) ,
195
+ Token ( data as usize ) ,
196
+ ev_type. to_interest ( ) ,
197
+ )
198
+ . map_err ( std:: io:: Error :: other) ?;
199
+ fd_set. insert ( fd) ;
200
+ Ok ( ( ) )
140
201
}
141
202
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) )
203
+ pub ( crate ) fn unregister_event ( & self , fd : RawFd , _ev_type : EventSet , _data : u64 ) -> Result < ( ) > {
204
+ let mut fd_set = self . fd_set . lock ( ) . unwrap ( ) ;
205
+ if !fd_set. contains ( & fd) {
206
+ return Err ( io:: Error :: from_raw_os_error ( libc:: ENOENT ) ) ;
207
+ }
208
+ self . registry
209
+ . deregister ( & mut SourceFd ( & fd) )
210
+ . map_err ( |e| std:: io:: Error :: other ( format ! ( "Failed to deregister fd {}: {}" , fd, e) ) ) ?;
211
+ fd_set. remove ( & fd) ;
212
+ Ok ( ( ) )
145
213
}
146
214
147
215
/// Run the event poll loop to handle all pending events on registered fds.
@@ -150,49 +218,30 @@ where
150
218
/// associated with the backend.
151
219
pub ( crate ) fn run ( & self ) -> VringEpollResult < ( ) > {
152
220
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
221
183
- let ev_type = event. data ( ) as u16 ;
222
+ let mut events = Events :: with_capacity ( EPOLL_EVENTS_LEN ) ;
223
+ ' poll: loop {
224
+ self . poller
225
+ . lock ( )
226
+ . unwrap ( )
227
+ . poll ( & mut events, None )
228
+ . map_err ( VringPollError :: PollerWait ) ?;
184
229
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;
230
+ for event in events. iter ( ) {
231
+ let token = event. token ( ) ;
232
+
233
+ if let Some ( evt_set) = event_to_event_set ( event) {
234
+ if self . handle_event ( token. 0 as u16 , evt_set) ? {
235
+ break ' poll;
236
+ }
188
237
}
189
238
}
190
239
}
191
240
192
241
Ok ( ( ) )
193
242
}
194
243
195
- fn handle_event ( & self , device_event : u16 , evset : EventSet ) -> VringEpollResult < bool > {
244
+ fn handle_event ( & self , device_event : u16 , event : EventSet ) -> VringEpollResult < bool > {
196
245
if self . exit_event_fd . is_some ( ) && device_event as usize == self . backend . num_queues ( ) {
197
246
return Ok ( true ) ;
198
247
}
@@ -201,7 +250,7 @@ where
201
250
let vring = & self . vrings [ device_event as usize ] ;
202
251
let enabled = vring
203
252
. read_kick ( )
204
- . map_err ( VringEpollError :: HandleEventReadKick ) ?;
253
+ . map_err ( VringPollError :: HandleEventReadKick ) ?;
205
254
206
255
// If the vring is not enabled, it should not be processed.
207
256
if !enabled {
@@ -210,16 +259,16 @@ where
210
259
}
211
260
212
261
self . backend
213
- . handle_event ( device_event, evset , & self . vrings , self . thread_id )
214
- . map_err ( VringEpollError :: HandleEventBackendHandling ) ?;
262
+ . handle_event ( device_event, event , & self . vrings , self . thread_id )
263
+ . map_err ( VringPollError :: HandleEventBackendHandling ) ?;
215
264
216
265
Ok ( false )
217
266
}
218
267
}
219
268
220
269
impl < T : VhostUserBackend > AsRawFd for VringEpollHandler < T > {
221
270
fn as_raw_fd ( & self ) -> RawFd {
222
- self . epoll . as_raw_fd ( )
271
+ self . poller . lock ( ) . unwrap ( ) . as_raw_fd ( )
223
272
}
224
273
}
225
274
@@ -244,29 +293,32 @@ mod tests {
244
293
245
294
let eventfd = EventFd :: new ( 0 ) . unwrap ( ) ;
246
295
handler
247
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
296
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 3 )
248
297
. unwrap ( ) ;
249
298
// Register an already registered fd.
250
299
handler
251
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
300
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 3 )
252
301
. unwrap_err ( ) ;
253
302
// Register an invalid data.
254
303
handler
255
- . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 1 )
304
+ . register_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 1 )
256
305
. unwrap_err ( ) ;
257
306
258
307
handler
259
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
308
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 3 )
260
309
. unwrap ( ) ;
261
310
// unregister an already unregistered fd.
262
311
handler
263
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 3 )
312
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 3 )
264
313
. unwrap_err ( ) ;
265
314
// unregister an invalid data.
266
315
handler
267
- . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: IN , 1 )
316
+ . unregister_listener ( eventfd. as_raw_fd ( ) , EventSet :: Readable , 1 )
268
317
. unwrap_err ( ) ;
269
318
// Check we retrieve the correct file descriptor
270
- assert_eq ! ( handler. as_raw_fd( ) , handler. epoll. as_raw_fd( ) ) ;
319
+ assert_eq ! (
320
+ handler. as_raw_fd( ) ,
321
+ handler. poller. lock( ) . unwrap( ) . as_raw_fd( )
322
+ ) ;
271
323
}
272
324
}
0 commit comments