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:: fd:: IntoRawFd ;
10
11
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
12
+ use std:: sync:: Mutex ;
11
13
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 } ;
13
17
use vmm_sys_util:: event:: EventNotifier ;
14
18
15
19
use super :: backend:: VhostUserBackend ;
16
20
use super :: vring:: VringT ;
17
21
18
22
/// Errors related to vring epoll event handling.
19
23
#[ derive( Debug ) ]
20
- pub enum VringEpollError {
24
+ pub enum VringPollError {
21
25
/// Failed to create epoll file descriptor.
22
- EpollCreateFd ( io:: Error ) ,
26
+ PollerCreate ( io:: Error ) ,
23
27
/// Failed while waiting for events.
24
- EpollWait ( io:: Error ) ,
28
+ PollerWait ( io:: Error ) ,
25
29
/// Could not register exit event
26
30
RegisterExitEvent ( io:: Error ) ,
27
31
/// Failed to read the event from kick EventFd.
28
32
HandleEventReadKick ( io:: Error ) ,
29
33
/// Failed to handle the event from the backend.
30
34
HandleEventBackendHandling ( io:: Error ) ,
35
+ /// Failed to clone registry.
36
+ RegistryClone ( io:: Error ) ,
31
37
}
32
38
33
- impl Display for VringEpollError {
39
+ impl Display for VringPollError {
34
40
fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
35
41
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) => {
40
46
write ! ( f, "cannot read vring kick event: {e}" )
41
47
}
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}" )
44
50
}
51
+ VringPollError :: RegistryClone ( e) => write ! ( f, "cannot clone poller's registry: {e}" ) ,
45
52
}
46
53
}
47
54
}
48
55
49
- impl std:: error:: Error for VringEpollError { }
56
+ impl std:: error:: Error for VringPollError { }
50
57
51
58
/// 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
+ }
53
90
54
91
/// Epoll event handler to manage and process epoll events for registered file descriptor.
55
92
///
@@ -58,7 +95,11 @@ pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
58
95
/// - remove registered file descriptors from the epoll fd
59
96
/// - run the event loop to handle pending events on the epoll fd
60
97
pub 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 > > ,
62
103
backend : T ,
63
104
vrings : Vec < T :: Vring > ,
64
105
thread_id : usize ,
@@ -85,25 +126,35 @@ where
85
126
vrings : Vec < T :: Vring > ,
86
127
thread_id : usize ,
87
128
) -> VringEpollResult < Self > {
88
- let epoll = Epoll :: new ( ) . map_err ( VringEpollError :: EpollCreateFd ) ?;
129
+ let poller = Poll :: new ( ) . map_err ( VringPollError :: PollerCreate ) ?;
89
130
let exit_event_fd = backend. exit_event ( thread_id) ;
131
+ let fd_set = Mutex :: new ( HashSet :: new ( ) ) ;
90
132
133
+ let registry = poller
134
+ . registry ( )
135
+ . try_clone ( )
136
+ . map_err ( VringPollError :: RegistryClone ) ?;
91
137
let exit_event_fd = if let Some ( ( consumer, notifier) ) = exit_event_fd {
92
138
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 ,
98
145
)
99
- . map_err ( VringEpollError :: RegisterExitEvent ) ?;
146
+ . map_err ( VringPollError :: RegisterExitEvent ) ?;
147
+
148
+ fd_set. lock ( ) . unwrap ( ) . insert ( consumer. into_raw_fd ( ) ) ;
100
149
Some ( notifier)
101
150
} else {
102
151
None
103
152
} ;
104
153
105
154
Ok ( VringEpollHandler {
106
- epoll,
155
+ poller : Mutex :: new ( poller) ,
156
+ registry,
157
+ fd_set,
107
158
backend,
108
159
vrings,
109
160
thread_id,
@@ -129,29 +180,37 @@ where
129
180
///
130
181
/// If the event is triggered after this function has been called, the event will be silently
131
182
/// 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 < ( ) > {
133
184
// `data` range [0...num_queues] is reserved for queues and exit event.
134
185
if data <= self . backend . num_queues ( ) {
135
186
Err ( io:: Error :: from_raw_os_error ( libc:: EINVAL ) )
136
187
} else {
137
- self . unregister_event ( fd, ev_type , data )
188
+ self . unregister_event ( fd)
138
189
}
139
190
}
140
191
141
192
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 ( ( ) )
147
202
}
148
203
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 ( ( ) )
155
214
}
156
215
157
216
/// Run the event poll loop to handle all pending events on registered fds.
@@ -160,41 +219,22 @@ where
160
219
/// associated with the backend.
161
220
pub ( crate ) fn run ( & self ) -> VringEpollResult < ( ) > {
162
221
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
- } ;
192
222
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 ) ?;
194
230
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
+ }
198
238
}
199
239
}
200
240
}
@@ -211,7 +251,7 @@ where
211
251
let vring = & self . vrings [ device_event] ;
212
252
let enabled = vring
213
253
. read_kick ( )
214
- . map_err ( VringEpollError :: HandleEventReadKick ) ?;
254
+ . map_err ( VringPollError :: HandleEventReadKick ) ?;
215
255
216
256
// If the vring is not enabled, it should not be processed.
217
257
if !enabled {
@@ -221,15 +261,15 @@ where
221
261
222
262
self . backend
223
263
. handle_event ( device_event, evset, & self . vrings , self . thread_id )
224
- . map_err ( VringEpollError :: HandleEventBackendHandling ) ?;
264
+ . map_err ( VringPollError :: HandleEventBackendHandling ) ?;
225
265
226
266
Ok ( false )
227
267
}
228
268
}
229
269
230
270
impl < T : VhostUserBackend > AsRawFd for VringEpollHandler < T > {
231
271
fn as_raw_fd ( & self ) -> RawFd {
232
- self . epoll . as_raw_fd ( )
272
+ self . poller . lock ( ) . unwrap ( ) . as_raw_fd ( )
233
273
}
234
274
}
235
275
@@ -254,29 +294,32 @@ mod tests {
254
294
255
295
let ( consumer, _notifier) = new_event_consumer_and_notifier ( EventFlag :: empty ( ) ) . unwrap ( ) ;
256
296
handler
257
- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
297
+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 3 )
258
298
. unwrap ( ) ;
259
299
// Register an already registered fd.
260
300
handler
261
- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
301
+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 3 )
262
302
. unwrap_err ( ) ;
263
303
// Register an invalid data.
264
304
handler
265
- . register_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 1 )
305
+ . register_listener ( consumer. as_raw_fd ( ) , EventSet :: Readable , 1 )
266
306
. unwrap_err ( ) ;
267
307
268
308
handler
269
- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
309
+ . unregister_listener ( consumer. as_raw_fd ( ) , 3 )
270
310
. unwrap ( ) ;
271
311
// unregister an already unregistered fd.
272
312
handler
273
- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 3 )
313
+ . unregister_listener ( consumer. as_raw_fd ( ) , 3 )
274
314
. unwrap_err ( ) ;
275
315
// unregister an invalid data.
276
316
handler
277
- . unregister_listener ( consumer. as_raw_fd ( ) , EventSet :: IN , 1 )
317
+ . unregister_listener ( consumer. as_raw_fd ( ) , 1 )
278
318
. unwrap_err ( ) ;
279
319
// 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
+ ) ;
281
324
}
282
325
}
0 commit comments