mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
The visible goal was a Web app: type a URL, see the page, fetched over the TCP stack SUB-OS built. Getting there surfaced -- and forced fixes to -- two deeper problems. Async HTTP client (net/http_client.c) tcp_connect/recv all block, so fetching from the GUI would freeze the compositor. Fetches now run on one long-lived kernel worker thread that services a single-slot mailbox; the requester posts a job and polls its state. Ownership follows the state, and the two hand-off points (worker completion, requester release) run under interrupts-off, so a window can close mid-fetch with neither leak nor use-after-free. do_fetch returns its terminal state rather than publishing it, closing a window where the requester could free the job before finalize read it. Cooperative scheduling for the idle thread (the core fix) The login prompt, the shell and the GUI compositor all run on the pid-0 idle thread, which the scheduler by design never preempts (sched_tick skips pid 0) and never requeues on a yield (weave_on clear). So it could neither be preempted to let the worker run, nor cleanly yield -- the worker was simply starved, and an early attempt to yield from it froze the shell outright. The idle thread now joins the weave rotation once hardware interrupts are live, and the network wait loops (tcp, dns, ping, the worker's idle) yield through a new net_wait() instead of halting the CPU. The compositor spends its frame-budget slack yielding too. Result: a background fetch progresses while the desktop holds 54 FPS. Web app (gui/gui_app_web.c) A text browser: URL bar, Go, and a Raw/Reader toggle. Raw shows the response verbatim; Reader strips markup (dropping <script>/<style> bodies), decodes the common entities, and word-wraps the body. The line index is cached against content/view/width so scrolling and idle repaints are free. It only ever polls the worker, so it never stalls. TCP throughput (the limit flagged last time) The 32-slot table with a 2 s TIME_WAIT linger capped sustained serving at ~16 req/s. The table is now 64 slots, a connection this end closed after serving a request lingers 250 ms rather than 2 s, and expired TIME_WAIT entries are reaped from the count path so a quiet table still drains. netstat/netmon gained served-since-boot and peak-slots counters. Also: a `webget` CLI (the async client from a shell), listen/accept introspection already present, and a globe icon for the app. Verified on x86_64: `webget` fetched an 812-byte page (HTTP 200, 10 ms) on the worker thread; the GUI Web app rendered the same page in Reader mode while the desktop held 54 FPS; an 80-request burst through the 64-slot table returned 80/80 (was 39/40 before) and netstat reported "80 served, peak 33 of 64 slots" -- a peak that would have overflowed the old table. Builds clean on x86_64, aarch64 and armv8i. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
430 lines
14 KiB
C
430 lines
14 KiB
C
#include <kernel/kernel.h>
|
|
#include <kernel/printk.h>
|
|
#include <kernel/sched.h>
|
|
#include <kernel/task.h>
|
|
#include <kernel/signal.h>
|
|
#include <kernel/syscall.h>
|
|
#include <kernel/timer.h>
|
|
#include <kernel/workqueue.h>
|
|
#include <kernel/module.h>
|
|
#include <kernel/nt/ob.h>
|
|
#include <kernel/nt/reg.h>
|
|
#include <kernel/nt/io.h>
|
|
#include <kernel/trace.h>
|
|
#include <kernel/namespace.h>
|
|
#include <kernel/syslog.h>
|
|
#include <kernel/cron.h>
|
|
#include <kernel/metrics.h>
|
|
#include <kernel/bpf.h>
|
|
#include <kernel/kobject.h>
|
|
#include <kernel/wait.h>
|
|
#include <kernel/futex.h>
|
|
#include <kernel/rcu.h>
|
|
#include <kernel/ktest.h>
|
|
#include <mm/page_cache.h>
|
|
#include <mm/vma.h>
|
|
#include <drivers/canvas.h>
|
|
#include <drivers/pty.h>
|
|
#include <arch/arch.h>
|
|
#include <mm/pmm.h>
|
|
#include <mm/kmalloc.h>
|
|
#include <mm/slab.h>
|
|
#include <drivers/tty.h>
|
|
#include <drivers/serial.h>
|
|
#include <drivers/keyboard.h>
|
|
#include <drivers/mouse.h>
|
|
#include <drivers/ata.h>
|
|
#include <drivers/ahci.h>
|
|
#include <drivers/nvme.h>
|
|
#include <drivers/bochs.h>
|
|
#include <drivers/virtio_blk.h>
|
|
#include <drivers/virtio_net.h>
|
|
#include <drivers/virtio_rng.h>
|
|
#include <drivers/hwmon.h>
|
|
#include <drivers/pci.h>
|
|
#include <drivers/e1000.h>
|
|
#include <drivers/rtl8139.h>
|
|
#include <drivers/speaker.h>
|
|
#include <drivers/fb.h>
|
|
#include <drivers/rtc.h>
|
|
#include <drivers/acpi.h>
|
|
#include <drivers/usb.h>
|
|
#include <drivers/xhci.h>
|
|
#include <drivers/ramdisk.h>
|
|
#include <block/block.h>
|
|
#include <ipc/ipc.h>
|
|
#include <sound/sound.h>
|
|
#include <sound/hda.h>
|
|
#include <sound/melody.h>
|
|
#include <fs/vfs.h>
|
|
#include <fs/fat32.h>
|
|
#include <fs/ext2.h>
|
|
#include <fs/sysfs.h>
|
|
#include <net/net.h>
|
|
#include <net/socket.h>
|
|
#include <net/udp.h>
|
|
#include <net/tcp.h>
|
|
#include <net/dhcp.h>
|
|
#include <net/dns.h>
|
|
#include <net/http_client.h>
|
|
#include <net/dns_cache.h>
|
|
#include <ipc/shm_posix.h>
|
|
#include <sound/beep.h>
|
|
#include <kernel/tsc.h>
|
|
#include <drivers/e1000e.h>
|
|
#include <drivers/virtio_gpu.h>
|
|
#include <drivers/cpufreq.h>
|
|
#include <drivers/hpet.h>
|
|
#include <drivers/nvram.h>
|
|
#include <drivers/lpt.h>
|
|
#include <kernel/ktime.h>
|
|
#include <drivers/virtio_input.h>
|
|
#include <gui/gui.h>
|
|
#include <init/init.h>
|
|
#include <kernel/rust.h>
|
|
#include <kernel/sub_lang.h>
|
|
#include <kernel/cpp_kernel.h>
|
|
#include <kernel/cpp_analytics.h>
|
|
#include <net/filter.h>
|
|
#include <net/http.h>
|
|
#include <net/ssh.h>
|
|
#include <crypto/crypto.h>
|
|
#include <certs/certs.h>
|
|
#include <security/security.h>
|
|
#include <security/auth.h>
|
|
#include <io_uring/io_uring.h>
|
|
#include <usr/initramfs.h>
|
|
#include <virt/virt.h>
|
|
#include <init/init.h>
|
|
#include <init/service.h>
|
|
#include <init/version.h>
|
|
#include <init/bootlogo.h>
|
|
#include <drivers/fbcon.h>
|
|
#include <userland/lazybox.h>
|
|
#include <userland/sh.h>
|
|
#include <userland/shell.h>
|
|
#include <kernel/exec.h>
|
|
|
|
static void subos_modular_core_boot(void) {
|
|
#if defined(__x86_64__)
|
|
pci_init();
|
|
#endif
|
|
|
|
// Storage & Block Layer
|
|
printk(KERN_INFO "[4/14] Initializing Block Layer & Storage Controllers... ");
|
|
block_init();
|
|
page_cache_init();
|
|
ramdisk_init();
|
|
#if defined(__x86_64__)
|
|
ata_init();
|
|
ahci_init();
|
|
nvme_init();
|
|
#endif
|
|
virtio_blk_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Bus & Devices
|
|
printk(KERN_INFO "[5/14] Enumerating System Devices, Canvas & PTY... ");
|
|
#if defined(__x86_64__)
|
|
virt_init();
|
|
fb_init();
|
|
bochs_vbe_init();
|
|
virtio_gpu_init();
|
|
usb_init();
|
|
xhci_init();
|
|
hwmon_init();
|
|
cpufreq_init();
|
|
hpet_init();
|
|
nvram_init();
|
|
lpt_init();
|
|
#endif
|
|
ktime_init();
|
|
canvas_init();
|
|
pty_init();
|
|
virtio_rng_init();
|
|
virtio_input_init();
|
|
tsc_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// The framebuffer exists from here on, so raise the graphical splash unless
|
|
// a text console was requested. When it was, the adapter is still in graphics
|
|
// mode and the VGA text buffer is no longer scanned out, so move the console
|
|
// to the framebuffer or the rest of the boot log is visible only on the
|
|
// serial line. Remaining messages keep flowing to the serial line and dmesg.
|
|
bool want_splash = !(init_has_param("nogui") || init_has_param("text") ||
|
|
init_has_param("emergency") || init_has_param("single") ||
|
|
init_has_param("nosplash"));
|
|
if (want_splash) {
|
|
boot_logo_splash_begin();
|
|
} else {
|
|
fbcon_enable(true);
|
|
}
|
|
|
|
// Network Subsystem, NetFilter, HTTPD & SSH Server
|
|
printk(KERN_INFO "[6/14] Initializing Network Stack, NetFilter, HTTPD & SSHD... ");
|
|
boot_logo_splash_progress(40, "Bringing up the network stack");
|
|
filter_init();
|
|
httpd_init();
|
|
sshd_init();
|
|
#if defined(__x86_64__)
|
|
rtl8139_init();
|
|
virtio_net_init();
|
|
e1000e_init();
|
|
if (e1000_init() || e1000e_is_online()) {
|
|
net_init();
|
|
socket_subsystem_init();
|
|
udp_init();
|
|
tcp_init();
|
|
dhcp_init();
|
|
dns_init();
|
|
dns_cache_init();
|
|
printk(ANSI_BRIGHT_GREEN "Online\n" ANSI_RESET);
|
|
} else {
|
|
printk(ANSI_YELLOW "No NIC detected\n" ANSI_RESET);
|
|
}
|
|
#else
|
|
virtio_net_init();
|
|
dns_cache_init();
|
|
printk(ANSI_BRIGHT_GREEN "Online\n" ANSI_RESET);
|
|
#endif
|
|
|
|
// Sound & Voice Synthesizer
|
|
#if defined(__x86_64__)
|
|
printk(KERN_INFO "[7/14] Initializing Sound Architecture, Melody Player & Formant TTS... ");
|
|
sound_init();
|
|
hda_init();
|
|
melody_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
#endif
|
|
|
|
// Crypto, Certificates, LSM Security, Authentication, Namespaces, Rust, SUB-Lang & C++ Subsystems
|
|
printk(KERN_INFO "[8/14] Initializing Rust, C++ Core, SUB-Lang Engine, Keyring & Auth... ");
|
|
boot_logo_splash_progress(55, "Starting Rust, C++ and SUB-Lang engines");
|
|
rust_kernel_init();
|
|
cpp_kernel_init();
|
|
cpp_analytics_init();
|
|
sub_kernel_init();
|
|
prng_seed(0, 0);
|
|
certs_init();
|
|
security_init();
|
|
auth_init();
|
|
namespace_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Concurrency Primitives: Wait Queues, Futexes & Tiny RCU
|
|
printk(KERN_INFO "[9/14] Initializing Wait Queues, Futex Hash & Tiny RCU... ");
|
|
boot_logo_splash_progress(65, "Initializing concurrency primitives");
|
|
wait_subsystem_init();
|
|
futex_init();
|
|
rcu_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Inter-Process Communication
|
|
printk(KERN_INFO "[9/14] Initializing IPC Engine (Pipes, MsgQueues, POSIX SHM, Semaphores)... ");
|
|
ipc_init();
|
|
posix_shm_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Asynchronous I/O Engine
|
|
printk(KERN_INFO "[10/14] Initializing io_uring Async Ring Engine... ");
|
|
io_uring_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Virtual File System & Multi-Filesystem Support
|
|
printk(KERN_INFO "[11/14] Mounting Virtual File System (VFS, devfs, procfs, sysfs)... ");
|
|
boot_logo_splash_progress(78, "Mounting the virtual file system");
|
|
vfs_init();
|
|
sysfs_init();
|
|
kobject_subsystem_init();
|
|
fat32_init();
|
|
ext2_init();
|
|
initramfs_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Kernel Core: Signals, Modules, Syscalls, Tracing, Syslog, Metrics, Crond & Systemd
|
|
printk(KERN_INFO "[12/14] Initializing Syslog, Metrics, Cron, Tracing, BPF & Services... ");
|
|
boot_logo_splash_progress(88, "Starting kernel services");
|
|
signal_init();
|
|
workqueue_init();
|
|
syscall_init();
|
|
module_init_subsystem();
|
|
trace_init();
|
|
bpf_init();
|
|
syslog_init();
|
|
metrics_init();
|
|
cron_init();
|
|
ob_init();
|
|
reg_init();
|
|
io_init();
|
|
service_manager_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
// Preemptive Multi-Tasking & Userland
|
|
printk(KERN_INFO "[13/14] Initializing Preemptive Task Scheduler & LazyBox... ");
|
|
boot_logo_splash_progress(95, "Starting the scheduler and userland");
|
|
sched_init();
|
|
lazybox_init();
|
|
ktest_init();
|
|
ktest_register_builtin_suites();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
#if defined(__x86_64__)
|
|
/* Prove real kernel-thread context switching before hardware interrupts
|
|
* are enabled: the Weave scheduler drives a batch of cooperative threads
|
|
* to completion on their own stacks and returns cleanly to this boot
|
|
* thread. Interrupts are still masked here, so the run is deterministic. */
|
|
weave_selftest();
|
|
#endif
|
|
|
|
// Hardware Interrupts
|
|
printk(KERN_INFO "[14/14] Enabling Hardware Interrupts... ");
|
|
arch_enable_interrupts();
|
|
printk(ANSI_BRIGHT_GREEN "ACTIVE\n" ANSI_RESET);
|
|
|
|
#if defined(__x86_64__)
|
|
/* With interrupts live, prove timer-driven preemption: two non-yielding
|
|
* threads are forced to share the CPU by the tick. Preemption is left armed
|
|
* afterwards, so CPU-bound kernel threads are time-sliced from here on. */
|
|
weave_preempt_selftest();
|
|
|
|
// The async HTTP client runs on its own kernel thread, which idles on hlt
|
|
// between fetches. It is started only now, once hardware interrupts are
|
|
// live -- earlier, and its first idle would hlt with no timer tick to wake
|
|
// it -- and after the deterministic scheduler self-tests, so it never joins
|
|
// their fixed thread set. Harmless with no NIC: a fetch then fails at
|
|
// connect. It stays dormant until the GUI Web app requests a page.
|
|
http_client_init();
|
|
|
|
// The rest of the system -- the login prompt, the shell, the GUI
|
|
// compositor -- has run on the pid-0 idle thread, which the scheduler
|
|
// neither preempts (sched_tick skips pid 0) nor requeues on a yield
|
|
// (weave_on is clear). That was fine while nothing else needed the CPU, but
|
|
// now a background worker (the async HTTP client) does. Joining the weave
|
|
// rotation makes this thread a first-class participant: a sched_yield from
|
|
// the compositor's idle slack requeues it and lets the worker run, and
|
|
// control comes straight back on the next rotation. Without this a yield
|
|
// here would switch away for good.
|
|
sched_join();
|
|
#endif
|
|
|
|
// Boot directly into the GUI Desktop unless emergency text mode is requested.
|
|
bool emergency_text = init_has_param("nogui") || init_has_param("text") ||
|
|
init_has_param("emergency") || init_has_param("single");
|
|
|
|
// End the splash and return the screen to a text console so the login
|
|
// prompt is visible before any session (graphical or TTY) begins.
|
|
boot_logo_splash_end();
|
|
fbcon_enable(true);
|
|
|
|
// Gate the session behind an interactive login. This blocks until a valid
|
|
// username/password is entered; the default account is SUB / SUB.
|
|
console_login();
|
|
|
|
if (!emergency_text) {
|
|
printk(KERN_INFO "INIT: Starting SUB-OS Graphical Desktop Environment...\n");
|
|
gui_start_desktop();
|
|
printk(KERN_INFO "INIT: GUI session closed. Entering Kernel TTY Mode.\n");
|
|
// The desktop owned the framebuffer; return it to the text console.
|
|
fbcon_enable(true);
|
|
} else {
|
|
printk(KERN_INFO "INIT: Emergency text/kernel TTY mode requested via boot parameters.\n");
|
|
}
|
|
|
|
// Hand control to userland: /sbin/init is a separate static ELF that runs
|
|
// in ring 3 with its own page tables and talks back only through INT 0x80.
|
|
exec_run_builtin_init();
|
|
|
|
// Launch Shell (Emergency TTY Mode)
|
|
shell_run();
|
|
|
|
while (1) {
|
|
arch_halt();
|
|
}
|
|
}
|
|
|
|
#if defined(__x86_64__)
|
|
void kernel_main(void* memory_map, uint64_t memory_map_count) {
|
|
tty_init();
|
|
serial_init();
|
|
printk_init();
|
|
|
|
boot_logo_print_text();
|
|
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n" ANSI_RESET);
|
|
printk(ANSI_BRIGHT_CYAN " SUB-OS 64-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
|
|
|
|
init_early("root=/dev/sda console=tty1 init=/bin/lazybox video=1280x720 quiet");
|
|
rtc_init();
|
|
|
|
printk(KERN_INFO "[1/14] Initializing 64-Bit GDT, IDT, PIC & PIT Timer... ");
|
|
arch_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
printk(KERN_INFO "[2/14] Initializing PS/2 Keyboard, Mouse & ACPI... ");
|
|
keyboard_init();
|
|
mouse_init();
|
|
acpi_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
printk(KERN_INFO "[3/14] Initializing Physical PMM, Dynamic Heap & SLAB Cache... ");
|
|
pmm_init(memory_map, memory_map_count);
|
|
heap_init();
|
|
slab_init();
|
|
vma_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
subos_modular_core_boot();
|
|
}
|
|
#elif defined(__aarch64__)
|
|
void kernel_main_aarch64(void) {
|
|
arch_early_init();
|
|
printk_init();
|
|
|
|
boot_logo_print_text();
|
|
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n" ANSI_RESET);
|
|
printk(ANSI_BRIGHT_CYAN " SUB-OS 64-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
|
|
|
|
init_early("root=/dev/vda console=ttyAMA0 init=/bin/lazybox quiet");
|
|
|
|
printk(KERN_INFO "[1/14] Initializing AArch64 CPU, GICv2, Generic Timer & MMU... ");
|
|
arch_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
printk(KERN_INFO "[2/14] Initializing Physical PMM, Dynamic Heap & SLAB Cache... ");
|
|
pmm_init(NULL, 0);
|
|
heap_init();
|
|
slab_init();
|
|
vma_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
subos_modular_core_boot();
|
|
}
|
|
#elif defined(__arm__) || defined(__armv8i__)
|
|
void kernel_main_armv8i(void) {
|
|
arch_early_init();
|
|
printk_init();
|
|
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n" ANSI_RESET);
|
|
printk(ANSI_BRIGHT_CYAN " SUB-OS 32-Bit [%s] Modular Monolithic Kernel %s\n" ANSI_RESET, arch_get_name(), kernel_get_version());
|
|
printk(ANSI_BRIGHT_CYAN "=================================================================\n\n" ANSI_RESET);
|
|
|
|
init_early("root=/dev/vda console=ttyAMA0 init=/bin/lazybox quiet");
|
|
|
|
printk(KERN_INFO "[1/14] Initializing ARMv8i CPU, GICv2, Generic Timer & MMU... ");
|
|
arch_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
printk(KERN_INFO "[2/14] Initializing Physical PMM, Dynamic Heap & SLAB Cache... ");
|
|
pmm_init(NULL, 0);
|
|
heap_init();
|
|
slab_init();
|
|
vma_init();
|
|
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
|
|
|
subos_modular_core_boot();
|
|
}
|
|
#endif
|