Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
11e31ae
Trampoline format: redzone reservation, R11 restart, RIP-relative re-…
wdcui Apr 2, 2026
8b5a4ba
Fix CI: 32-bit build, Windows redzone callback, rustfmt
wdcui Apr 2, 2026
aa7dd83
Runtime ELF patching and rtld_audit removal
wdcui Apr 2, 2026
6620fc7
Fix Windows CI: suppress dead_code warning for syscall_callback extern
wdcui Apr 2, 2026
e50aa0a
Fix Windows CI: remove rtld_audit.so from Windows test (incompatible …
wdcui Apr 2, 2026
9729fed
Windows: preserve guest R11 across syscall callback via TEB.Arbitrary…
wdcui Apr 2, 2026
cc10a9a
Remove rtld_audit, fix RFLAGS on Windows, simplify callback dispatch,…
wdcui Apr 2, 2026
bfa1587
Clean up rewriter: remove unit tests, revert bun footer to suffix che…
wdcui Apr 3, 2026
8bd36f4
Fix signal handler to check both callback entry points, add short-rea…
wdcui Apr 3, 2026
35d845d
Fix integration tests: replace OUT_DIR with CARGO_TARGET_TMPDIR
wdcui Apr 3, 2026
e8561c8
Cross-platform packager: remove Linux-only gates, add OCI symlink res…
wdcui Apr 3, 2026
5c35d84
Fix OCI whiteout symlink pruning and degenerate symlink target resolu…
wdcui Apr 3, 2026
1eec9f3
Remove no-op build.rs from litebox_packager (rtld_audit fully removed)
wdcui Apr 3, 2026
41d4da7
Preserve tar header permissions for cross-platform OCI extraction
wdcui Apr 3, 2026
d880f73
Prune dead observers on registration
wdcui Apr 7, 2026
6c425be
Add Clone support to AnyMap via type-erased clone functions
wdcui Apr 7, 2026
8adb37c
Add needs_host_poll() and should_block_read() to IOPollable
wdcui Apr 7, 2026
5dedca6
Add noreserve parameter to allocate_pages and fix copy_pages chunk le…
wdcui Apr 7, 2026
7c4d62e
Misc cleanup: pub(crate) mock fields, log_println allow, current_proc…
wdcui Apr 7, 2026
eedd3b9
Add RawMessageProvider trait and expand SendError/ReceiveError variants
wdcui Apr 7, 2026
88a6274
Expand StdioProvider with terminal types and nonblocking stdin
wdcui Apr 7, 2026
9585932
Add AddressSpaceProvider trait for multi-process address space manage…
wdcui Apr 7, 2026
7794e90
Add address_space_id parameter to futex wait/wake for multi-process s…
wdcui Apr 7, 2026
870206f
Add trace_fs feature gate for conditional DebugLogProvider bound
wdcui Apr 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,20 @@ jobs:
tool: nextest@${{ env.NEXTEST_VERSION }}
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --locked --verbose --all-targets --all-features -p litebox_runner_linux_on_windows_userland
- run: cargo clippy --locked --verbose --all-targets --all-features -p litebox_packager
- run: cargo build --locked --verbose -p litebox_runner_linux_on_windows_userland
- run: cargo build --locked --verbose -p litebox_packager
- run: cargo nextest run --locked --profile ci -p litebox_runner_linux_on_windows_userland
- run: cargo nextest run --locked --profile ci -p litebox_packager
- run: cargo nextest run --locked --profile ci -p litebox_shim_linux --no-default-features --features platform_windows_userland
- run: |
cargo test --locked --verbose --doc -p litebox_runner_linux_on_windows_userland
cargo test --locked --verbose --doc -p litebox_packager
# We need to run `cargo test --doc` separately because doc tests
# aren't included in nextest at the moment. See relevant discussion at
# https://github.com/nextest-rs/nextest/issues/16
- name: Build documentation (fail on warnings)
run: cargo doc --locked --verbose --no-deps --all-features --document-private-items -p litebox_runner_linux_on_windows_userland
run: cargo doc --locked --verbose --no-deps --all-features --document-private-items -p litebox_runner_linux_on_windows_userland -p litebox_packager

build_and_test_snp:
name: Build and Test SNP
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dev_bench/unixbench/prepare_unixbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ def prepare_benchmark(
"""
Prepare a single benchmark using litebox_packager.

The packager discovers dependencies, rewrites all ELFs, and creates a tar
(including litebox_rtld_audit.so). The rewritten main binary is extracted
The packager discovers dependencies, rewrites all ELFs, and creates a tar.
The rewritten main binary is extracted
from the tar and placed alongside it.

Returns True on success.
Expand Down
1 change: 0 additions & 1 deletion dev_tests/src/boilerplate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ const SKIP_FILES: &[&str] = &[
"LICENSE",
"litebox/src/sync/mutex.rs",
"litebox/src/sync/rwlock.rs",
"litebox_rtld_audit/Makefile",
"litebox_runner_linux_on_windows_userland/tests/test-bins/hello_exec_nolibc",
"litebox_runner_linux_on_windows_userland/tests/test-bins/hello_thread",
"litebox_runner_linux_on_windows_userland/tests/test-bins/hello_thread_static",
Expand Down
1 change: 0 additions & 1 deletion dev_tests/src/ratchet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ fn ratchet_globals() -> Result<()> {
("litebox_platform_lvbs/", 23),
("litebox_platform_multiplex/", 1),
("litebox_platform_windows_userland/", 8),
("litebox_runner_linux_userland/", 1),
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 1),
("litebox_shim_linux/", 1),
Expand Down
1 change: 1 addition & 0 deletions litebox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ windows-sys = { version = "0.60.2", features = [

[features]
lock_tracing = ["dep:arrayvec", "spin/mutex"]
trace_fs = []
panic_on_unclosed_fd_drop = []
enforce_singleton_litebox_instance = []

Expand Down
29 changes: 29 additions & 0 deletions litebox/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,29 @@ pub trait IOPollable {
/// calls are what notify observers. This particular function itself however _may_ be used to
/// essentially get "the current status" of events for the system.
fn check_io_events(&self) -> Events;

/// Returns `true` if this pollable cannot deliver asynchronous observer
/// notifications (e.g. host-backed stdin where the host has no callback
/// mechanism). Callers should use periodic polling instead of blocking
/// indefinitely on observer wakeups.
///
/// Defaults to `false` (async notifications work). This is safe for all
/// existing implementors; callers that use this method arrive in subsequent
/// stacked PRs.
fn needs_host_poll(&self) -> bool {
false
}

/// Returns `true` if reads on this pollable should block when no data is
/// available. Returns `false` for pollables whose callers perform
/// asynchronous readiness checks and expect a "would block" indication
/// immediately (e.g. PTY master side).
///
/// Defaults to `true` (blocking reads). This is safe for all existing
/// implementors; callers arrive in subsequent stacked PRs.
fn should_block_read(&self) -> bool {
true
}
}

impl<T: IOPollable> IOPollable for alloc::sync::Arc<T> {
Expand All @@ -61,4 +84,10 @@ impl<T: IOPollable> IOPollable for alloc::sync::Arc<T> {
fn check_io_events(&self) -> Events {
self.as_ref().check_io_events()
}
fn needs_host_poll(&self) -> bool {
self.as_ref().needs_host_poll()
}
fn should_block_read(&self) -> bool {
self.as_ref().should_block_read()
}
}
86 changes: 77 additions & 9 deletions litebox/src/event/observer.rs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes should be factored out into a separate PR, they are orthogonal to the rest of the changes here.

Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,28 @@ impl<E, F: EventsFilter<E>, Platform: RawSyncPrimitivesProvider> Subject<E, F, P
}
}

/// Remove entries whose weak references are no longer alive, decrementing
/// `nums` for each pruned entry.
///
/// Called under the lock during registration to eagerly reclaim stale
/// entries from observers that were dropped without being explicitly
/// unregistered. `notify_observers` also calls this to prune before
/// dispatching events.
fn prune_dead_observers(&self, observers: &mut BTreeMap<ObserverKey<E>, F>) {
observers.retain(|observer, _| {
if observer.upgrade().is_some() {
true
} else {
self.nums.fetch_sub(1, Ordering::Relaxed);
false
}
});
}

/// Register an observer with the given filter.
pub fn register_observer(&self, observer: Weak<dyn Observer<E>>, filter: F) {
let mut observers = self.observers.lock();
self.prune_dead_observers(&mut observers);
if observers
.insert(ObserverKey::new(observer), filter)
.is_none()
Expand All @@ -119,16 +138,65 @@ impl<E, F: EventsFilter<E>, Platform: RawSyncPrimitivesProvider> Subject<E, F, P
}

let mut observers = self.observers.lock();
observers.retain(|observer, filter| {
if let Some(observer) = observer.upgrade() {
if filter.filter(&events) {
observer.on_events(&events);
}
true
} else {
self.nums.fetch_sub(1, Ordering::Relaxed);
false
self.prune_dead_observers(&mut observers);
for (observer, filter) in observers.iter() {
if let Some(observer) = observer.upgrade()
&& filter.filter(&events)
{
observer.on_events(&events);
}
}
}
}

#[cfg(test)]
mod tests {
use alloc::sync::Arc;
use core::sync::atomic::{AtomicUsize, Ordering};

use super::{Observer, Subject};
use crate::{event::Events, platform::mock::MockPlatform};

struct TestObserver {
notifications: AtomicUsize,
}

impl Observer<Events> for TestObserver {
fn on_events(&self, _events: &Events) {
self.notifications.fetch_add(1, Ordering::Relaxed);
}
}

#[test]
fn register_observer_prunes_dead_entries() {
let subject = Subject::<Events, Events, MockPlatform>::new();

let stale = Arc::new(TestObserver {
notifications: AtomicUsize::new(0),
});
subject.register_observer(Arc::downgrade(&stale) as _, Events::IN);
assert_eq!(subject.nums.load(Ordering::Relaxed), 1);
assert_eq!(subject.observers.lock().len(), 1);
drop(stale);

let fresh = Arc::new(TestObserver {
notifications: AtomicUsize::new(0),
});
subject.register_observer(Arc::downgrade(&fresh) as _, Events::OUT);
{
let observers = subject.observers.lock();
let registered = observers
.keys()
.next()
.and_then(super::ObserverKey::upgrade)
.expect("dead observer should be pruned during registration");
let fresh_observer: Arc<dyn Observer<Events>> = fresh.clone();
assert!(Arc::ptr_eq(&registered, &fresh_observer));
assert_eq!(subject.nums.load(Ordering::Relaxed), 1);
assert_eq!(observers.len(), 1);
}
subject.notify_observers(Events::OUT);

assert_eq!(fresh.notifications.load(Ordering::Relaxed), 1);
}
}
4 changes: 2 additions & 2 deletions litebox/src/fd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ impl<Platform: RawSyncPrimitivesProvider> Descriptors<Platform> {
) -> Option<T>
where
Subsystem: FdEnabledSubsystem,
T: core::any::Any + Send + Sync,
T: core::any::Any + Clone + Send + Sync,
{
self.entries[fd.x.as_usize()?]
.as_ref()
Expand Down Expand Up @@ -506,7 +506,7 @@ impl<Platform: RawSyncPrimitivesProvider> Descriptors<Platform> {
) -> Option<T>
where
Subsystem: FdEnabledSubsystem,
T: core::any::Any + Send + Sync,
T: core::any::Any + Clone + Send + Sync,
{
self.entries[fd.x.as_usize()?]
.as_mut()
Expand Down
2 changes: 1 addition & 1 deletion litebox/src/fd/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use alloc::string::ToString as _;
use alloc::vec;
use alloc::vec::Vec;

use crate::LiteBox;
use crate::fd::FdEnabledSubsystemEntry;
use crate::fd::{ErrRawIntFd, FdEnabledSubsystem, TypedFd};
use crate::platform::mock::MockPlatform;
use crate::LiteBox;

struct MockSubsystem;
impl FdEnabledSubsystem for MockSubsystem {
Expand Down
13 changes: 7 additions & 6 deletions litebox/src/fs/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
use alloc::string::String;

use crate::{
LiteBox,
fs::{
FileStatus, FileType, Mode, NodeInfo, OFlags, SeekWhence, UserInfo,
errors::{
ChmodError, ChownError, CloseError, FileStatusError, MkdirError, OpenError, PathError,
ReadDirError, ReadError, RmdirError, SeekError, TruncateError, UnlinkError, WriteError,
},
FileStatus, FileType, Mode, NodeInfo, OFlags, SeekWhence, UserInfo,
},
path::Arg,
platform::{StdioOutStream, StdioReadError, StdioWriteError},
LiteBox,
};

/// Block size for stdio devices
Expand Down Expand Up @@ -145,10 +145,10 @@ impl<Platform: crate::sync::RawSyncPrimitivesProvider + crate::platform::StdioPr
}

impl<
Platform: crate::sync::RawSyncPrimitivesProvider
+ crate::platform::StdioProvider
+ crate::platform::CrngProvider,
> super::FileSystem for FileSystem<Platform>
Platform: crate::sync::RawSyncPrimitivesProvider
+ crate::platform::StdioProvider
+ crate::platform::CrngProvider,
> super::FileSystem for FileSystem<Platform>
{
fn open(
&self,
Expand Down Expand Up @@ -254,6 +254,7 @@ impl<
.read_from_stdin(buf)
.map_err(|e| match e {
StdioReadError::Closed => unimplemented!(),
StdioReadError::WouldBlock => unimplemented!(),
})
}

Expand Down
5 changes: 3 additions & 2 deletions litebox/src/mm/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ use alloc::vec::Vec;
use rangemap::RangeMap;
use thiserror::Error;

use crate::platform::PageManagementProvider;
use crate::platform::RawConstPointer;
use crate::platform::page_mgmt::AllocationError;
use crate::platform::page_mgmt::FixedAddressBehavior;
use crate::platform::page_mgmt::MemoryRegionPermissions;
use crate::platform::PageManagementProvider;
use crate::platform::RawConstPointer;

/// Page size in bytes
pub const PAGE_SIZE: usize = 4096;
Expand Down Expand Up @@ -509,6 +509,7 @@ impl<Platform: PageManagementProvider<ALIGN> + 'static, const ALIGN: usize> Vmem
MemoryRegionPermissions::from_bits(permissions).unwrap(),
vma.flags.contains(VmFlags::VM_GROWSDOWN),
populate_pages_immediately,
false,
platform_fixed_address_behavior,
)
.map_err(|err| match err {
Expand Down
Loading