syscalls: fix nanosleep, thanks to gemini, sorry for that
This commit is contained in:
@@ -315,10 +315,11 @@ uint32_t sys_nanosleep(TrapFrame *tf)
|
|||||||
//debug_log("waiting for 0x%X ms\n", ms);
|
//debug_log("waiting for 0x%X ms\n", ms);
|
||||||
size_t start_time = timer_ticks;
|
size_t start_time = timer_ticks;
|
||||||
|
|
||||||
|
scheduler_lock();
|
||||||
current->wake_up_time = timer_ticks + ms;
|
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);
|
current->state = Waiting;
|
||||||
|
schedule();
|
||||||
//TODO: find a way to call the scheduler from here without fucking shit up
|
scheduler_unlock();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-23
@@ -103,23 +103,33 @@ void scheduler_unlock()
|
|||||||
void schedule() {
|
void schedule() {
|
||||||
scheduler_lock();
|
scheduler_lock();
|
||||||
|
|
||||||
Process* prev = NULL;
|
// Step 1: Iterate through all processes to wake up any that are due.
|
||||||
Process* p = queue;
|
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) {
|
while (p) {
|
||||||
if (p->state == Terminated) {
|
if (p->state == Terminated) {
|
||||||
Process* next_proc = p->next;
|
Process* next_proc = p->next;
|
||||||
// Unlink from the queue
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next = next_proc;
|
prev->next = next_proc;
|
||||||
} else {
|
} else {
|
||||||
queue = next_proc;
|
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) {
|
if (p == current) {
|
||||||
current = NULL;
|
current = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free the terminated process's resources.
|
||||||
destroy_page_dir(p->pagedir);
|
destroy_page_dir(p->pagedir);
|
||||||
free_page((void*)virt_to_phys(p->kstack));
|
free_page((void*)virt_to_phys(p->kstack));
|
||||||
free_page((void*)virt_to_phys(p));
|
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 there are no processes left, we have a problem.
|
||||||
if (!current || current->state != Ready) {
|
if (!queue) {
|
||||||
current = queue; // Start search from the beginning
|
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)
|
// Step 3: Find the next process to run using a round-robin algorithm.
|
||||||
{
|
Process* start_search = NULL;
|
||||||
current = queue;
|
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
|
// Ensure start_search is not NULL (handles wrapping around).
|
||||||
Process* next = current ? current->next : NULL;
|
if (!start_search) {
|
||||||
if (!next) next = queue;
|
start_search = queue;
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate through the list to find a process that is ready to run
|
// Find the first available 'Ready' process.
|
||||||
Process* start_node = next;
|
Process* next = start_search;
|
||||||
while (next && next->state != Ready) {
|
do {
|
||||||
next = next->next;
|
if (next->state == Ready) {
|
||||||
if (!next) next = queue; // Wrap around
|
// We found a process to run.
|
||||||
if (next == start_node) { // Full circle, no ready process
|
// 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();
|
scheduler_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
next = next->next;
|
||||||
|
if (!next) {
|
||||||
|
next = queue; // Wrap around to the beginning of the list.
|
||||||
}
|
}
|
||||||
|
} while (next != start_search);
|
||||||
|
|
||||||
if (next && next != current) {
|
// If we get here, it means no process is in the 'Ready' state.
|
||||||
tss.esp0 = next->kstack_top;
|
// This can happen if all tasks are waiting for I/O or sleeping.
|
||||||
switchProcess(next);
|
// We just unlock and wait for the next interrupt to change a process's state.
|
||||||
}
|
|
||||||
|
|
||||||
scheduler_unlock();
|
scheduler_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user