preemptive_threads/
platform_timer.rs

1//! Platform-specific timer implementations for preemptive scheduling
2
3use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4
5static PREEMPTION_PENDING: AtomicBool = AtomicBool::new(false);
6static PREEMPTION_COUNT: AtomicU64 = AtomicU64::new(0);
7
8/// Signal handler that just sets a flag - actual scheduling happens outside signal context
9/// 
10/// # Safety
11/// This function is called from signal context and only uses async-signal-safe operations.
12/// It only modifies atomic variables and performs no memory allocation or complex operations.
13#[cfg(target_os = "linux")]
14pub unsafe extern "C" fn signal_safe_handler(_sig: i32) {
15    // Only use async-signal-safe operations here
16    PREEMPTION_PENDING.store(true, Ordering::Release);
17    PREEMPTION_COUNT.fetch_add(1, Ordering::Relaxed);
18}
19
20/// Check if preemption is pending (called from normal context)
21pub fn is_preemption_pending() -> bool {
22    PREEMPTION_PENDING.load(Ordering::Acquire)
23}
24
25/// Clear preemption pending flag
26pub fn clear_preemption_pending() {
27    PREEMPTION_PENDING.store(false, Ordering::Release);
28}
29
30/// Get total preemption count for statistics
31pub fn get_preemption_count() -> u64 {
32    PREEMPTION_COUNT.load(Ordering::Relaxed)
33}
34
35/// Platform-specific timer implementation for Linux using timerfd
36#[cfg(target_os = "linux")]
37pub mod linux_timer {
38    
39    pub fn init_preemption_timer(_interval_ms: u64) -> Result<(), &'static str> {
40        // For a complete implementation, you would:
41        // 1. Create a timerfd using timerfd_create()
42        // 2. Set it up with timerfd_settime()
43        // 3. Use signalfd() or signal handlers
44        // 4. Or use a separate thread with epoll/poll
45        
46        // For now, return an error suggesting cooperative scheduling
47        Err("Hardware timer preemption not implemented - use cooperative yield points")
48    }
49    
50    pub fn stop_preemption_timer() {
51        // Would close the timerfd and clean up
52    }
53}
54
55/// Platform-specific timer implementation for macOS/BSD
56#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
57pub mod bsd_timer {
58    
59    pub fn init_preemption_timer(_interval_ms: u64) -> Result<(), &'static str> {
60        // For BSD systems, you would use kqueue with EVFILT_TIMER
61        // or setitimer() if available
62        Err("Hardware timer preemption not implemented for BSD - use cooperative yield points")
63    }
64    
65    pub fn stop_preemption_timer() {
66        // Would clean up kqueue timer
67    }
68}
69
70/// Fallback implementation for other platforms
71#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
72pub mod generic_timer {
73    
74    pub fn init_preemption_timer(_interval_ms: u64) -> Result<(), &'static str> {
75        Err("Hardware timer preemption not supported on this platform")
76    }
77    
78    pub fn stop_preemption_timer() {
79        // No-op
80    }
81}
82
83/// Initialize platform-appropriate preemption timer
84pub fn init_preemption_timer(interval_ms: u64) -> Result<(), &'static str> {
85    #[cfg(target_os = "linux")]
86    return linux_timer::init_preemption_timer(interval_ms);
87    
88    #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
89    return bsd_timer::init_preemption_timer(interval_ms);
90    
91    #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
92    return generic_timer::init_preemption_timer(interval_ms);
93}
94
95/// Stop platform-appropriate preemption timer
96pub fn stop_preemption_timer() {
97    #[cfg(target_os = "linux")]
98    linux_timer::stop_preemption_timer();
99    
100    #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
101    bsd_timer::stop_preemption_timer();
102    
103    #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
104    generic_timer::stop_preemption_timer();
105}
106
107/// Preemption checkpoint - should be called regularly from normal code
108/// This is where actual scheduling decisions are made, outside signal context
109pub fn preemption_checkpoint() {
110    if is_preemption_pending() {
111        clear_preemption_pending();
112        
113        // Safe to do complex operations here - we're not in signal context
114        // Yield to scheduler - the scheduler is a global static
115        crate::sync::yield_thread();
116    }
117}
118
119/// Cooperative preemption points - insert these in long-running code
120#[macro_export]
121macro_rules! preemption_point {
122    () => {
123        $crate::platform_timer::preemption_checkpoint();
124    };
125}