1use linux_api::epoll::EpollEvents;
2
3use crate::host::descriptor::listener::StateListenHandle;
4use crate::host::descriptor::{FileSignals, FileState};
5
6pub(super) struct Entry {
10 priority: Option<u64>,
12 interest: EpollEvents,
14 data: u64,
16 listener_handle: Option<StateListenHandle>,
18 state: FileState,
20 collected: FileState,
23 is_legacy: bool,
25}
26
27impl Entry {
28 pub fn new(interest: EpollEvents, data: u64, state: FileState) -> Self {
29 Self {
30 priority: None,
31 interest,
32 data,
33 listener_handle: None,
34 state,
35 collected: FileState::empty(),
36 is_legacy: false,
37 }
38 }
39
40 pub fn set_legacy(&mut self) {
42 self.is_legacy = true;
43 }
44
45 pub fn modify(&mut self, interest: EpollEvents, data: u64, state: FileState) {
52 log::trace!("Reset old state {:?}, new state {:?}", self.state, state);
53 self.interest = interest;
54 self.data = data;
55 self.state = state;
56 self.collected = FileState::empty();
57 }
58
59 pub fn set_priority(&mut self, priority: Option<u64>) {
60 self.priority = priority;
61 }
62
63 pub fn priority(&self) -> Option<u64> {
64 self.priority
65 }
66
67 pub fn notify(&mut self, new_state: FileState, changed: FileState, signals: FileSignals) {
68 log::trace!(
69 "Notify old state {:?}, new state {:?}, changed {:?}, signals {:?}",
70 self.state,
71 new_state,
72 changed,
73 signals,
74 );
75 self.state = new_state;
76 self.collected.remove(changed);
77
78 if signals.contains(FileSignals::READ_BUFFER_GREW) {
80 debug_assert!(self.interest.intersects(EpollEvents::EPOLLET));
82
83 if new_state.contains(FileState::READABLE) {
85 self.collected.remove(FileState::READABLE);
86 } else {
87 warn_once_then_debug!("Epoll received READ_BUFFER_GREW but state is not READABLE");
90 }
91 }
92 }
93
94 pub fn get_listener_state(&self) -> FileState {
95 if self.is_legacy {
97 return FileState::all();
98 }
99
100 Self::state_from_events(self.interest).union(FileState::CLOSED)
102 }
103
104 pub fn get_listener_signals(&self) -> FileSignals {
105 let mut signals = FileSignals::empty();
106
107 if self.interest.intersects(EpollEvents::EPOLLET) {
108 signals.insert(FileSignals::READ_BUFFER_GREW);
109 }
110
111 signals
112 }
113
114 pub fn set_listener_handle(&mut self, handle: Option<StateListenHandle>) {
115 self.listener_handle = handle;
116 }
117
118 pub fn has_ready_events(&self) -> bool {
119 if self.is_legacy {
121 if self.state.contains(FileState::CLOSED) {
122 return false;
123 } else if self.state.contains(FileState::ACTIVE) {
124 return !self.get_ready_events().is_empty();
125 } else {
126 return false;
127 }
128 }
129
130 !self.state.contains(FileState::CLOSED) && !self.get_ready_events().is_empty()
131 }
132
133 pub fn collect_ready_events(&mut self) -> Option<(EpollEvents, u64)> {
134 let events = self.get_ready_events();
135
136 if events.is_empty() {
137 return None;
138 }
139
140 self.collected.insert(Self::state_from_events(events));
141
142 if self.interest.contains(EpollEvents::EPOLLONESHOT) {
143 self.interest.remove(events)
144 }
145
146 log::trace!(
147 "Collected ready events {events:?} interest {:?} state {:?}",
148 self.interest,
149 self.state
150 );
151
152 Some((events, self.data))
153 }
154
155 fn get_ready_events(&self) -> EpollEvents {
156 let events = Self::events_from_state(self.get_ready_state());
157 self.interest.intersection(events)
158 }
159
160 fn get_ready_state(&self) -> FileState {
161 if self.interest.contains(EpollEvents::EPOLLET) {
162 self.state.difference(self.collected)
164 } else {
165 self.state
167 }
168 }
169
170 fn events_from_state(state: FileState) -> EpollEvents {
171 let mut events = EpollEvents::empty();
172
173 if state.intersects(FileState::READABLE) {
174 events.insert(EpollEvents::EPOLLIN);
175 }
176 if state.intersects(FileState::WRITABLE) {
177 events.insert(EpollEvents::EPOLLOUT);
178 }
179
180 events
181 }
182
183 fn state_from_events(events: EpollEvents) -> FileState {
184 let mut state = FileState::empty();
185
186 if events.intersects(EpollEvents::EPOLLIN) {
187 state.insert(FileState::READABLE)
188 }
189 if events.intersects(EpollEvents::EPOLLOUT) {
190 state.insert(FileState::WRITABLE)
191 }
192
193 state
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 const DATA: u64 = 1234;
202
203 fn poll_init(init: FileState, interest: EpollEvents) {
204 let mut entry = Entry::new(interest, DATA, init);
205 assert!(entry.has_ready_events());
206
207 let (ev, data) = entry.collect_ready_events().unwrap();
208 assert!(interest.contains(ev));
209 assert_eq!(data, DATA);
210 }
211
212 #[test]
213 fn poll_init_r() {
214 let init = FileState::READABLE;
215 poll_init(init, EpollEvents::EPOLLIN);
216 }
217
218 #[test]
219 fn poll_init_w() {
220 let init = FileState::WRITABLE;
221 poll_init(init, EpollEvents::EPOLLOUT);
222 }
223
224 #[test]
225 fn poll_init_rw() {
226 let init = FileState::READABLE | FileState::WRITABLE;
227 poll_init(init, EpollEvents::EPOLLIN);
228 poll_init(init, EpollEvents::EPOLLOUT);
229 poll_init(init, EpollEvents::EPOLLIN | EpollEvents::EPOLLOUT);
230 }
231
232 fn poll_on_state(
235 init: FileState,
236 interest: EpollEvents,
237 change_on: FileState,
238 signals: FileSignals,
239 ) {
240 let mut entry = Entry::new(interest, DATA, init);
241 assert!(!entry.has_ready_events());
242
243 entry.notify(init.union(change_on), change_on, signals);
244 assert!(entry.has_ready_events());
245
246 let (ev, data) = entry.collect_ready_events().unwrap();
247 assert!(interest.contains(ev));
248 assert_eq!(data, DATA);
249 }
250
251 #[test]
252 fn poll_on_r() {
253 let on = FileState::READABLE;
254 poll_on_state(
255 FileState::empty(),
256 EpollEvents::EPOLLIN,
257 on,
258 FileSignals::empty(),
259 );
260 poll_on_state(
261 FileState::empty(),
262 EpollEvents::EPOLLIN | EpollEvents::EPOLLOUT,
263 on,
264 FileSignals::empty(),
265 );
266 poll_on_state(
267 FileState::WRITABLE,
268 EpollEvents::EPOLLIN,
269 on,
270 FileSignals::empty(),
271 );
272 }
273
274 #[test]
275 fn poll_on_w() {
276 let on = FileState::WRITABLE;
277 poll_on_state(
278 FileState::empty(),
279 EpollEvents::EPOLLOUT,
280 on,
281 FileSignals::empty(),
282 );
283 poll_on_state(
284 FileState::empty(),
285 EpollEvents::EPOLLIN | EpollEvents::EPOLLOUT,
286 on,
287 FileSignals::empty(),
288 );
289 poll_on_state(
290 FileState::READABLE,
291 EpollEvents::EPOLLOUT,
292 on,
293 FileSignals::empty(),
294 );
295 }
296
297 #[test]
298 fn poll_on_rw() {
299 let on = FileState::READABLE | FileState::WRITABLE;
300 poll_on_state(
301 FileState::empty(),
302 EpollEvents::EPOLLIN,
303 on,
304 FileSignals::empty(),
305 );
306 poll_on_state(
307 FileState::empty(),
308 EpollEvents::EPOLLOUT,
309 on,
310 FileSignals::empty(),
311 );
312 poll_on_state(
313 FileState::empty(),
314 EpollEvents::EPOLLIN | EpollEvents::EPOLLOUT,
315 on,
316 FileSignals::empty(),
317 );
318 }
319
320 fn poll_off_state(
323 init: FileState,
324 interest: EpollEvents,
325 change_off: FileState,
326 signals: FileSignals,
327 ) {
328 let mut entry = Entry::new(interest, DATA, init);
329 assert!(entry.has_ready_events());
330
331 entry.notify(init.difference(change_off), change_off, signals);
332 assert!(!entry.has_ready_events());
333 assert!(entry.collect_ready_events().is_none());
334 }
335
336 #[test]
337 fn poll_off_r() {
338 let interest = EpollEvents::EPOLLIN;
339 let off = FileState::READABLE;
340 poll_off_state(off, interest, off, FileSignals::empty());
341 poll_off_state(
342 FileState::WRITABLE | off,
343 interest,
344 off,
345 FileSignals::empty(),
346 );
347 }
348
349 #[test]
350 fn poll_off_w() {
351 let interest = EpollEvents::EPOLLOUT;
352 let off = FileState::WRITABLE;
353 poll_off_state(off, interest, off, FileSignals::empty());
354 poll_off_state(
355 FileState::READABLE | off,
356 interest,
357 off,
358 FileSignals::empty(),
359 );
360 }
361
362 #[test]
363 fn poll_off_rw() {
364 let off = FileState::READABLE | FileState::WRITABLE;
365 poll_off_state(off, EpollEvents::EPOLLIN, off, FileSignals::empty());
366 poll_off_state(off, EpollEvents::EPOLLOUT, off, FileSignals::empty());
367 poll_off_state(
368 off,
369 EpollEvents::EPOLLIN | EpollEvents::EPOLLOUT,
370 off,
371 FileSignals::empty(),
372 );
373 }
374
375 #[test]
376 fn level_trigger() {
377 let in_lt = EpollEvents::EPOLLIN;
378 let mut entry = Entry::new(in_lt, DATA, FileState::empty());
379 assert!(!entry.has_ready_events());
380
381 entry.notify(
382 FileState::READABLE,
383 FileState::READABLE,
384 FileSignals::empty(),
385 );
386 assert!(entry.has_ready_events());
387
388 for _ in 0..3 {
389 assert_eq!(
390 entry.collect_ready_events(),
391 Some((EpollEvents::EPOLLIN, DATA))
392 );
393 assert!(entry.has_ready_events());
394 }
395
396 entry.notify(
397 FileState::empty(),
398 FileState::READABLE,
399 FileSignals::empty(),
400 );
401 assert!(!entry.has_ready_events());
402 entry.notify(
403 FileState::READABLE,
404 FileState::READABLE,
405 FileSignals::empty(),
406 );
407 assert!(entry.has_ready_events());
408
409 for _ in 0..3 {
410 assert_eq!(
411 entry.collect_ready_events(),
412 Some((EpollEvents::EPOLLIN, DATA))
413 );
414 assert!(entry.has_ready_events());
415 }
416 }
417
418 #[test]
419 fn edge_trigger() {
420 let in_et = EpollEvents::EPOLLIN | EpollEvents::EPOLLET;
421 let mut entry = Entry::new(in_et, DATA, FileState::empty());
422 assert!(!entry.has_ready_events());
423
424 entry.notify(
425 FileState::READABLE,
426 FileState::READABLE,
427 FileSignals::empty(),
428 );
429
430 assert!(entry.has_ready_events());
431 assert_eq!(
432 entry.collect_ready_events(),
433 Some((EpollEvents::EPOLLIN, DATA))
434 );
435
436 assert!(!entry.has_ready_events());
438 assert_eq!(entry.collect_ready_events(), None);
439
440 entry.notify(
442 FileState::READABLE,
443 FileState::empty(),
444 FileSignals::empty(),
445 );
446 assert!(!entry.has_ready_events());
447
448 entry.notify(
450 FileState::READABLE,
451 FileState::empty(),
452 FileSignals::READ_BUFFER_GREW,
453 );
454 assert!(entry.has_ready_events());
455 assert_eq!(
456 entry.collect_ready_events(),
457 Some((EpollEvents::EPOLLIN, DATA))
458 );
459
460 entry.notify(
463 FileState::empty(),
464 FileState::empty(),
465 FileSignals::READ_BUFFER_GREW,
466 );
467 assert!(!entry.has_ready_events());
468
469 entry.notify(
471 FileState::empty(),
472 FileState::READABLE,
473 FileSignals::empty(),
474 );
475 assert!(!entry.has_ready_events());
476
477 entry.notify(
479 FileState::READABLE,
480 FileState::READABLE,
481 FileSignals::empty(),
482 );
483 assert!(entry.has_ready_events());
484 assert_eq!(
485 entry.collect_ready_events(),
486 Some((EpollEvents::EPOLLIN, DATA))
487 );
488
489 assert!(!entry.has_ready_events());
490 }
491
492 #[test]
493 fn one_shot() {
494 let in_os = EpollEvents::EPOLLIN | EpollEvents::EPOLLONESHOT;
495 let mut entry = Entry::new(in_os, DATA, FileState::empty());
496 assert!(!entry.has_ready_events());
497
498 entry.notify(
499 FileState::READABLE,
500 FileState::READABLE,
501 FileSignals::empty(),
502 );
503
504 assert!(entry.has_ready_events());
505 assert_eq!(
506 entry.collect_ready_events(),
507 Some((EpollEvents::EPOLLIN, DATA))
508 );
509
510 assert!(!entry.has_ready_events());
512 assert_eq!(entry.collect_ready_events(), None);
513 entry.notify(
514 FileState::READABLE,
515 FileState::empty(),
516 FileSignals::empty(),
517 );
518 assert!(!entry.has_ready_events());
519 entry.notify(
520 FileState::empty(),
521 FileState::READABLE,
522 FileSignals::empty(),
523 );
524 assert!(!entry.has_ready_events());
525 entry.notify(
526 FileState::READABLE,
527 FileState::READABLE,
528 FileSignals::empty(),
529 );
530 assert!(!entry.has_ready_events());
531
532 entry.modify(in_os, DATA, FileState::READABLE);
533
534 assert!(entry.has_ready_events());
535 assert_eq!(
536 entry.collect_ready_events(),
537 Some((EpollEvents::EPOLLIN, DATA))
538 );
539
540 entry.notify(
541 FileState::empty(),
542 FileState::READABLE,
543 FileSignals::empty(),
544 );
545 entry.notify(
546 FileState::READABLE,
547 FileState::READABLE,
548 FileSignals::empty(),
549 );
550
551 assert!(!entry.has_ready_events());
552 assert_eq!(entry.collect_ready_events(), None);
553 }
554}