Skip to main content

reovim_kernel/sched/
priority.rs

1//! Priority queue for ordered event processing.
2//!
3//! Linux equivalent: Priority scheduling in `kernel/sched/`
4//!
5//! This module provides a priority-ordered queue for events. Events with
6//! lower priority values are processed first. Events with the same priority
7//! are processed in FIFO order.
8//!
9//! # Example
10//!
11//! ```ignore
12//! use reovim_kernel::sched::PriorityQueue;
13//! use reovim_kernel::ipc::{DynEvent, Event};
14//!
15//! #[derive(Debug)]
16//! struct HighPriorityEvent;
17//! impl Event for HighPriorityEvent {
18//!     fn priority(&self) -> u32 { 0 }
19//! }
20//!
21//! #[derive(Debug)]
22//! struct LowPriorityEvent;
23//! impl Event for LowPriorityEvent {
24//!     fn priority(&self) -> u32 { 200 }
25//! }
26//!
27//! let queue = PriorityQueue::new();
28//!
29//! // Add events in reverse priority order
30//! queue.push(DynEvent::new(LowPriorityEvent));
31//! queue.push(DynEvent::new(HighPriorityEvent));
32//!
33//! // Pop returns highest priority (lowest value) first
34//! let event = queue.pop().unwrap();
35//! assert_eq!(event.priority(), 0); // HighPriorityEvent
36//! ```
37
38use std::{
39    cmp::Ordering,
40    collections::BinaryHeap,
41    sync::atomic::{AtomicU64, Ordering as AtomicOrdering},
42};
43
44use crate::{arch::sync::Mutex, ipc::DynEvent};
45
46/// Default capacity for priority queue.
47pub const DEFAULT_CAPACITY: usize = 256;
48
49/// Entry in the priority queue.
50///
51/// Wraps a `DynEvent` with ordering metadata for the binary heap.
52struct PriorityEntry {
53    /// Event priority (from `Event::priority()`).
54    priority: u32,
55
56    /// Insertion sequence for FIFO ordering within same priority.
57    sequence: u64,
58
59    /// The event.
60    event: DynEvent,
61}
62
63// LLVM coverage artifact: closing brace of PartialEq impl marked DA:0;
64// PriorityEntry equality is only used internally by BinaryHeap ordering.
65#[cfg_attr(coverage_nightly, coverage(off))]
66impl PartialEq for PriorityEntry {
67    fn eq(&self, other: &Self) -> bool {
68        self.priority == other.priority && self.sequence == other.sequence
69    }
70}
71
72impl Eq for PriorityEntry {}
73
74impl PartialOrd for PriorityEntry {
75    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76        Some(self.cmp(other))
77    }
78}
79
80impl Ord for PriorityEntry {
81    fn cmp(&self, other: &Self) -> Ordering {
82        // BinaryHeap is a max-heap, so we reverse the ordering:
83        // - Lower priority value = higher precedence (comes first)
84        // - For same priority, lower sequence = earlier (FIFO)
85        //
86        // We want: smaller priority → "greater" in heap terms
87        // We want: smaller sequence → "greater" in heap terms (for same priority)
88        match other.priority.cmp(&self.priority) {
89            Ordering::Equal => other.sequence.cmp(&self.sequence),
90            ord => ord,
91        }
92    }
93}
94
95/// Priority queue for events.
96///
97/// Maintains events in priority order with FIFO ordering for events
98/// of the same priority. Thread-safe via internal mutex.
99///
100/// # Ordering
101///
102/// Events are ordered by:
103/// 1. Priority (lower value = higher precedence)
104/// 2. Insertion order (earlier = higher precedence)
105///
106/// This ensures that high-priority events (like user input) are always
107/// processed before low-priority events (like render signals).
108pub struct PriorityQueue {
109    /// Heap storage.
110    heap: Mutex<BinaryHeap<PriorityEntry>>,
111
112    /// Sequence counter for FIFO ordering.
113    sequence: AtomicU64,
114
115    /// Maximum capacity (0 = unlimited).
116    capacity: usize,
117}
118
119impl PriorityQueue {
120    /// Create a new priority queue with default capacity.
121    #[must_use]
122    pub fn new() -> Self {
123        Self::with_capacity(DEFAULT_CAPACITY)
124    }
125
126    /// Create a priority queue with specified capacity.
127    ///
128    /// A capacity of 0 means unlimited (not recommended).
129    #[must_use]
130    pub fn with_capacity(capacity: usize) -> Self {
131        Self {
132            heap: Mutex::new(BinaryHeap::with_capacity(capacity.min(4096))),
133            sequence: AtomicU64::new(0),
134            capacity,
135        }
136    }
137
138    /// Push an event onto the queue.
139    ///
140    /// Returns `false` if capacity is exceeded (event is dropped).
141    #[cfg_attr(coverage_nightly, coverage(off))]
142    pub fn push(&self, event: DynEvent) -> bool {
143        let mut heap = self.heap.lock();
144
145        if self.capacity > 0 && heap.len() >= self.capacity {
146            return false;
147        }
148
149        let entry = PriorityEntry {
150            priority: event.priority(),
151            sequence: self.sequence.fetch_add(1, AtomicOrdering::Relaxed),
152            event,
153        };
154        heap.push(entry);
155        true
156    }
157
158    /// Pop the highest priority event.
159    ///
160    /// Returns `None` if the queue is empty.
161    #[must_use]
162    pub fn pop(&self) -> Option<DynEvent> {
163        self.heap.lock().pop().map(|e| e.event)
164    }
165
166    /// Peek at the priority of the next event without removing it.
167    ///
168    /// Returns `None` if the queue is empty.
169    #[must_use]
170    pub fn peek_priority(&self) -> Option<u32> {
171        self.heap.lock().peek().map(|e| e.priority)
172    }
173
174    /// Get the number of events in the queue.
175    #[must_use]
176    pub fn len(&self) -> usize {
177        self.heap.lock().len()
178    }
179
180    /// Check if the queue is empty.
181    #[must_use]
182    pub fn is_empty(&self) -> bool {
183        self.heap.lock().is_empty()
184    }
185
186    /// Get the queue capacity.
187    #[inline]
188    #[must_use]
189    pub const fn capacity(&self) -> usize {
190        self.capacity
191    }
192
193    /// Clear all events from the queue.
194    pub fn clear(&self) {
195        self.heap.lock().clear();
196    }
197
198    /// Drain all events from the queue in priority order.
199    ///
200    /// Returns events sorted by priority (highest first).
201    #[must_use]
202    pub fn drain(&self) -> Vec<DynEvent> {
203        let mut heap = self.heap.lock();
204        let mut result = Vec::with_capacity(heap.len());
205        while let Some(entry) = heap.pop() {
206            result.push(entry.event);
207        }
208        result
209    }
210}
211
212impl Default for PriorityQueue {
213    fn default() -> Self {
214        Self::new()
215    }
216}
217
218impl std::fmt::Debug for PriorityQueue {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        f.debug_struct("PriorityQueue")
221            .field("len", &self.len())
222            .field("capacity", &self.capacity)
223            .field("peek_priority", &self.peek_priority())
224            .finish_non_exhaustive()
225    }
226}