I am developing a custom x86 hobbyist kernel called MagicBox. I've reached a point where I can run BusyBox (ash & vi) via musl-libc, but I am encountering a specific synchronization issue with vi.
The Symptom
- In ash: Interactive commands work as expected.
- In vi:
- The editor starts and renders the file content or the empty buffer correctly.
- Commands like :q work fine if entered immediately after startup.
- The Issue: Any other input (e.g., pressing a, i, or arrow keys) causes vi to stop responding. sys_read() captures the characters, but vi never issues a subsequent sys_write() or sys_writev() to refresh the terminal.
1. The "Stub" Poll
Currently, my poll() implementation is a synchronous "stub" to satisfy BusyBox requirements:
Code: Select all
// Simplified logic
static int32_t do_poll(struct pollfd* fds, uint32_t nfds) {
for (uint32_t i = 0; i < nfds; i++) {
if (fds[i].fd <= 2) { // TTY FDs
fds[i].revents = fds[i].events; // Faking "always ready"
}
}
return (int32_t)nfds; // Returns immediately without blocking
}
2. Semaphore-based TTY Read
My TTY driver uses a semaphore (line_sem) for synchronization:
- Input Handler: In non-canonical mode, every received byte calls sema_signal(&line_sem).
- TTY Read: It performs a sema_wait(&line_sem) and then enters a while loop to try and fill the user-requested count from the ring buffer.
I have implemented TCGETS, TCSETS, TIOCGPGRP, and TIOCSPGRP. vi seems to successfully switch the terminal to non-canonical mode.
My Hypotheses
I suspect the issue lies in the interaction between my "fake" poll() and the blocking read():
- Desync: poll() claims data is ready. vi enters read(). If read() tries to fill a large count but the buffer only has 1 byte, my current loop might be causing an unintended block.
- POSIX Semantics: My implementation lacks strict VMIN/VTIME logic. I suspect vi's state machine relies on poll() timing out to trigger UI refreshes, which my current poll() doesn't support.
I would appreciate any advice on:
- Is a proper Wait Queue implementation for poll mandatory for editors like vi to function?
- Does the semaphore-based "one signal per byte" approach fundamentally break stream-oriented programs?
- POSIX Compliance in TTY: Since my current TTY implementation is quite "lazy," should I prioritize a more strict adherence to POSIX TTY semantics (e.g., proper termios line discipline) to support complex editors? Specifically, I suspect my lack of VMIN/VTIME handling is a major blocker.
Thanks in advance for any insights!

