Files
SUB-OS/kernel/main.c
T
subhobhai943andClaude Opus 4.8 dd4922767a feat(net,gui,sched): async HTTP client + Web browser app, and the scheduler fix that makes background work possible
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
2026-08-27 02:21:48 +05:30

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