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

View File

@@ -51,3 +51,21 @@ uint64_t v2p(uint64_t 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);
uint64_t p2v(uint64_t phys);
uint64_t v2p(uint64_t virt);
void platform_get_cpu_model(char *model);
#endif

View File

@@ -15,12 +15,16 @@ extern void cmd_write(const char *str);
extern void serial_write(const char *str);
#define MAX_PROCESSES 16
static process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
static int process_count = 0;
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
int process_count = 0;
static process_t* current_process = NULL;
static uint32_t next_pid = 0;
void process_init(void) {
for (int i = 0; i < MAX_PROCESSES; i++) {
processes[i].pid = 0xFFFFFFFF;
}
// Current kernel execution is PID 0
process_t *kernel_proc = &processes[process_count++];
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;
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
current_process = kernel_proc;
}
@@ -121,9 +129,12 @@ void process_create(void* entry_point, bool is_user) {
asm volatile("fninit");
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;
current_process->next = new_proc;
asm volatile("push %0; popfq" : : "r"(rflags));
}
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;
}
// 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
// Increase to 256KB to prevent stack smashing on heavy networking
size_t user_stack_size = 262144;
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
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;
// 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) = current_user_sp; // RSP (Updated user stack pointer)
*(--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("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->user_stack_alloc = stack;
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");
new_proc->fpu_initialized = true;
// Slot is already counted in process_count if new, or reused.
// 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;
current_process->next = new_proc;
asm volatile("push %0; popfq" : : "r"(rflags));
serial_write("[PROCESS] Spawned ELF Executable: ");
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)
return current_rsp;
// serial_write("SCHED\n");
// Save/Restore context
// Save context
current_process->rsp = current_rsp;
// Switch process
current_process = current_process->next;
// Switch to next ready process
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
if (current_process->is_user && current_process->kernel_stack) {
@@ -326,9 +361,18 @@ uint64_t process_schedule(uint64_t current_rsp) {
// Switch page table
paging_switch_directory(current_process->pml4_phys);
current_process->ticks++;
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) {
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) {
if (!to_delete || to_delete->pid == 0xFFFFFFFF) return;
if (!to_delete || to_delete->pid == 0xFFFFFFFF || to_delete->pid == 0) return;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
@@ -389,8 +433,9 @@ void process_terminate(process_t *to_delete) {
to_delete->pid = 0xFFFFFFFF;
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->kernel_stack_alloc = NULL;
to_delete->kernel_stack_alloc = NULL;
asm volatile("push %0; popfq" : : "r"(rflags));
}
@@ -399,7 +444,7 @@ uint64_t process_terminate_current(void) {
uint64_t 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));
return 0;
}

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "gui_ipc.h"
#define MAX_GUI_EVENTS 32
@@ -13,9 +14,8 @@
struct FAT32_FileHandle;
// Registers saved on the stack by interrupts/exceptions
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 rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t int_no, err_code;
@@ -24,31 +24,42 @@ typedef struct registers_t {
typedef struct process {
uint32_t pid;
uint64_t rsp; // Current stack pointer representing context
uint64_t pml4_phys; // Physical address of the page table
uint64_t kernel_stack; // Ring 0 stack pointer for user mode switches
uint64_t rsp;
uint64_t pml4_phys;
uint64_t kernel_stack;
bool is_user;
gui_event_t gui_events[MAX_GUI_EVENTS];
int gui_event_head;
int gui_event_tail;
void *ui_window; // Pointer to the active Window
void *ui_window;
uint64_t heap_start;
uint64_t heap_end;
void *fds[MAX_PROCESS_FDS];
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
void *user_stack_alloc; // Original pointer from kmalloc for freeing
void *kernel_stack_alloc;
void *user_stack_alloc;
bool is_terminal_proc;
struct process *next;
bool fpu_initialized;
char name[64];
uint64_t ticks;
uint64_t sleep_until;
} __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_create(void* entry_point, bool is_user);
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_terminate_current(void);
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);
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;
uint64_t timer_handler(registers_t *regs) {
outb(0x20, 0x20); // EOI as fast as possible
kernel_ticks++;
wm_timer_tick();
network_process_frames();
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
extern uint64_t process_schedule(uint64_t current_rsp);
return process_schedule((uint64_t)regs);
}

View File

@@ -811,6 +811,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
return old_end;
} else if (syscall_num == 5) { // SYS_SYSTEM
int cmd = (int)arg1;
process_t *proc = process_get_current();
if (cmd == 1) { // SYSTEM_CMD_SET_BG_COLOR
uint32_t color = (uint32_t)arg2;
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;
extern int network_tcp_recv_nb(void *buf, size_t 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;
}
@@ -1079,16 +1125,47 @@ uint64_t syscall_handler_c(registers_t *regs) {
uint64_t syscall_num = regs->rax;
// 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();
}
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
extern uint64_t process_schedule(uint64_t current_rsp);
regs->rax = 0;
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
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_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);
uint64_t syscall_handler_c(registers_t *regs);

View File

@@ -15,7 +15,9 @@ section .text
; R9 = arg5
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 rsp, [rel kernel_syscall_stack]
@@ -52,9 +54,7 @@ syscall_entry:
; 4. Call C handler with registers_t*
mov rdi, rsp
sti
call syscall_handler_c
cli
; 5. Switch to the resulting RSP (might be different if task switched)
mov rsp, rax
@@ -80,6 +80,11 @@ syscall_entry:
pop rbx
pop rax
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
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 header needs to maintain in any file it is present in, as per the GPL license terms.
#include "syscall.h"
#include "libui.h"
#include <stddef.h>
#include "libc/libui.h"
#include "libc/stdlib.h"
#include <stdbool.h>
static uint32_t ansi_to_boredos_color(int code) {
uint32_t default_color = 0xFFFFFFFF;
@@ -121,7 +122,7 @@ int main(void) {
}
} else {
// Avoid high CPU usage
for(volatile int i=0; i<10000; i++);
sleep(10);
}
}

View File

@@ -6,7 +6,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "libc/stdlib.h"
static int win_w = 1280;
static int win_h = 960;
@@ -1734,9 +1734,9 @@ int main(int argc, char **argv) {
}
if (gif_updated) {
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;
}

View File

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

View File

@@ -256,7 +256,7 @@ int main(void) {
} else {
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; }
for(volatile int i=0; i<5000; i++);
sleep(10);
}
}
return 0;

View File

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

View File

@@ -68,6 +68,9 @@
#define SYSTEM_CMD_DNS_LOOKUP 37
#define SYSTEM_CMD_SET_DNS 38
#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_TCP_RECV_NB 42
#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_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
typedef struct { uint8_t bytes[6]; } net_mac_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.
#include "libc/syscall.h"
#include "libc/libui.h"
#include "libc/stdlib.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -441,6 +442,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0);
}
} else {
sleep(10);
}
}
return 0;

View File

@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "libc/stdlib.h"
#define COLOR_DARK_BG 0xFF121212
#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.
#include "libc/syscall.h"
#include "libc/libui.h"
#include "libc/stdlib.h"
#include "libc/syscall_user.h"
#include <stddef.h>
@@ -257,8 +258,7 @@ int main(int argc, char **argv) {
sys_exit(0);
}
} else {
for(volatile int i=0; i<10000; i++);
sleep(10);
}
}

View File

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

View File

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

View File

@@ -138,8 +138,7 @@ int main(void) {
goto exit_app;
}
}
// No explicit sleep, rendering takes some time and provides natural visual delay.
// If it's too fast, we'll add sleep(1) here later.
sleep(2);
}
}
@@ -168,13 +167,14 @@ int main(void) {
goto exit_app;
}
}
sleep(2);
}
}
start = start + 1;
} else {
// Sort is done, just render and idle
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.
#include "libc/syscall.h"
#include "libc/libui.h"
#include "libc/stdlib.h"
#include <stddef.h>
#define COLOR_DARK_PANEL 0xFF202020
@@ -426,6 +427,8 @@ int main(int argc, char **argv) {
} else if (ev.type == GUI_EVENT_CLOSE) {
sys_exit(0);
}
} else {
sleep(10);
}
}
return 0;

View File

@@ -307,7 +307,7 @@ int main(int argc, char **argv) {
}
}
// Small sleep to avoid eating 100% CPU
for (volatile int i = 0; i < 10000; i++);
sleep(10);
}
}
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_paint(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_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);
}
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);
// Draw traffic light (close button - red)
@@ -1299,7 +1317,7 @@ void wm_paint(void) {
int dock_y = sh - dock_h - 6;
int dock_item_size = 48;
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_w = total_dock_width + 24;
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;
draw_dock_browser(dock_x, dock_item_y);
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);
// 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_item_size = 48;
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_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 == 6) start_menu_pending_app = "Paint";
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 {
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 if (str_starts_with(start_menu_pending_app, "About")) {
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")) {
k_shutdown();
} else if (str_starts_with(start_menu_pending_app, "Restart")) {