Skip to content

Conversation

@ryanbreen
Copy link
Owner

@ryanbreen ryanbreen commented Dec 15, 2025

Summary

This PR adds foundational IPC and networking capabilities to Breenix:

  • POSIX Signal Handling: Full signal infrastructure including signal delivery, sigaction, sigreturn, and register preservation
  • Pipe IPC: pipe() and close() syscalls with proper fd management
  • UDP Sockets: socket(), bind(), sendto(), recvfrom() with loopback support
  • Unified FdTable: Consolidated file descriptor management across all IPC types
  • Network Stack: ARP resolution, ICMP, UDP protocols with E1000 driver

Key Changes

Signals (currently disabled due to QEMU 8.2.2 bug)

  • Signal delivery from kernel to userspace
  • sigaction() for registering handlers
  • sigreturn() for returning from handlers
  • Full register save/restore on signal frames

Pipe IPC

  • pipe() creates read/write fd pair
  • close() handles all fd types properly
  • Shared buffer with Arc<Mutex<>> for future fork support

UDP Sockets

  • Full syscall implementation
  • Loopback delivery with deferred queue (prevents deadlock)
  • Integration with E1000 network driver

Architecture Improvements

  • FdTable unified in ipc/fd.rs (was duplicated in socket/mod.rs)
  • Consistent Arc<Mutex<>> pattern for all shareable resources
  • Lock ordering fixes to prevent deadlocks

Test plan

  • All 76 boot stages pass
  • Build clean with zero warnings
  • UDP loopback test validates send/receive path
  • Pipe test validates read/write/close
  • Signal tests disabled pending QEMU fix (documented in commit 47e2232)

🤖 Generated with Claude Code


Note

Introduce unified IPC with pipes and close syscalls, refactor per-CPU/TSS stack handling, and update networking, syscalls, userspace wrappers, and tests to use the new FD model.

  • IPC:
    • Unified FD model: Add ipc/ module with fd.rs (FdTable, FdKind) consolidating stdio, pipes, and UDP sockets; remove old FD table from socket/mod.rs.
    • Pipes: Implement PipeBuffer (ipc/pipe.rs) and create_pipe(). Add syscalls sys_pipe and sys_close; wire in dispatcher/handler. Extend sys_read/sys_write to support pipe ends.
    • Userspace: Add libbreenix::io::{pipe, close}; new pipe_test binary and build integration.
  • Networking:
    • Update UDP delivery to use ipc::fd::{FdKind, MAX_FDS} and lock UdpSocket via Arc<Mutex<...>>. Adjust socket syscalls to the new FD model.
  • Kernel core / scheduling:
    • Refactor per_cpu::PerCpuData: switch cpu_id and kernel_stack_top to u64, change exception_cleanup_context to u8, add switch diagnostics (canaries, TSC, counters), assert new size. Change APIs: kernel_stack_top()/set_kernel_stack_top()/update_tss_rsp0() now use u64.
    • Update all call sites (main.rs, interrupts/context_switch.rs, test_userspace.rs) to pass as_u64() and set TSS.RSP0 accordingly.
  • Syscall infra:
    • Add syscall numbers for Pipe and Close; route in dispatcher.rs and handler.rs. Relax copy_to_user to avoid manager lock; extend read/write path for pipes and stdio.
  • Process:
    • Use new ipc::FdTable in process::Process; adjust creation path to avoid disabling interrupts to prevent deadlocks.
  • Tooling/Tests:
    • Include pipe_test in userspace Cargo/build script; xtask adds boot-stage check for PIPE_TEST_PASSED.

Written by Cursor Bugbot for commit 97480a3. This will update automatically on new commits. Configure here.

ryanbreen and others added 3 commits December 12, 2025 08:52
This commit adds POSIX-style pipe support to Breenix:

Kernel infrastructure:
- kernel/src/ipc/fd.rs: FdTable with heap-allocated fd array (avoids
  stack overflow), FdKind enum for StdIo/PipeRead/PipeWrite
- kernel/src/ipc/pipe.rs: PipeBuffer with 64KB circular buffer,
  reader/writer tracking for EOF/broken pipe detection
- kernel/src/syscall/pipe.rs: sys_pipe() and sys_close() implementations

Syscall integration:
- Added Close (6) and Pipe (22) syscall numbers
- Updated sys_read/sys_write to route through FdTable for pipe support
- Added FdTable to Process struct for per-process file descriptors

Userspace support:
- libs/libbreenix: Added pipe() and close() wrappers
- userspace/tests/pipe_test.rs: End-to-end test for pipe IPC

The FdTable uses Box to heap-allocate its 256-entry fd array, preventing
stack overflow during process creation (the array is ~6KB).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pipe_test binary to userspace/tests Cargo.toml and build.sh
- Add test_pipe() function in kernel/src/test_exec.rs to load and
  run the pipe_test binary during boot
- Add call to test_pipe() in kernel/src/main.rs test sequence
- Add PIPE_TEST_PASSED boot stage marker in xtask/src/main.rs
- Update pipe_test.rs to emit boot stage marker

The pipe test validates:
- pipe() syscall creates valid file descriptors
- Writing to pipe write end succeeds
- Reading from pipe read end retrieves correct data
- close() syscall properly closes pipe file descriptors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move FdTable from socket/mod.rs to ipc/fd.rs (proper layer)
- Change UdpSocket to Arc<Mutex<>> pattern (matches pipes)
- Remove without_interrupts from process creation (prevents deadlock)
- Simplify copy_to_user (no PROCESS_MANAGER lock needed)
- Add per-CPU context switch diagnostic fields

All 76 boot stages pass. Build clean with zero warnings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ryanbreen ryanbreen merged commit 327a0de into main Dec 15, 2025
2 checks passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

}
}
Err(24) // EMFILE
}
Copy link

Choose a reason for hiding this comment

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

Bug: Pipe reference counts not updated during dup/clone operations

The dup(), dup2(), and FdTable::clone() implementations clone the Arc<Mutex<PipeBuffer>> but don't increment the readers/writers counts inside PipeBuffer. These counts are used to detect EOF (writers=0) and broken pipe (readers=0). When a pipe fd is duplicated and then the original is closed via sys_close (which calls close_read()/close_write()), the count drops to 0 even though a valid fd still exists. This causes incorrect EPIPE errors on write or premature EOF on read. Additionally, dup2 discards the result of closing new_fd with let _ = ..., which skips the cleanup logic in sys_close that decrements pipe reference counts.

Additional Locations (2)

Fix in Cursor Fix in Web

log::debug!("sys_close: Closed UDP socket fd={}, unbound port {}", fd, port);
} else {
log::debug!("sys_close: Closed unbound UDP socket fd={}", fd);
}
Copy link

Choose a reason for hiding this comment

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

Bug: UDP socket unbinds prematurely when fd is closed

The sys_close implementation for UDP sockets explicitly calls unbind_udp() when a file descriptor is closed. However, with the new Arc<Mutex<UdpSocket>> design that enables socket sharing via dup/fork, this is incorrect. If two file descriptors reference the same socket and one is closed, the socket gets unbound while the other fd is still valid. The UdpSocket::Drop implementation already handles unbinding when the last reference is released, so the explicit unbind in sys_close should be removed to allow shared sockets to remain bound until all references are closed.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants