Skip to content

jmalicki-ai-slop/compio-sync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

compio-sync

Async synchronization primitives for the compio runtime.

Features

  • Semaphore: Async semaphore for bounding concurrency
    • Lock-free fast path using atomics
    • FIFO waiter queue for fairness
    • RAII permit guards for automatic cleanup
    • Compatible with compio's async runtime

Usage

Add to your Cargo.toml:

[dependencies]
compio-sync = "0.1"

Semaphore Example

use compio_sync::Semaphore;
use std::sync::Arc;

#[compio::main]
async fn main() {
    // Create semaphore with 100 permits
    let sem = Arc::new(Semaphore::new(100));
    
    // Spawn 1000 tasks, but only 100 run concurrently
    let mut handles = Vec::new();
    for i in 0..1000 {
        let sem = sem.clone();
        let handle = compio::runtime::spawn(async move {
            let _permit = sem.acquire().await;
            println!("Task {} running (max 100 concurrent)", i);
            // Permit automatically released when dropped
        });
        handles.push(handle);
    }
    
    // Wait for all tasks
    for handle in handles {
        handle.await.unwrap();
    }
}

Semaphore API

impl Semaphore {
    /// Create a new semaphore with the given number of permits
    pub fn new(permits: usize) -> Self;
    
    /// Acquire a permit, waiting asynchronously if none available
    pub async fn acquire(&self) -> SemaphorePermit;
    
    /// Try to acquire a permit without waiting
    pub fn try_acquire(&self) -> Option<SemaphorePermit>;
    
    /// Get the number of available permits
    pub fn available_permits(&self) -> usize;
    
    /// Get the maximum number of permits (configured limit)
    pub fn max_permits(&self) -> usize;
    
    /// Get the number of permits currently in use
    pub fn in_use(&self) -> usize;
}

Design

The semaphore uses a two-tier approach for optimal performance:

  1. Fast Path (Lock-Free): When permits are available, acquisition uses atomic compare-and-swap operations with no mutex locking
  2. Slow Path (Mutex-Protected): When no permits are available, tasks register their waker in a FIFO queue and wait for notification

This design minimizes contention while providing fair scheduling.

Use Cases

  • Bounding Concurrency: Limit the number of concurrent file operations
  • Resource Protection: Prevent file descriptor or memory exhaustion
  • Backpressure: Pause discovery when processing is saturated
  • Rate Limiting: Control operation throughput

Comparison with Tokio

This semaphore is inspired by tokio::sync::Semaphore but built specifically for the compio runtime:

Feature tokio::sync::Semaphore compio-sync::Semaphore
Runtime Tokio Compio
Lock-free fast path
FIFO fairness
RAII permits
Async acquire
Try acquire

Development & Research

Lock-Free Wakeup Research

We are actively researching and planning to eliminate mutexes from our synchronization primitives to achieve truly lock-free async wakeups. This work is documented in the docs/ directory:

Planned Improvements

Phase 1: parking_lot + AtomicWaker (1-2 days)

  • Replace std::sync::Mutex with parking_lot::Mutex
  • Add AtomicWaker fast path for single-waiter scenarios
  • Expected: 20-30% performance improvement

Phase 2: crossbeam Lock-Free Queue (1 week)

  • Replace mutex-based queue with crossbeam-queue::SegQueue
  • True lock-free operation
  • Expected: 40-60% performance improvement

Phase 3: Intrusive Lists (Optional, 3-4 weeks)

  • Tokio-style intrusive linked lists
  • Zero allocations, maximum performance
  • Only if Phase 2 isn't sufficient

See the research docs for detailed analysis and trade-offs.

CI Matrix

Our CI tests across multiple platforms to ensure compatibility and performance:

Platform Purpose Implementation
Ubuntu 24.04 Modern Linux (kernel 6.11) io_uring futex integration
Ubuntu 22.04 Older Linux (kernel 5.15) Generic fallback (parking_lot)
Windows 2022 Modern Windows IOCP event integration (planned)
macOS 14 macOS Generic fallback (parking_lot)

Platform-Specific Features

  • Linux: Uses io_uring futex operations for unified event loop
  • Windows: Will use IOCP events for unified event loop (Phase 3)
  • macOS: Uses generic fallback (kqueue could be added in future)
  • Fallback: Generic implementation using parking_lot + AtomicWaker

Testing Limitations

Windows 7 Support: While compio-sync is designed to work on older Windows versions (including Windows 7), we cannot test this in CI due to GitHub Actions limitations. GitHub Actions only provides:

  • windows-latest (Windows Server 2022)
  • windows-2019 (Windows Server 2019)
  • windows-2016 (Windows Server 2016)

Legacy Windows Testing: For Windows 7 and other legacy versions, the library will use the generic fallback implementation (parking_lot + AtomicWaker). This provides good performance while maintaining compatibility with older systems.

Development

Pre-commit Hook

This repository includes a pre-commit hook that automatically formats and lints code before commits. To install it:

# Install the pre-commit hook
./scripts/install-pre-commit.sh

The hook will:

  • Format all Rust code with cargo fmt
  • Run clippy lints with strict settings
  • Run all tests to ensure nothing is broken

Code Quality

All code must pass:

  • cargo fmt --all (formatting)
  • cargo clippy --all-targets --all-features -- -D warnings (linting)
  • cargo test --all-targets (testing)

Contributing

Contributions are welcome! Please see:

License

MIT

About

Async synchronization primitives for compio runtime

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •