Skip to main content

portalis_transpiler/wasi_threading/
mod.rs

1//! WASI Threading and Synchronization Primitives
2//!
3//! Provides a unified threading API that works across:
4//! - Native Rust (std::thread + rayon + parking_lot)
5//! - Browser WASM (Web Workers via wasm-bindgen)
6//! - WASI WASM (wasi-threads or compatibility layer)
7//!
8//! This module bridges Python's threading operations to WASM-compatible implementations.
9//!
10//! # Examples
11//!
12//! ## Basic Threading
13//! ```rust,no_run
14//! use wasi_threading::{WasiThread, ThreadConfig};
15//!
16//! // Spawn a new thread
17//! let handle = WasiThread::spawn(|| {
18//!     println!("Hello from thread!");
19//!     42
20//! })?;
21//!
22//! // Wait for completion and get result
23//! let result = handle.join()?;
24//! assert_eq!(result, 42);
25//! ```
26//!
27//! ## Synchronization
28//! ```rust,no_run
29//! use wasi_threading::{WasiMutex, WasiRwLock};
30//!
31//! // Mutex for exclusive access
32//! let mutex = WasiMutex::new(0);
33//! {
34//!     let mut guard = mutex.lock();
35//!     *guard += 1;
36//! }
37//!
38//! // RwLock for concurrent reads
39//! let rwlock = WasiRwLock::new(vec![1, 2, 3]);
40//! {
41//!     let read_guard = rwlock.read();
42//!     println!("Length: {}", read_guard.len());
43//! }
44//! ```
45//!
46//! ## Thread Pool
47//! ```rust,no_run
48//! use wasi_threading::ThreadPool;
49//!
50//! let pool = ThreadPool::new(4)?;
51//! pool.execute(|| {
52//!     println!("Task running in pool");
53//! });
54//! ```
55
56use anyhow::Result;
57use std::time::Duration;
58
59// Re-export platform-specific modules
60pub mod thread;
61pub mod sync;
62pub mod collections;
63pub mod pool;
64
65// Platform-specific implementations
66#[cfg(not(target_arch = "wasm32"))]
67pub(crate) mod native;
68
69#[cfg(all(target_arch = "wasm32", feature = "wasm"))]
70pub(crate) mod browser;
71
72#[cfg(all(target_arch = "wasm32", feature = "wasi"))]
73pub(crate) mod wasi_impl;
74
75// Re-export main types
76pub use thread::{
77    WasiThread, ThreadConfig, ThreadHandle, ThreadId, ThreadPriority,
78    thread_sleep, thread_yield, thread_park, thread_unpark,
79};
80
81pub use sync::{
82    WasiMutex, WasiRwLock, WasiSemaphore, WasiCondvar, WasiBarrier, WasiEvent,
83    MutexGuard, RwLockReadGuard, RwLockWriteGuard,
84};
85
86pub use collections::{
87    WasiQueue, WasiStack, WasiPriorityQueue, WasiDeque,
88};
89
90pub use pool::{
91    ThreadPool, ThreadPoolConfig, ThreadPoolBuilder, WorkResult,
92};
93
94/// Threading error types
95#[derive(Debug, thiserror::Error)]
96pub enum ThreadingError {
97    #[error("Thread spawn error: {0}")]
98    Spawn(String),
99
100    #[error("Thread join error: {0}")]
101    Join(String),
102
103    #[error("Lock poisoned: {0}")]
104    Poisoned(String),
105
106    #[error("Deadlock detected: {0}")]
107    Deadlock(String),
108
109    #[error("Timeout error: {0}")]
110    Timeout(String),
111
112    #[error("Channel closed: {0}")]
113    ChannelClosed(String),
114
115    #[error("Thread panic: {0}")]
116    Panic(String),
117
118    #[error("Invalid operation: {0}")]
119    InvalidOperation(String),
120
121    #[error("Platform not supported: {0}")]
122    PlatformNotSupported(String),
123
124    #[error("Resource exhausted: {0}")]
125    ResourceExhausted(String),
126}
127
128/// Thread-local storage key
129#[cfg(not(target_arch = "wasm32"))]
130pub struct ThreadLocal<T: Send + 'static> {
131    #[allow(dead_code)]
132    inner: std::thread::LocalKey<std::cell::RefCell<Option<T>>>,
133}
134
135/// Thread builder for advanced configuration
136pub struct ThreadBuilder {
137    name: Option<String>,
138    stack_size: Option<usize>,
139    priority: ThreadPriority,
140}
141
142impl ThreadBuilder {
143    /// Create a new thread builder
144    pub fn new() -> Self {
145        Self {
146            name: None,
147            stack_size: None,
148            priority: ThreadPriority::Normal,
149        }
150    }
151
152    /// Set the thread name
153    pub fn name(mut self, name: impl Into<String>) -> Self {
154        self.name = Some(name.into());
155        self
156    }
157
158    /// Set the stack size in bytes
159    pub fn stack_size(mut self, size: usize) -> Self {
160        self.stack_size = Some(size);
161        self
162    }
163
164    /// Set the thread priority
165    pub fn priority(mut self, priority: ThreadPriority) -> Self {
166        self.priority = priority;
167        self
168    }
169
170    /// Spawn a thread with the configured settings
171    pub fn spawn<F, T>(self, f: F) -> Result<ThreadHandle<T>>
172    where
173        F: FnOnce() -> T + Send + 'static,
174        T: Send + 'static,
175    {
176        let config = ThreadConfig {
177            name: self.name,
178            stack_size: self.stack_size,
179            priority: self.priority,
180        };
181        WasiThread::spawn_with_config(f, config)
182    }
183}
184
185impl Default for ThreadBuilder {
186    fn default() -> Self {
187        Self::new()
188    }
189}
190
191/// Global thread count (for debugging)
192#[cfg(not(target_arch = "wasm32"))]
193pub fn active_thread_count() -> usize {
194    // Platform-specific implementation
195    #[cfg(target_os = "linux")]
196    {
197        // On Linux, count threads via /proc
198        std::fs::read_dir(format!("/proc/{}/task", std::process::id()))
199            .ok()
200            .and_then(|entries| Some(entries.count()))
201            .unwrap_or(1)
202    }
203    #[cfg(not(target_os = "linux"))]
204    {
205        // Fallback: not available on all platforms
206        1
207    }
208}
209
210/// Get the current thread ID
211pub fn current_thread_id() -> ThreadId {
212    thread::current_thread_id()
213}
214
215/// Sleep for the specified duration
216pub fn sleep(duration: Duration) {
217    thread_sleep(duration)
218}
219
220/// Yield the current thread
221pub fn yield_now() {
222    thread_yield()
223}
224
225#[cfg(test)]
226mod tests {
227    use super::*;
228
229    #[test]
230    fn test_thread_builder() {
231        let builder = ThreadBuilder::new()
232            .name("test-thread")
233            .stack_size(1024 * 1024)
234            .priority(ThreadPriority::Normal);
235
236        assert_eq!(builder.name.as_ref().unwrap(), "test-thread");
237        assert_eq!(builder.stack_size, Some(1024 * 1024));
238    }
239
240    #[test]
241    #[cfg(not(target_arch = "wasm32"))]
242    fn test_current_thread_id() {
243        let id1 = current_thread_id();
244        let id2 = current_thread_id();
245        assert_eq!(id1, id2);
246    }
247
248    #[test]
249    fn test_sleep() {
250        let start = std::time::Instant::now();
251        sleep(Duration::from_millis(10));
252        let elapsed = start.elapsed();
253        assert!(elapsed >= Duration::from_millis(10));
254    }
255}