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
}
}