kernel/sync/
waker.rs

1//! Waker - Synchronization primitive for task waiting and waking
2//!
3//! This module provides the `Waker` struct, which manages asynchronous task waiting
4//! and waking mechanisms. It allows tasks to block on specific events and be woken
5//! up when those events occur, such as I/O completion or interrupt handling.
6
7extern crate alloc;
8
9use alloc::collections::VecDeque;
10use spin::Mutex;
11use core::fmt;
12use crate::arch::Arch;
13use crate::task::{BlockedType, Task, TaskState};
14use crate::sched::scheduler::get_scheduler;
15
16/// A synchronization primitive that manages waiting and waking of tasks
17/// 
18/// The `Waker` struct provides a mechanism for tasks to wait for specific events
19/// and be woken up when those events occur. It maintains a queue of waiting task IDs
20/// and provides methods to block the current task or wake up waiting tasks.
21/// 
22/// # Examples
23/// 
24/// ```
25/// // Create a new interruptible waker for UART receive events
26/// static UART_RX_WAKER: Waker = Waker::new_interruptible("uart_rx");
27/// 
28/// // In a blocking read function
29/// UART_RX_WAKER.wait();
30/// 
31/// // In an interrupt handler
32/// UART_RX_WAKER.wake_one();
33/// ```
34pub struct Waker {
35    /// Queue of waiting task IDs
36    wait_queue: Mutex<VecDeque<usize>>,
37    /// The type of blocking this waker uses (interruptible or uninterruptible)
38    block_type: BlockedType,
39    /// Human-readable name for debugging purposes
40    name: &'static str,
41}
42
43impl Waker {
44    /// Create a new interruptible waker
45    /// 
46    /// Interruptible wakers allow waiting tasks to be interrupted by signals
47    /// or other asynchronous events. This is suitable for user I/O operations
48    /// where cancellation might be needed.
49    /// 
50    /// # Arguments
51    /// 
52    /// * `name` - A human-readable name for debugging purposes
53    /// 
54    /// # Examples
55    /// 
56    /// ```
57    /// static KEYBOARD_WAKER: Waker = Waker::new_interruptible("keyboard");
58    /// ```
59    pub const fn new_interruptible(name: &'static str) -> Self {
60        Self {
61            wait_queue: Mutex::new(VecDeque::new()),
62            block_type: BlockedType::Interruptible,
63            name,
64        }
65    }
66
67    /// Create a new uninterruptible waker
68    /// 
69    /// Uninterruptible wakers ensure that waiting tasks cannot be interrupted
70    /// and will wait until the event occurs. This is suitable for critical
71    /// operations like disk I/O where data integrity is important.
72    /// 
73    /// # Arguments
74    /// 
75    /// * `name` - A human-readable name for debugging purposes
76    /// 
77    /// # Examples
78    /// 
79    /// ```
80    /// static DISK_IO_WAKER: Waker = Waker::new_uninterruptible("disk_io");
81    /// ```
82    pub const fn new_uninterruptible(name: &'static str) -> Self {
83        Self {
84            wait_queue: Mutex::new(VecDeque::new()),
85            block_type: BlockedType::Uninterruptible,
86            name,
87        }
88    }
89
90    /// Block the current task and add it to the wait queue
91    /// 
92    /// This method puts the current task into a blocked state and adds its ID
93    /// to the wait queue. The task will remain blocked until another part of
94    /// the system calls `wake_one()` or `wake_all()` on this waker.
95    /// 
96    /// # Behavior
97    /// 
98    /// 1. Gets the current task ID
99    /// 2. Sets the task state to `Blocked(self.block_type)`
100    /// 3. Adds the task ID to the wait queue
101    /// 4. Calls the scheduler to yield CPU to other tasks
102    /// 
103    /// # Note
104    /// 
105    /// This function never returns normally. The task will be blocked and only
106    /// resume execution when the entire syscall is restarted after being woken up.
107    /// The `!` return type indicates this function diverges (never returns).
108    pub fn wait(&self, task: &mut Task, cpu: &mut Arch) -> ! {
109        let task_id = task.get_id();
110                
111        // Add task to wait queue first
112        {
113            let mut queue = self.wait_queue.lock();
114            queue.push_back(task_id);
115        }
116        
117        // Set task state to blocked
118        task.set_state(TaskState::Blocked(self.block_type));
119
120        // Store current CPU state to task before yielding
121        task.vcpu.store(cpu);
122
123        // Yield CPU to scheduler - this never returns
124        // The scheduler will handle saving the current task state internally
125        get_scheduler().schedule(cpu);
126    }
127
128    /// Wake up one waiting task
129    /// 
130    /// This method removes one task from the wait queue and moves it from
131    /// the blocked queue to the ready queue, making it eligible for scheduling again.
132    /// 
133    /// # Returns
134    /// 
135    /// * `true` if a task was woken up
136    /// * `false` if the wait queue was empty
137    /// 
138    /// # Examples
139    /// 
140    /// ```
141    /// // In an interrupt handler
142    /// if UART_RX_WAKER.wake_one() {
143    ///     // A task was woken up
144    /// }
145    /// ```
146    pub fn wake_one(&self) -> bool {
147        let task_id = {
148            let mut queue = self.wait_queue.lock();
149            queue.pop_front()
150        };
151
152        if let Some(task_id) = task_id {
153            // Use the scheduler's wake_task method to move from blocked to ready queue
154            get_scheduler().wake_task(task_id)
155        } else {
156            false
157        }
158    }
159
160    /// Wake up all waiting tasks
161    /// 
162    /// This method removes all tasks from the wait queue and moves them from
163    /// the blocked queue to the ready queue, making them all eligible for scheduling again.
164    /// 
165    /// # Returns
166    /// 
167    /// The number of tasks that were woken up
168    /// 
169    /// # Examples
170    /// 
171    /// ```
172    /// // Wake all tasks waiting for a broadcast event
173    /// let woken_count = BROADCAST_WAKER.wake_all();
174    /// println!("Woke up {} tasks", woken_count);
175    /// ```
176    pub fn wake_all(&self) -> usize {
177        let task_ids = {
178            let mut queue = self.wait_queue.lock();
179            let ids: VecDeque<usize> = queue.drain(..).collect();
180            ids
181        };
182
183        let mut woken_count = 0;
184        for task_id in task_ids {
185            // Use the scheduler's wake_task method to move from blocked to ready queue
186            if get_scheduler().wake_task(task_id) {
187                woken_count += 1;
188            }
189        }
190
191        woken_count
192    }
193
194    /// Get the blocking type of this waker
195    /// 
196    /// # Returns
197    /// 
198    /// The `BlockedType` (either `Interruptible` or `Uninterruptible`)
199    pub fn block_type(&self) -> BlockedType {
200        self.block_type
201    }
202
203    /// Get the number of tasks currently waiting
204    /// 
205    /// # Returns
206    /// 
207    /// The number of tasks in the wait queue
208    pub fn waiting_count(&self) -> usize {
209        self.wait_queue.lock().len()
210    }
211
212    /// Get the name of this waker
213    /// 
214    /// # Returns
215    /// 
216    /// The human-readable name for debugging purposes
217    pub fn name(&self) -> &'static str {
218        self.name
219    }
220
221    /// Get a list of task IDs currently waiting in the queue
222    /// 
223    /// This method returns a snapshot of all task IDs currently waiting
224    /// in this waker's queue. Useful for debugging and monitoring.
225    /// 
226    /// # Returns
227    /// 
228    /// A vector containing all waiting task IDs
229    /// 
230    /// # Examples
231    /// 
232    /// ```
233    /// let waiting_tasks = waker.get_waiting_task_ids();
234    /// println!("Tasks waiting: {:?}", waiting_tasks);
235    /// ```
236    pub fn get_waiting_task_ids(&self) -> VecDeque<usize> {
237        self.wait_queue.lock().clone()
238    }
239
240    /// Check if a specific task is waiting in this waker
241    /// 
242    /// # Arguments
243    /// 
244    /// * `task_id` - The ID of the task to check
245    /// 
246    /// # Returns
247    /// 
248    /// `true` if the task is waiting in this waker, `false` otherwise
249    pub fn is_task_waiting(&self, task_id: usize) -> bool {
250        self.wait_queue.lock().contains(&task_id)
251    }
252
253    /// Get detailed statistics about this waker
254    /// 
255    /// This method provides detailed information about the current state
256    /// of the waker, including all waiting tasks and their metadata.
257    /// 
258    /// # Returns
259    /// 
260    /// A `WakerStats` struct containing comprehensive state information
261    /// 
262    /// # Examples
263    /// 
264    /// ```
265    /// let stats = uart_waker.get_stats();
266    /// // Use Debug trait to print the stats
267    /// ```
268    pub fn get_stats(&self) -> WakerStats {
269        let waiting_tasks = self.wait_queue.lock();
270        WakerStats {
271            name: self.name,
272            block_type: self.block_type,
273            waiting_count: waiting_tasks.len(),
274            waiting_task_ids: waiting_tasks.clone(),
275        }
276    }
277
278    /// Print debug information about this waker
279    /// 
280    /// Outputs detailed information about the waker's current state
281    /// including name, blocking type, waiting task count, and task IDs.
282    /// Useful for debugging and monitoring system state.
283    /// 
284    /// # Examples
285    /// 
286    /// ```
287    /// waker.debug_print();
288    /// // Output:
289    /// // [Waker DEBUG] uart_rx: Interruptible, 3 waiting tasks: [42, 137, 89]
290    /// ```
291    /// Check if the waker has any waiting tasks
292    /// 
293    /// # Returns
294    /// 
295    /// `true` if there are no waiting tasks, `false` otherwise
296    pub fn is_empty(&self) -> bool {
297        self.wait_queue.lock().is_empty()
298    }
299
300    /// Clear all waiting tasks without waking them
301    /// 
302    /// This is a dangerous operation that should only be used in
303    /// exceptional circumstances like system cleanup or error recovery.
304    /// The tasks will remain in blocked state and need to be handled
305    /// separately.
306    /// 
307    /// # Returns
308    /// 
309    /// The number of tasks that were removed from the queue
310    /// 
311    /// # Safety
312    /// 
313    /// This operation can leave tasks in a permanently blocked state.
314    /// Use with extreme caution.
315    pub fn clear_queue(&self) -> usize {
316        let mut queue = self.wait_queue.lock();
317        let count = queue.len();
318        queue.clear();
319        count
320    }
321}
322
323impl fmt::Debug for Waker {
324    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325        let waiting_tasks = self.wait_queue.lock();
326        f.debug_struct("Waker")
327            .field("name", &self.name)
328            .field("block_type", &self.block_type)
329            .field("waiting_count", &waiting_tasks.len())
330            .field("waiting_task_ids", &*waiting_tasks)
331            .finish()
332    }
333}
334
335/// Statistics and state information for a Waker
336/// 
337/// This struct provides a comprehensive view of a waker's current state,
338/// useful for debugging, monitoring, and system analysis.
339#[derive(Debug, Clone)]
340pub struct WakerStats {
341    /// Human-readable name of the waker
342    pub name: &'static str,
343    /// The blocking type (Interruptible or Uninterruptible)
344    pub block_type: BlockedType,
345    /// Number of tasks currently waiting
346    pub waiting_count: usize,
347    /// List of task IDs currently waiting
348    pub waiting_task_ids: VecDeque<usize>,
349}
350
351#[cfg(test)]
352mod tests {
353    use super::*;
354
355    #[test_case]
356    fn test_waker_creation() {
357        let interruptible_waker = Waker::new_interruptible("test_int");
358        assert_eq!(interruptible_waker.name(), "test_int");
359        assert_eq!(interruptible_waker.block_type(), BlockedType::Interruptible);
360        assert_eq!(interruptible_waker.waiting_count(), 0);
361
362        let uninterruptible_waker = Waker::new_uninterruptible("test_unint");
363        assert_eq!(uninterruptible_waker.name(), "test_unint");
364        assert_eq!(uninterruptible_waker.block_type(), BlockedType::Uninterruptible);
365        assert_eq!(uninterruptible_waker.waiting_count(), 0);
366    }
367
368    #[test_case]
369    fn test_wake_empty_queue() {
370        let waker = Waker::new_interruptible("empty_test");
371        assert_eq!(waker.wake_one(), false);
372        assert_eq!(waker.wake_all(), 0);
373    }
374
375    #[test_case]
376    fn test_debug_functionality() {
377        let waker = Waker::new_interruptible("debug_test");
378        
379        // Test empty waker
380        assert!(waker.is_empty());
381        assert_eq!(waker.waiting_count(), 0);
382        assert_eq!(waker.get_waiting_task_ids().len(), 0);
383        assert!(!waker.is_task_waiting(42));
384        
385        // Test stats
386        let stats = waker.get_stats();
387        assert_eq!(stats.name, "debug_test");
388        assert_eq!(stats.block_type, BlockedType::Interruptible);
389        assert_eq!(stats.waiting_count, 0);
390        assert!(stats.waiting_task_ids.is_empty());
391    }
392
393    #[test_case]
394    fn test_debug_trait() {
395        let waker = Waker::new_uninterruptible("debug_trait_test");
396        
397        // Verify Debug trait implementation exists and works
398        let debug_string = alloc::format!("{:?}", waker);
399        assert!(debug_string.contains("debug_trait_test"));
400        assert!(debug_string.contains("Uninterruptible"));
401        assert!(debug_string.contains("waiting_count: 0"));
402    }
403
404    #[test_case]
405    fn test_clear_queue() {
406        let waker = Waker::new_interruptible("clear_test");
407        
408        // Test clearing empty queue
409        assert_eq!(waker.clear_queue(), 0);
410        assert!(waker.is_empty());
411    }
412
413    #[test_case]
414    fn test_waker_stats_debug() {
415        let waker = Waker::new_interruptible("stats_test");
416        let stats = waker.get_stats();
417        
418        // Test WakerStats Debug implementation
419        let debug_string = alloc::format!("{:?}", stats);
420        assert!(debug_string.contains("stats_test"));
421        assert!(debug_string.contains("Interruptible"));
422    }
423}