From 63938e1acd892fed9caa15f26b7b00c0becba2c5 Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Wed, 3 Sep 2025 16:35:07 +0300 Subject: [PATCH] syscalls: fix nanosleep, thanks to gemini, sorry for that --- src/tasking/syscalls.c | 7 ++-- src/tasking/task.c | 75 ++++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index 4bb3da1..b85a95e 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -315,10 +315,11 @@ uint32_t sys_nanosleep(TrapFrame *tf) //debug_log("waiting for 0x%X ms\n", ms); size_t start_time = timer_ticks; + scheduler_lock(); current->wake_up_time = timer_ticks + ms; - //debug_log("setting wake up time to %X (current time is %X)\n", current->wake_up_time, timer_ticks); - - //TODO: find a way to call the scheduler from here without fucking shit up + current->state = Waiting; + schedule(); + scheduler_unlock(); return 0; } diff --git a/src/tasking/task.c b/src/tasking/task.c index f0c8d68..e4d960c 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -103,23 +103,33 @@ void scheduler_unlock() void schedule() { scheduler_lock(); - Process* prev = NULL; + // Step 1: Iterate through all processes to wake up any that are due. Process* p = queue; + while (p) { + if (p->state == Waiting && timer_ticks >= p->wake_up_time) { + p->state = Ready; + } + p = p->next; + } + + // Step 2: Clean up any terminated processes. + Process* prev = NULL; + p = queue; while (p) { if (p->state == Terminated) { Process* next_proc = p->next; - // Unlink from the queue if (prev) { prev->next = next_proc; } else { queue = next_proc; } - // If the terminated process is the current one, we must not switch to it. + // If we are terminating the currently running process, we must find a new one. if (p == current) { current = NULL; } + // Free the terminated process's resources. destroy_page_dir(p->pagedir); free_page((void*)virt_to_phys(p->kstack)); free_page((void*)virt_to_phys(p)); @@ -131,36 +141,53 @@ void schedule() { } } - // If 'current' was terminated or this is the first run, find a new process. - if (!current || current->state != Ready) { - current = queue; // Start search from the beginning + // If there are no processes left, we have a problem. + if (!queue) { + scheduler_unlock(); + // Ideally, you would panic the kernel here. + // For now, we just return and hope an interrupt happens. + return; } - if(current->wake_up_time > timer_ticks) - { - current = queue; + // Step 3: Find the next process to run using a round-robin algorithm. + Process* start_search = NULL; + if (current && current->state == Ready) { + // If the current process is still ready, start searching from the next one. + start_search = current->next; + } else { + // If the current process is not ready (e.g., it's Waiting or was Terminated), + // start the search from the beginning of the queue. + start_search = queue; } - // Find the next ready process to run - Process* next = current ? current->next : NULL; - if (!next) next = queue; + // Ensure start_search is not NULL (handles wrapping around). + if (!start_search) { + start_search = queue; + } - // Iterate through the list to find a process that is ready to run - Process* start_node = next; - while (next && next->state != Ready) { - next = next->next; - if (!next) next = queue; // Wrap around - if (next == start_node) { // Full circle, no ready process + // Find the first available 'Ready' process. + Process* next = start_search; + do { + if (next->state == Ready) { + // We found a process to run. + // If it's not the same one we're already running, switch to it. + if (next != current) { + tss.esp0 = next->kstack_top; + switchProcess(next); // This will update 'current' and switch contexts. + } + // If next == current, we don't need to switch. Just continue execution. scheduler_unlock(); return; } - } - - if (next && next != current) { - tss.esp0 = next->kstack_top; - switchProcess(next); - } + next = next->next; + if (!next) { + next = queue; // Wrap around to the beginning of the list. + } + } while (next != start_search); + // If we get here, it means no process is in the 'Ready' state. + // This can happen if all tasks are waiting for I/O or sleeping. + // We just unlock and wait for the next interrupt to change a process's state. scheduler_unlock(); }