shadow_rs/host/descriptor/epoll/
key.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use core::hash::Hash;
use std::cmp::Ordering;

use crate::host::descriptor::File;

/// A `Key` helps us find an epoll entry given the fd and `File` object available at the time that a
/// syscall is made. Epoll uses `Key`s to be able to add the same `File` multiple times under
/// different fds, and add the same fd multiple times as long as the `File` is different.
#[derive(Clone)]
pub(super) struct Key {
    fd: i32,
    file: File,
}

impl Key {
    pub fn new(fd: i32, file: File) -> Self {
        Self { fd, file }
    }

    pub fn file(&self) -> &File {
        &self.file
    }
}

impl Eq for Key {}

impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        self.fd == other.fd && self.file.canonical_handle() == other.file.canonical_handle()
    }
}

impl Hash for Key {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.fd.hash(state);
        self.file.canonical_handle().hash(state);
    }
}

/// A `PriorityKey` helps us sort keys by a given priority. We use monitonically increasing priority
/// values to ensure fairness when reporting events (so that we don't always report events from the
/// same entry first and starve other entries). Using unique priority values for every key also
/// ensure deterministic sorting.
pub(super) struct PriorityKey {
    pri: u64,
    key: Key,
}

impl PriorityKey {
    /// Creates a new `PriorityKey` with the given priority.
    ///
    /// The new key will be tested for equality and order based exclusively on the `pri` value while
    /// ignoring the `key` value. Thus, callers should ensure that every instance of this object
    /// that should be considered unique is created with a unique priority value.
    pub fn new(pri: u64, key: Key) -> Self {
        Self { pri, key }
    }

    pub fn priority(&self) -> u64 {
        self.pri
    }
}

impl Eq for PriorityKey {}

impl PartialEq for PriorityKey {
    fn eq(&self, other: &Self) -> bool {
        // Equality is based only on the priority value as explained in `PriorityKey::new()`.
        self.pri.eq(&other.pri)
    }
}

impl Ord for PriorityKey {
    fn cmp(&self, other: &Self) -> Ordering {
        // Order is based only on the priority value as explained in `PriorityKey::new()`.
        self.pri.cmp(&other.pri)
    }
}

impl PartialOrd for PriorityKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl From<PriorityKey> for Key {
    fn from(value: PriorityKey) -> Self {
        value.key
    }
}