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}