task manager and major memory stability fixes

This commit is contained in:
boreddevnl 2026-03-10 18:12:57 +01:00
parent 1639b09cb5
commit 6a41be2437
31 changed files with 567 additions and 50 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -51,3 +51,21 @@ uint64_t v2p(uint64_t virt) {
} }
return virt; return virt;
} }
void platform_get_cpu_model(char *model) {
uint32_t brand[12];
uint32_t eax, ebx, ecx, edx;
for (uint32_t i = 0; i < 3; i++) {
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000002 + i));
brand[i * 4 + 0] = eax;
brand[i * 4 + 1] = ebx;
brand[i * 4 + 2] = ecx;
brand[i * 4 + 3] = edx;
}
char *p = (char *)brand;
for (int i = 0; i < 48; i++) {
model[i] = p[i];
}
model[48] = '\0';
}

View file

@ -9,5 +9,6 @@
void platform_init(void); void platform_init(void);
uint64_t p2v(uint64_t phys); uint64_t p2v(uint64_t phys);
uint64_t v2p(uint64_t virt); uint64_t v2p(uint64_t virt);
void platform_get_cpu_model(char *model);
#endif #endif

View file

@ -15,12 +15,16 @@ extern void cmd_write(const char *str);
extern void serial_write(const char *str); extern void serial_write(const char *str);
#define MAX_PROCESSES 16 #define MAX_PROCESSES 16
static process_t processes[MAX_PROCESSES] __attribute__((aligned(16))); process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
static int process_count = 0; int process_count = 0;
static process_t* current_process = NULL; static process_t* current_process = NULL;
static uint32_t next_pid = 0; static uint32_t next_pid = 0;
void process_init(void) { void process_init(void) {
for (int i = 0; i < MAX_PROCESSES; i++) {
processes[i].pid = 0xFFFFFFFF;
}
// Current kernel execution is PID 0 // Current kernel execution is PID 0
process_t *kernel_proc = &processes[process_count++]; process_t *kernel_proc = &processes[process_count++];
kernel_proc->pid = next_pid++; kernel_proc->pid = next_pid++;
@ -36,6 +40,10 @@ void process_init(void) {
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL; for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(kernel_proc->name, "kernel", 7);
kernel_proc->ticks = 0;
kernel_proc->next = kernel_proc; // Circular linked list kernel_proc->next = kernel_proc; // Circular linked list
current_process = kernel_proc; current_process = kernel_proc;
} }
@ -121,9 +129,12 @@ void process_create(void* entry_point, bool is_user) {
asm volatile("fninit"); asm volatile("fninit");
new_proc->fpu_initialized = true; new_proc->fpu_initialized = true;
// Add to linked list // Add to linked list (Critical Section)
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
new_proc->next = current_process->next; new_proc->next = current_process->next;
current_process->next = new_proc; current_process->next = new_proc;
asm volatile("push %0; popfq" : : "r"(rflags));
} }
process_t* process_create_elf(const char* filepath, const char* args_str) { process_t* process_create_elf(const char* filepath, const char* args_str) {
@ -165,11 +176,23 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
return NULL; return NULL;
} }
// Set process name from filepath
int last_slash = -1;
for (int i = 0; filepath[i]; i++) if (filepath[i] == '/') last_slash = i;
const char *filename = (last_slash == -1) ? filepath : (filepath + last_slash + 1);
int ni = 0;
while (filename[ni] && ni < 63) {
new_proc->name[ni] = filename[ni];
ni++;
}
new_proc->name[ni] = 0;
new_proc->ticks = 0;
// 3. Allocate generic User stack and Kernel stack for interrupts // 3. Allocate generic User stack and Kernel stack for interrupts
// Increase to 256KB to prevent stack smashing on heavy networking // Increase to 256KB to prevent stack smashing on heavy networking
size_t user_stack_size = 262144; size_t user_stack_size = 262144;
void* stack = kmalloc_aligned(user_stack_size, 4096); void* stack = kmalloc_aligned(user_stack_size, 4096);
void* kernel_stack = kmalloc_aligned(32768, 32768); void* kernel_stack = kmalloc_aligned(65536, 65536);
// Map User stack to 0x800000 // Map User stack to 0x800000
for (uint64_t i = 0; i < (user_stack_size / 4096); i++) { for (uint64_t i = 0; i < (user_stack_size / 4096); i++) {
@ -248,7 +271,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
current_user_sp &= ~15ULL; current_user_sp &= ~15ULL;
// 4. Build Stack Frame for context switch via IRETQ // 4. Build Stack Frame for context switch via IRETQ
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 32768); uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 65536);
*(--stack_ptr) = 0x1B; // SS (User Mode Data) *(--stack_ptr) = 0x1B; // SS (User Mode Data)
*(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer) *(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer)
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled) *(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
@ -279,7 +302,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
asm volatile("fninit"); asm volatile("fninit");
asm volatile("fxsave %0" : "=m"(*stack_ptr)); asm volatile("fxsave %0" : "=m"(*stack_ptr));
new_proc->kernel_stack = (uint64_t)kernel_stack + 32768; new_proc->kernel_stack = (uint64_t)kernel_stack + 65536;
new_proc->kernel_stack_alloc = kernel_stack; new_proc->kernel_stack_alloc = kernel_stack;
new_proc->user_stack_alloc = stack; new_proc->user_stack_alloc = stack;
new_proc->rsp = (uint64_t)stack_ptr; new_proc->rsp = (uint64_t)stack_ptr;
@ -288,11 +311,12 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
asm volatile("fninit"); asm volatile("fninit");
new_proc->fpu_initialized = true; new_proc->fpu_initialized = true;
// Slot is already counted in process_count if new, or reused. // Add to linked list (Critical Section)
uint64_t rflags;
// Add to linked list asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
new_proc->next = current_process->next; new_proc->next = current_process->next;
current_process->next = new_proc; current_process->next = new_proc;
asm volatile("push %0; popfq" : : "r"(rflags));
serial_write("[PROCESS] Spawned ELF Executable: "); serial_write("[PROCESS] Spawned ELF Executable: ");
serial_write(filepath); serial_write(filepath);
@ -308,13 +332,24 @@ uint64_t process_schedule(uint64_t current_rsp) {
if (!current_process || !current_process->next || current_process == current_process->next) if (!current_process || !current_process->next || current_process == current_process->next)
return current_rsp; return current_rsp;
// serial_write("SCHED\n"); // Save context
// Save/Restore context
current_process->rsp = current_rsp; current_process->rsp = current_rsp;
// Switch process // Switch to next ready process
current_process = current_process->next; extern uint32_t wm_get_ticks(void);
uint32_t now = wm_get_ticks();
process_t *start = current_process;
process_t *next_proc = current_process->next;
while (next_proc != start) {
if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) {
break;
}
next_proc = next_proc->next;
}
current_process = next_proc;
// Update Kernel Stack for User Mode interrupts and System Calls // Update Kernel Stack for User Mode interrupts and System Calls
if (current_process->is_user && current_process->kernel_stack) { if (current_process->is_user && current_process->kernel_stack) {
@ -326,9 +361,18 @@ uint64_t process_schedule(uint64_t current_rsp) {
// Switch page table // Switch page table
paging_switch_directory(current_process->pml4_phys); paging_switch_directory(current_process->pml4_phys);
current_process->ticks++;
return current_process->rsp; return current_process->rsp;
} }
process_t* process_get_by_pid(uint32_t pid) {
for (int i = 0; i < MAX_PROCESSES; i++) {
if (processes[i].pid == pid) return &processes[i];
}
return NULL;
}
static void process_cleanup_inner(process_t *proc) { static void process_cleanup_inner(process_t *proc) {
if (!proc || proc->pid == 0xFFFFFFFF) return; if (!proc || proc->pid == 0xFFFFFFFF) return;
@ -356,7 +400,7 @@ static void process_cleanup_inner(process_t *proc) {
} }
void process_terminate(process_t *to_delete) { void process_terminate(process_t *to_delete) {
if (!to_delete || to_delete->pid == 0xFFFFFFFF) return; if (!to_delete || to_delete->pid == 0xFFFFFFFF || to_delete->pid == 0) return;
uint64_t rflags; uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
@ -389,8 +433,9 @@ void process_terminate(process_t *to_delete) {
to_delete->pid = 0xFFFFFFFF; to_delete->pid = 0xFFFFFFFF;
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc); if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
if (to_delete->kernel_stack_alloc) kfree(to_delete->kernel_stack_alloc);
to_delete->user_stack_alloc = NULL; to_delete->user_stack_alloc = NULL;
to_delete->kernel_stack_alloc = NULL; to_delete->kernel_stack_alloc = NULL;
asm volatile("push %0; popfq" : : "r"(rflags)); asm volatile("push %0; popfq" : : "r"(rflags));
} }
@ -399,7 +444,7 @@ uint64_t process_terminate_current(void) {
uint64_t rflags; uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (!current_process) { if (!current_process || current_process->pid == 0) {
asm volatile("push %0; popfq" : : "r"(rflags)); asm volatile("push %0; popfq" : : "r"(rflags));
return 0; return 0;
} }

View file

@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include "gui_ipc.h" #include "gui_ipc.h"
#define MAX_GUI_EVENTS 32 #define MAX_GUI_EVENTS 32
@ -13,9 +14,8 @@
struct FAT32_FileHandle; struct FAT32_FileHandle;
// Registers saved on the stack by interrupts/exceptions
typedef struct registers_t { typedef struct registers_t {
uint8_t fxsave_region[512]; // SSE/FPU state, MUST be at the bottom (lowest address) uint8_t fxsave_region[512];
uint64_t r15, r14, r13, r12, r11, r10, r9, r8; uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t int_no, err_code; uint64_t int_no, err_code;
@ -24,31 +24,42 @@ typedef struct registers_t {
typedef struct process { typedef struct process {
uint32_t pid; uint32_t pid;
uint64_t rsp; // Current stack pointer representing context uint64_t rsp;
uint64_t pml4_phys; // Physical address of the page table uint64_t pml4_phys;
uint64_t kernel_stack; // Ring 0 stack pointer for user mode switches uint64_t kernel_stack;
bool is_user; bool is_user;
gui_event_t gui_events[MAX_GUI_EVENTS]; gui_event_t gui_events[MAX_GUI_EVENTS];
int gui_event_head; int gui_event_head;
int gui_event_tail; int gui_event_tail;
void *ui_window; // Pointer to the active Window void *ui_window;
uint64_t heap_start; uint64_t heap_start;
uint64_t heap_end; uint64_t heap_end;
void *fds[MAX_PROCESS_FDS]; void *fds[MAX_PROCESS_FDS];
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing void *kernel_stack_alloc;
void *user_stack_alloc; // Original pointer from kmalloc for freeing void *user_stack_alloc;
bool is_terminal_proc; bool is_terminal_proc;
struct process *next; struct process *next;
bool fpu_initialized; bool fpu_initialized;
char name[64];
uint64_t ticks;
uint64_t sleep_until;
} __attribute__((aligned(16))) process_t; } __attribute__((aligned(16))) process_t;
typedef struct {
uint32_t pid;
char name[64];
uint64_t ticks;
size_t used_memory;
} ProcessInfo;
void process_init(void); void process_init(void);
void process_create(void* entry_point, bool is_user); void process_create(void* entry_point, bool is_user);
process_t* process_create_elf(const char* filepath, const char* args_str); process_t* process_create_elf(const char* filepath, const char* args_str);
@ -56,6 +67,7 @@ process_t* process_get_current(void);
uint64_t process_schedule(uint64_t current_rsp); uint64_t process_schedule(uint64_t current_rsp);
uint64_t process_terminate_current(void); uint64_t process_terminate_current(void);
void process_terminate(process_t *proc); void process_terminate(process_t *proc);
process_t* process_get_by_pid(uint32_t pid);
void process_push_gui_event(process_t *proc, gui_event_t *ev); void process_push_gui_event(process_t *proc, gui_event_t *ev);
process_t* process_get_by_ui_window(void* win); process_t* process_get_by_ui_window(void* win);

View file

@ -14,11 +14,11 @@ extern void serial_print_hex(uint64_t n);
volatile uint64_t kernel_ticks = 0; volatile uint64_t kernel_ticks = 0;
uint64_t timer_handler(registers_t *regs) { uint64_t timer_handler(registers_t *regs) {
outb(0x20, 0x20); // EOI as fast as possible
kernel_ticks++; kernel_ticks++;
wm_timer_tick(); wm_timer_tick();
network_process_frames(); network_process_frames();
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
extern uint64_t process_schedule(uint64_t current_rsp); extern uint64_t process_schedule(uint64_t current_rsp);
return process_schedule((uint64_t)regs); return process_schedule((uint64_t)regs);
} }

View file

@ -811,6 +811,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
return old_end; return old_end;
} else if (syscall_num == 5) { // SYS_SYSTEM } else if (syscall_num == 5) { // SYS_SYSTEM
int cmd = (int)arg1; int cmd = (int)arg1;
process_t *proc = process_get_current();
if (cmd == 1) { // SYSTEM_CMD_SET_BG_COLOR if (cmd == 1) { // SYSTEM_CMD_SET_BG_COLOR
uint32_t color = (uint32_t)arg2; uint32_t color = (uint32_t)arg2;
extern void graphics_set_bg_color(uint32_t color); extern void graphics_set_bg_color(uint32_t color);
@ -1068,6 +1069,51 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
size_t max_len = (size_t)arg3; size_t max_len = (size_t)arg3;
extern int network_tcp_recv_nb(void *buf, size_t max_len); extern int network_tcp_recv_nb(void *buf, size_t max_len);
return (uint64_t)network_tcp_recv_nb(buf, max_len); return (uint64_t)network_tcp_recv_nb(buf, max_len);
} else if (cmd == SYSTEM_CMD_PROCESS_LIST) {
ProcessInfo *out = (ProcessInfo *)arg2;
int max_procs = (int)arg3;
if (!out) return 0;
extern process_t processes[];
extern int process_count;
int count = 0;
for (int i = 0; i < 16; i++) { // MAX_PROCESSES is 16
if (processes[i].pid != 0xFFFFFFFF) {
out[count].pid = processes[i].pid;
extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(out[count].name, processes[i].name, 64);
out[count].ticks = processes[i].ticks;
// Memory estimation: heap + stacks
size_t mem = 0;
if (processes[i].heap_end > processes[i].heap_start)
mem += (processes[i].heap_end - processes[i].heap_start);
if (processes[i].pid == 0) {
// For kernel, we can report a more realistic figure if we want,
// but 32KB is specifically its stack. Let's keep it but maybe
// add a note in documentation.
mem = 32768;
} else {
if (processes[i].is_user) mem += 262144; // User stack
mem += 32768; // Kernel stack
}
out[count].used_memory = mem;
count++;
if (count >= max_procs) break;
}
}
return (uint64_t)count;
} else if (cmd == SYSTEM_CMD_GET_CPU_MODEL) {
char *user_buf = (char *)arg2;
if (!user_buf) return -1;
char model[64];
platform_get_cpu_model(model);
extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(user_buf, model, 49);
return 0;
} }
return -1; return -1;
} }
@ -1079,16 +1125,47 @@ uint64_t syscall_handler_c(registers_t *regs) {
uint64_t syscall_num = regs->rax; uint64_t syscall_num = regs->rax;
// Check for context-switching syscalls // Check for context-switching syscalls
if (syscall_num == 0 || syscall_num == 60 || syscall_num == 10) { // EXIT or KILL if (syscall_num == 0 || syscall_num == 60) { // EXIT
return process_terminate_current(); return process_terminate_current();
} }
if (syscall_num == 10) { // KILL
uint32_t target_pid = (uint32_t)regs->rdi;
process_t *current = process_get_current();
if (target_pid == 0) {
// Protect kernel process
regs->rax = -1;
return (uint64_t)regs;
}
if (target_pid == 0xFFFFFFFF || target_pid == current->pid) {
return process_terminate_current();
} else {
process_t *target = process_get_by_pid(target_pid);
if (target) {
process_terminate(target);
}
regs->rax = 0;
return (uint64_t)regs;
}
}
if (syscall_num == 5 && regs->rdi == 43) { // SYSTEM_CMD_YIELD if (syscall_num == 5 && regs->rdi == 43) { // SYSTEM_CMD_YIELD
extern uint64_t process_schedule(uint64_t current_rsp); extern uint64_t process_schedule(uint64_t current_rsp);
regs->rax = 0; regs->rax = 0;
return process_schedule((uint64_t)regs); return process_schedule((uint64_t)regs);
} }
if (syscall_num == 5 && regs->rdi == 46) { // SYSTEM_CMD_SLEEP
uint32_t ms = (uint32_t)regs->rsi;
process_t *proc = process_get_current();
extern uint32_t wm_get_ticks(void);
uint32_t ticks = ms / 16;
if (ticks == 0 && ms > 0) ticks = 1;
proc->sleep_until = wm_get_ticks() + ticks;
regs->rax = 0;
return process_schedule((uint64_t)regs);
}
// Normal syscalls // Normal syscalls
regs->rax = syscall_handler_inner(regs); regs->rax = syscall_handler_inner(regs);

View file

@ -39,6 +39,13 @@ typedef struct registers_t registers_t;
#define FS_CMD_CHDIR 13 #define FS_CMD_CHDIR 13
#define FS_CMD_GET_INFO 14 #define FS_CMD_GET_INFO 14
#define SYSTEM_CMD_SET_RAW_MODE 41
#define SYSTEM_CMD_TCP_RECV_NB 42
#define SYSTEM_CMD_YIELD 43
#define SYSTEM_CMD_PROCESS_LIST 44
#define SYSTEM_CMD_GET_CPU_MODEL 45
#define SYSTEM_CMD_SLEEP 46
void syscall_init(void); void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs); uint64_t syscall_handler_c(registers_t *regs);

View file

@ -15,7 +15,9 @@ section .text
; R9 = arg5 ; R9 = arg5
syscall_entry: syscall_entry:
; 1. Switch to Kernel Stack ; 1. Switch to Kernel Stack safely
; Note: For true SMP safety, we need per-CPU storage (via swapgs).
; For now, we use a global scratch which is only safe because we mask interrupts on entry.
mov [rel user_rsp_scratch], rsp mov [rel user_rsp_scratch], rsp
mov rsp, [rel kernel_syscall_stack] mov rsp, [rel kernel_syscall_stack]
@ -52,9 +54,7 @@ syscall_entry:
; 4. Call C handler with registers_t* ; 4. Call C handler with registers_t*
mov rdi, rsp mov rdi, rsp
sti
call syscall_handler_c call syscall_handler_c
cli
; 5. Switch to the resulting RSP (might be different if task switched) ; 5. Switch to the resulting RSP (might be different if task switched)
mov rsp, rax mov rsp, rax
@ -80,6 +80,11 @@ syscall_entry:
pop rbx pop rbx
pop rax pop rax
add rsp, 16 ; drop int_no/err_code add rsp, 16 ; drop int_no/err_code
; Debug: check RIP before iretq
; We can't easily print from here without destroying registers,
; but we can at least check if it's canonical.
iretq iretq
section .bss section .bss

View file

@ -2,8 +2,9 @@
// This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms. // This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "syscall.h" #include "syscall.h"
#include "libui.h" #include "libc/libui.h"
#include <stddef.h> #include "libc/stdlib.h"
#include <stdbool.h>
static uint32_t ansi_to_boredos_color(int code) { static uint32_t ansi_to_boredos_color(int code) {
uint32_t default_color = 0xFFFFFFFF; uint32_t default_color = 0xFFFFFFFF;
@ -121,7 +122,7 @@ int main(void) {
} }
} else { } else {
// Avoid high CPU usage // Avoid high CPU usage
for(volatile int i=0; i<10000; i++); sleep(10);
} }
} }

View file

@ -6,7 +6,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include "libc/stdlib.h"
static int win_w = 1280; static int win_w = 1280;
static int win_h = 960; static int win_h = 960;
@ -1734,9 +1734,9 @@ int main(int argc, char **argv) {
} }
if (gif_updated) { if (gif_updated) {
browser_paint(); ui_mark_dirty(win_browser, 0, 0, win_w, win_h); browser_paint(); ui_mark_dirty(win_browser, 0, 0, win_w, win_h);
} else {
sleep(10);
} }
for(volatile int x=0; x<10000; x++);
} }
return 0; return 0;
} }

View file

@ -4,6 +4,7 @@
#include "syscall.h" #include "syscall.h"
#include "libui.h" #include "libui.h"
#include <stdbool.h> #include <stdbool.h>
#include "stdlib.h"
#define SCALE 1000000LL #define SCALE 1000000LL
@ -254,8 +255,7 @@ int main(void) {
sys_exit(0); sys_exit(0);
} }
} else { } else {
// Avoid high CPU usage sleep(10);
for(volatile int i=0; i<10000; i++);
} }
} }

View file

@ -256,7 +256,7 @@ int main(void) {
} else { } else {
long long now = sys_system(16, 0, 0, 0, 0); long long now = sys_system(16, 0, 0, 0, 0);
if (now - last_rep >= 6) { clock_paint(); ui_mark_dirty(win_clock, 0, 0, WIN_W, WIN_H); last_rep = now; } if (now - last_rep >= 6) { clock_paint(); ui_mark_dirty(win_clock, 0, 0, WIN_W, WIN_H); last_rep = now; }
for(volatile int i=0; i<5000; i++); sleep(10);
} }
} }
return 0; return 0;

View file

@ -292,8 +292,7 @@ char* getcwd(char *buf, int size) {
} }
void sleep(int ms) { void sleep(int ms) {
sys_system(46, ms, 0, 0, 0);
(void)ms;
} }
void exit(int status) { void exit(int status) {

View file

@ -68,6 +68,9 @@
#define SYSTEM_CMD_DNS_LOOKUP 37 #define SYSTEM_CMD_DNS_LOOKUP 37
#define SYSTEM_CMD_SET_DNS 38 #define SYSTEM_CMD_SET_DNS 38
#define SYSTEM_CMD_NET_UNLOCK 39 #define SYSTEM_CMD_NET_UNLOCK 39
#define SYSTEM_CMD_PROCESS_LIST 44
#define SYSTEM_CMD_GET_CPU_MODEL 45
#define SYSTEM_CMD_SLEEP 46
#define SYSTEM_CMD_SET_RAW_MODE 41 #define SYSTEM_CMD_SET_RAW_MODE 41
#define SYSTEM_CMD_TCP_RECV_NB 42 #define SYSTEM_CMD_TCP_RECV_NB 42
#define SYSTEM_CMD_YIELD 43 #define SYSTEM_CMD_YIELD 43
@ -113,6 +116,13 @@ typedef struct {
int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries); int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);
int sys_get_file_info(const char *path, FAT32_FileInfo *info); int sys_get_file_info(const char *path, FAT32_FileInfo *info);
typedef struct {
uint32_t pid;
char name[64];
uint64_t ticks;
size_t used_memory;
} ProcessInfo;
// Network API // Network API
typedef struct { uint8_t bytes[6]; } net_mac_address_t; typedef struct { uint8_t bytes[6]; } net_mac_address_t;
typedef struct { uint8_t bytes[4]; } net_ipv4_address_t; typedef struct { uint8_t bytes[4]; } net_ipv4_address_t;

View file

@ -3,6 +3,7 @@
// This header needs to maintain in any file it is present in, as per the GPL license terms. // This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "libc/syscall.h" #include "libc/syscall.h"
#include "libc/libui.h" #include "libc/libui.h"
#include "libc/stdlib.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -441,6 +442,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }
} else {
sleep(10);
} }
} }
return 0; return 0;

View file

@ -6,6 +6,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "libc/stdlib.h"
#define COLOR_DARK_BG 0xFF121212 #define COLOR_DARK_BG 0xFF121212
#define COLOR_DARK_PANEL 0xFF202020 #define COLOR_DARK_PANEL 0xFF202020

View file

@ -3,6 +3,7 @@
// This header needs to maintain in any file it is present in, as per the GPL license terms. // This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "libc/syscall.h" #include "libc/syscall.h"
#include "libc/libui.h" #include "libc/libui.h"
#include "libc/stdlib.h"
#include "libc/syscall_user.h" #include "libc/syscall_user.h"
#include <stddef.h> #include <stddef.h>
@ -257,8 +258,7 @@ int main(int argc, char **argv) {
sys_exit(0); sys_exit(0);
} }
} else { } else {
sleep(10);
for(volatile int i=0; i<10000; i++);
} }
} }

View file

@ -247,6 +247,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }
} else {
sleep(10);
} }
} }
return 0; return 0;

View file

@ -825,6 +825,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }
} else {
sleep(10);
} }
} }
return 0; return 0;

View file

@ -138,8 +138,7 @@ int main(void) {
goto exit_app; goto exit_app;
} }
} }
// No explicit sleep, rendering takes some time and provides natural visual delay. sleep(2);
// If it's too fast, we'll add sleep(1) here later.
} }
} }
@ -168,13 +167,14 @@ int main(void) {
goto exit_app; goto exit_app;
} }
} }
sleep(2);
} }
} }
start = start + 1; start = start + 1;
} else { } else {
// Sort is done, just render and idle // Sort is done, just render and idle
render_state(win); render_state(win);
sleep(50); sleep(200);
} }
} }

View file

@ -0,0 +1,306 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
#include "syscall.h"
#include "libui.h"
#include "stdlib.h"
#define COLOR_DARK_BG 0xFF121212
#define COLOR_DARK_PANEL 0xFF1E1E1E
#define COLOR_DARK_TEXT 0xFFE0E0E0
#define COLOR_DARK_BORDER 0xFF333333
#define COLOR_ACCENT 0xFF4FC3F7
#define COLOR_CPU 0xFF81C784
#define COLOR_MEM 0xFFFFB74D
#define COLOR_KILL 0xFFE57373
#define COLOR_DIM_TEXT 0xFF999999
#define MAX_VISIBLE_PROCS 10
#define GRAPH_POINTS 60
static ui_window_t win_taskman;
static ProcessInfo proc_list[32];
static int proc_count = 0;
static int selected_proc = -1;
// History as fixed-point (x100)
static int cpu_history[GRAPH_POINTS];
static int mem_history[GRAPH_POINTS];
static int history_idx = 0;
static uint64_t uptime_prev = 0;
static uint64_t kernel_ticks_prev = 0;
static uint64_t total_mem_system = 0;
static uint64_t used_mem_system = 0;
static char cpu_model_name[64] = "Unknown CPU";
typedef struct {
size_t total_memory;
size_t used_memory;
size_t available_memory;
size_t allocated_blocks;
size_t free_blocks;
size_t largest_free_block;
size_t smallest_free_block;
size_t fragmentation_percent;
size_t peak_memory_used;
} MemStats;
static void update_proc_list(void) {
proc_count = sys_system(SYSTEM_CMD_PROCESS_LIST, (uint64_t)proc_list, 32, 0, 0);
uint64_t uptime_now = sys_system(SYSTEM_CMD_UPTIME, 0, 0, 0, 0);
uint64_t kernel_ticks_now = 0;
for (int i = 0; i < proc_count; i++) {
if (proc_list[i].pid == 0) {
kernel_ticks_now = proc_list[i].ticks;
break;
}
}
if (uptime_prev > 0) {
uint64_t total_delta = uptime_now - uptime_prev;
if (total_delta > 0) {
uint64_t kernel_delta = kernel_ticks_now - kernel_ticks_prev;
if (kernel_delta > total_delta) kernel_delta = total_delta;
uint64_t used_delta = total_delta - kernel_delta;
int usage = (int)((used_delta * 100) / total_delta);
cpu_history[history_idx] = usage;
}
}
uptime_prev = uptime_now;
kernel_ticks_prev = kernel_ticks_now;
MemStats stats;
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
total_mem_system = stats.total_memory;
used_mem_system = stats.used_memory;
mem_history[history_idx] = (int)(stats.used_memory / 1024);
history_idx = (history_idx + 1) % GRAPH_POINTS;
}
static void draw_graph(int x, int y, int w, int h, int *data, uint32_t color, int max_val) {
ui_draw_rect(win_taskman, x, y, w, h, COLOR_DARK_PANEL);
ui_draw_rect(win_taskman, x, y, w, 1, COLOR_DARK_BORDER);
ui_draw_rect(win_taskman, x, y + h - 1, w, 1, COLOR_DARK_BORDER);
if (max_val == 0) max_val = 1;
for (int i = 0; i < GRAPH_POINTS - 1; i++) {
int idx1 = (history_idx + i) % GRAPH_POINTS;
long long val = (long long)data[idx1];
int h_val = (int)((val * h) / max_val);
if (h_val > h) h_val = h;
if (h_val < 0) h_val = 0;
int x1 = x + (i * w) / GRAPH_POINTS;
int next_x = x + ((i + 1) * w) / GRAPH_POINTS;
int draw_w = next_x - x1;
if (draw_w <= 0) draw_w = 1;
ui_draw_rect(win_taskman, x1, y + h - h_val, draw_w, h_val ? h_val : 1, color);
}
}
static void format_gib(uint64_t bytes, char *out) {
uint64_t gib_int = bytes / (1024 * 1024 * 1024);
uint64_t gib_frac = ((bytes % (1024 * 1024 * 1024)) * 100) / (1024 * 1024 * 1024);
char s_int[16], s_frac[16];
itoa((int)gib_int, s_int);
itoa((int)gib_frac, s_frac);
out[0] = 0;
strcat(out, s_int);
strcat(out, ".");
if (gib_frac < 10) strcat(out, "0");
strcat(out, s_frac);
strcat(out, " GiB");
}
static void draw_taskman(void) {
int win_w = 400;
int win_h = 480;
ui_draw_rect(win_taskman, 0, 0, win_w, win_h, COLOR_DARK_BG);
// CPU Graph Area
ui_draw_string(win_taskman, 10, 10, "PROCESSOR", COLOR_CPU);
char cpu_label[16];
int current_cpu = cpu_history[(history_idx + GRAPH_POINTS - 1) % GRAPH_POINTS];
itoa(current_cpu, cpu_label);
strcat(cpu_label, "%");
ui_draw_string(win_taskman, 140, 10, cpu_label, COLOR_CPU);
draw_graph(10, 25, 185, 60, cpu_history, COLOR_CPU, 100);
// CPU Model (Safe truncation)
char model_disp[32];
int mlen = strlen(cpu_model_name);
if (mlen > 22) {
memcpy(model_disp, cpu_model_name, 19);
model_disp[19] = '.'; model_disp[20] = '.'; model_disp[21] = '.'; model_disp[22] = 0;
} else {
strcpy(model_disp, cpu_model_name);
}
ui_draw_string(win_taskman, 10, 92, model_disp, COLOR_DIM_TEXT);
// Memory Graph Area
ui_draw_string(win_taskman, 205, 10, "MEMORY", COLOR_MEM);
char mem_pct_label[16];
int current_mem_pct = 0;
if (total_mem_system > 0) current_mem_pct = (int)((used_mem_system * 100) / total_mem_system);
itoa(current_mem_pct, mem_pct_label);
strcat(mem_pct_label, "%");
ui_draw_string(win_taskman, 340, 10, mem_pct_label, COLOR_MEM);
int max_mem_kb = (int)(total_mem_system / 1024);
draw_graph(205, 25, 185, 60, mem_history, COLOR_MEM, max_mem_kb);
// Memory GiB usage
char s_used[24], s_total[24], mem_text[64];
format_gib(used_mem_system, s_used);
format_gib(total_mem_system, s_total);
mem_text[0] = 0;
strcat(mem_text, s_used);
strcat(mem_text, " / ");
strcat(mem_text, s_total);
ui_draw_string(win_taskman, 205, 92, mem_text, COLOR_DIM_TEXT);
// Process List Header
ui_draw_rect(win_taskman, 10, 120, 380, 24, COLOR_DARK_PANEL);
ui_draw_string(win_taskman, 15, 125, "PID", COLOR_DIM_TEXT);
ui_draw_string(win_taskman, 60, 125, "NAME", COLOR_DIM_TEXT);
ui_draw_string(win_taskman, 250, 125, "MEMORY", COLOR_DIM_TEXT);
// Process Rows
int row = 0;
for (int i = 0; i < proc_count && row < MAX_VISIBLE_PROCS; i++) {
if (proc_list[i].pid == 0xFFFFFFFF) continue;
int ry = 150 + row * 26;
uint32_t bg = (selected_proc == row) ? 0xFF334455 : COLOR_DARK_PANEL;
ui_draw_rounded_rect_filled(win_taskman, 10, ry, 380, 24, 4, bg);
char pid_str[16];
itoa(proc_list[i].pid, pid_str);
ui_draw_string(win_taskman, 20, ry + 6, pid_str, COLOR_DARK_TEXT);
char name_disp[28];
if (strlen(proc_list[i].name) > 22) {
memcpy(name_disp, proc_list[i].name, 19);
name_disp[19] = '.'; name_disp[20] = '.'; name_disp[21] = '.'; name_disp[22] = 0;
} else {
strcpy(name_disp, proc_list[i].name);
}
ui_draw_string(win_taskman, 65, ry + 6, name_disp, COLOR_DARK_TEXT);
char m_str[32];
itoa((int)(proc_list[i].used_memory / 1024), m_str);
strcat(m_str, " KB");
ui_draw_string(win_taskman, 255, ry + 6, m_str, COLOR_DARK_TEXT);
row++;
}
// Kill button (Positioned relative to window height)
int btn_x = 400 - 110;
int btn_y = 480 - 70;
int btn_w = 100;
int btn_h = 30;
// Disable kill for PID 0
bool can_kill = (selected_proc != -1);
if (can_kill) {
int v_cnt = 0;
for (int i = 0; i < proc_count; i++) {
if (proc_list[i].pid != 0xFFFFFFFF) {
if (v_cnt == selected_proc) {
if (proc_list[i].pid == 0) can_kill = false;
break;
}
v_cnt++;
}
}
}
ui_draw_rounded_rect_filled(win_taskman, btn_x, btn_y, btn_w, btn_h, 6, can_kill ? COLOR_KILL : COLOR_DARK_BORDER);
const char *btn_text = "FORCE KILL";
int tx = btn_x + (btn_w - 80) / 2;
int ty = btn_y + (btn_h - 12) / 2;
ui_draw_string(win_taskman, tx, ty, btn_text, can_kill ? 0xFFFFFFFF : 0xFF666666);
}
int main(void) {
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
// Fetch CPU model
sys_system(SYSTEM_CMD_GET_CPU_MODEL, (uint64_t)cpu_model_name, 0, 0, 0);
for(int i=0; i<GRAPH_POINTS; i++) { cpu_history[i] = 0; mem_history[i] = 0; }
gui_event_t ev;
while (1) {
// Drain events
while (ui_get_event(win_taskman, &ev)) {
if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0);
} else if (ev.type == GUI_EVENT_CLICK) {
int mx = ev.arg1;
int my = ev.arg2;
if (mx >= 10 && mx < 390 && my >= 150 && my < 150 + MAX_VISIBLE_PROCS * 26) {
int idx = (my - 150) / 26;
int valid_count = 0;
int target_i = -1;
for (int i = 0; i < proc_count; i++) {
if (proc_list[i].pid != 0xFFFFFFFF) {
if (valid_count == idx) { target_i = i; break; }
valid_count++;
}
}
if (target_i != -1) selected_proc = idx;
else selected_proc = -1;
draw_taskman();
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
} else if (mx >= 290 && mx < 390 && my >= 410 && my < 440) {
if (selected_proc != -1) {
int valid_count = 0;
for (int i = 0; i < proc_count; i++) {
if (proc_list[i].pid != 0xFFFFFFFF) {
if (valid_count == selected_proc) {
if (proc_list[i].pid != 0) sys_kill(proc_list[i].pid);
break;
}
valid_count++;
}
}
selected_proc = -1;
update_proc_list();
draw_taskman();
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
}
}
} else if (ev.type == GUI_EVENT_PAINT) {
draw_taskman();
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
}
}
update_proc_list();
draw_taskman();
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
// Proper blocking sleep (200ms)
sys_system(46, 200, 0, 0, 0); // SYSTEM_CMD_SLEEP
}
return 0;
}

View file

@ -3,6 +3,7 @@
// This header needs to maintain in any file it is present in, as per the GPL license terms. // This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "libc/syscall.h" #include "libc/syscall.h"
#include "libc/libui.h" #include "libc/libui.h"
#include "libc/stdlib.h"
#include <stddef.h> #include <stddef.h>
#define COLOR_DARK_PANEL 0xFF202020 #define COLOR_DARK_PANEL 0xFF202020
@ -426,6 +427,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) { } else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0); sys_exit(0);
} }
} else {
sleep(10);
} }
} }
return 0; return 0;

View file

@ -307,7 +307,7 @@ int main(int argc, char **argv) {
} }
} }
// Small sleep to avoid eating 100% CPU // Small sleep to avoid eating 100% CPU
for (volatile int i = 0; i < 10000; i++); sleep(10);
} }
} }
return 0; return 0;

View file

@ -409,6 +409,8 @@ static void draw_dock_terminal(int x, int y);
static void draw_dock_minesweeper(int x, int y); static void draw_dock_minesweeper(int x, int y);
static void draw_dock_paint(int x, int y); static void draw_dock_paint(int x, int y);
static void draw_dock_clock(int x, int y); static void draw_dock_clock(int x, int y);
static void draw_dock_taskman(int x, int y);
static void draw_dock_editor(int x, int y);
static void draw_dock_editor(int x, int y); static void draw_dock_editor(int x, int y);
static void draw_filled_circle(int cx, int cy, int r, uint32_t color); static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
@ -795,6 +797,22 @@ void draw_paint_icon(int x, int y, const char *label) {
draw_icon_label(x, y, label); draw_icon_label(x, y, label);
} }
static void draw_dock_taskman(int x, int y) {
draw_rounded_rect_filled(x, y, 48, 48, 12, 0xFF37474F); // Dark blue-grey
draw_rounded_rect_filled(x+4, y+4, 40, 40, 8, 0xFF455A64);
// Draw "Activity" lines
draw_rect(x+8, y+24, 6, 12, 0xFF4FC3F7); // Light blue bar
draw_rect(x+16, y+16, 6, 20, 0xFF81C784); // Green bar
draw_rect(x+24, y+20, 6, 16, 0xFFFFB74D); // Orange bar
draw_rect(x+32, y+10, 6, 26, 0xFFE57373); // Red bar
}
void draw_taskman_icon(int x, int y, const char *label) {
draw_scaled_icon(x, y, draw_dock_taskman);
draw_icon_label(x, y, label);
}
static void draw_filled_circle(int cx, int cy, int r, uint32_t color); static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
// Draw traffic light (close button - red) // Draw traffic light (close button - red)
@ -1299,7 +1317,7 @@ void wm_paint(void) {
int dock_y = sh - dock_h - 6; int dock_y = sh - dock_h - 6;
int dock_item_size = 48; int dock_item_size = 48;
int dock_spacing = 10; int dock_spacing = 10;
int total_dock_width = 9 * (dock_item_size + dock_spacing); int total_dock_width = 10 * (dock_item_size + dock_spacing);
int dock_bg_x = (sw - total_dock_width) / 2 - 12; int dock_bg_x = (sw - total_dock_width) / 2 - 12;
int dock_bg_w = total_dock_width + 24; int dock_bg_w = total_dock_width + 24;
draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG); draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG);
@ -1323,6 +1341,8 @@ void wm_paint(void) {
dock_x += dock_item_size + dock_spacing; dock_x += dock_item_size + dock_spacing;
draw_dock_browser(dock_x, dock_item_y); draw_dock_browser(dock_x, dock_item_y);
dock_x += dock_item_size + dock_spacing; dock_x += dock_item_size + dock_spacing;
draw_dock_taskman(dock_x, dock_item_y);
dock_x += dock_item_size + dock_spacing;
draw_dock_clock(dock_x, dock_item_y); draw_dock_clock(dock_x, dock_item_y);
// Editor removed from dock // Editor removed from dock
@ -1867,7 +1887,7 @@ void wm_handle_right_click(int x, int y) {
int dock_y = sh - dock_h - 6; int dock_y = sh - dock_h - 6;
int dock_item_size = 48; int dock_item_size = 48;
int dock_spacing = 10; int dock_spacing = 10;
int total_dock_width = 9 * (dock_item_size + dock_spacing); int total_dock_width = 10 * (dock_item_size + dock_spacing);
int dock_bg_x = (sw - total_dock_width) / 2 - 12; int dock_bg_x = (sw - total_dock_width) / 2 - 12;
int dock_bg_w = total_dock_width + 24; int dock_bg_w = total_dock_width + 24;
@ -1886,7 +1906,8 @@ void wm_handle_right_click(int x, int y) {
else if (item == 5) start_menu_pending_app = "Minesweeper"; else if (item == 5) start_menu_pending_app = "Minesweeper";
else if (item == 6) start_menu_pending_app = "Paint"; else if (item == 6) start_menu_pending_app = "Paint";
else if (item == 7) start_menu_pending_app = "Browser"; else if (item == 7) start_menu_pending_app = "Browser";
else if (item == 8) start_menu_pending_app = "Clock"; else if (item == 8) start_menu_pending_app = "Task Manager";
else if (item == 9) start_menu_pending_app = "Clock";
} }
} else { } else {
wm_handle_click(mx, my); wm_handle_click(mx, my);
@ -2040,6 +2061,10 @@ void wm_handle_right_click(int x, int y) {
else process_create_elf("/bin/browser.elf", NULL); else process_create_elf("/bin/browser.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "About")) { } else if (str_starts_with(start_menu_pending_app, "About")) {
process_create_elf("/bin/about.elf", NULL); process_create_elf("/bin/about.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "Task Manager")) {
Window *existing = wm_find_window_by_title("Task Manager");
if (existing) wm_bring_to_front(existing);
else process_create_elf("/bin/taskman.elf", NULL);
} else if (str_starts_with(start_menu_pending_app, "Shutdown")) { } else if (str_starts_with(start_menu_pending_app, "Shutdown")) {
k_shutdown(); k_shutdown();
} else if (str_starts_with(start_menu_pending_app, "Restart")) { } else if (str_starts_with(start_menu_pending_app, "Restart")) {