Skip to content

Conversation

@ryanbreen
Copy link
Owner

Summary

  • Implement proper blocking for FIFO read operations with HLT loop
  • Fix critical lock contention bug that prevented context switches during blocking
  • Add read_waiters tracking to PipeBuffer for wake-on-data notifications
  • Wake blocked readers when data is written or all writers close (EOF)

Problem

Phase 7 of the FIFO tests (blocking read with fork) was failing because:

  1. Parent process blocked on FIFO read while holding process manager lock
  2. Timer interrupts tried to context switch to child process
  3. Context switch failed: "Could not acquire process manager lock to restore context"
  4. Child never executed, never wrote data, parent blocked forever

Solution

Drop the process manager lock before entering blocking paths:

FdKind::FifoRead(_path, pipe_buffer) => {
    let pipe_buffer_clone = pipe_buffer.clone();
    drop(manager_guard);  // CRITICAL: Release lock before blocking!
    // ... blocking loop ...
}

The blocking implementation follows the established TCP double-check pattern:

  1. Register as waiter BEFORE setting blocked state (race fix)
  2. Block thread and set blocked_in_syscall flag
  3. Double-check for data arrival (race condition fix)
  4. HLT loop until woken
  5. Retry read after wake

Test Results

All 10 FIFO test phases now pass:

  • Phase 1-6: Basic FIFO operations
  • Phase 7: Blocking read with fork (was failing)
  • Phase 8: EOF test (reader gets 0 when writer closes)
  • Phase 9: EPIPE test (write fails when reader closes)
  • Phase 10: Unlink FIFO while open

Files Changed

  • kernel/src/ipc/pipe.rs - Add read_waiters tracking and wake mechanism
  • kernel/src/ipc/fifo.rs - Add without_interrupts wrappers for lock safety
  • kernel/src/syscall/fs.rs - FIFO open blocking implementation
  • kernel/src/syscall/handlers.rs - FIFO read/write blocking with proper lock release

🤖 Generated with Claude Code

ryanbreen and others added 3 commits January 24, 2026 11:22
Add FIFO (named pipe) support to Breenix, enabling unrelated processes
to communicate through filesystem paths.

Key features:
- mkfifo syscall (mknod with S_IFIFO mode) creates named pipes
- FIFO registry tracks active named pipes by path
- Open semantics follow POSIX: readers block until writer opens (and vice versa)
- O_NONBLOCK support for non-blocking opens (EAGAIN/ENXIO)
- FIFOs reuse the existing PipeBuffer for data transfer
- Proper cleanup when file descriptors are closed

Implementation:
- kernel/src/ipc/fifo.rs: FIFO registry and FifoEntry management
- kernel/src/syscall/fifo.rs: sys_mkfifo syscall handler
- kernel/src/syscall/fs.rs: handle_fifo_open() for open() on FIFOs
- FdKind::FifoRead/FifoWrite variants for FIFO file descriptors
- Poll support for FIFO read/write ends
- libbreenix::fs::mkfifo() userspace wrapper

Test coverage (fifo_test.rs):
- Phase 1: Basic create/open/close/write/read
- Phase 2: EEXIST on duplicate mkfifo
- Phase 3: ENOENT on opening non-existent FIFO
- Phase 4: ENXIO on O_NONBLOCK write without reader
- Phase 5: EAGAIN on O_NONBLOCK read from empty FIFO
- Phase 6: Multiple writes and reads
- Phase 7: Unlink while FIFO is open

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address validation review feedback:
- Phase 7: Blocking read test using fork - parent blocks on open until
  child opens writer, verifying blocking semantics work correctly
- Phase 8: EOF test - reader gets 0 when all writers close
- Phase 9: EPIPE test - write fails when all readers close
- Phase 10: Unlink while open (renumbered from Phase 7)

These tests cover the critical POSIX semantics that were previously
untested due to all tests using O_NONBLOCK.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Key changes:
- Add read_waiters tracking to PipeBuffer for wake-on-data notifications
- Implement blocking read for FIFO with HLT loop (following TCP pattern)
- Drop process manager lock before entering blocking paths to prevent
  context switch deadlocks
- Wake blocked readers when data is written or EOF (all writers close)

The blocking implementation follows the double-check pattern:
1. Register as waiter before setting blocked state
2. Block thread and set blocked_in_syscall flag
3. Double-check for data (race condition fix)
4. HLT loop until woken
5. Retry read after wake

This fixes the lock contention issue where child processes couldn't
execute because the parent held the manager lock while blocked.

All 10 FIFO test phases now pass:
- Phase 1-6: Basic FIFO operations
- Phase 7: Blocking read with fork (was failing due to lock contention)
- Phase 8-10: EOF, EPIPE, and unlink tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ryanbreen ryanbreen merged commit 83834c3 into main Jan 24, 2026
2 checks passed
@ryanbreen ryanbreen deleted the test/fifo-isolated branch January 24, 2026 18:40
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