/* Calcite, src/kernel/scheduler.c * Copyright 2025-2026 Benji Dial * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "scheduler.h" #include "process.h" #include "utility.h" #include "debug.h" #include "heap.h" struct continuation_queue ready_continuations; void init_scheduler() { create_queue(&ready_continuations, 128); } //defined in scheduler.asm [[noreturn]] void resume_continuation(const struct continuation_info *info); [[noreturn]] void resume_next_continuation() { running_thread = 0; struct continuation_info ci; while (!take_from_queue(&ready_continuations, &ci)) { __asm__ ("sti"); __asm__ ("hlt"); __asm__ ("cli"); } assert(running_thread == 0) assert(ci.running_thread != 0) resume_continuation(&ci); } void create_queue(struct continuation_queue *queue, int buffer_size) { queue->cis = heap_alloc(buffer_size * sizeof(struct continuation_info)); queue->next_read_index = 0; queue->buffer_size = buffer_size; queue->count = 0; } void destroy_queue(struct continuation_queue *queue) { assert(queue->count == 0) heap_dealloc(queue->cis, queue->buffer_size * sizeof(struct continuation_info)); } void add_to_queue(struct continuation_queue *queue, struct continuation_info *ci) { if (queue->count == queue->buffer_size) { struct continuation_info *new_buffer = heap_alloc(2 * queue->buffer_size * sizeof(struct continuation_info)); memcpy( new_buffer, &queue->cis[queue->next_read_index], (queue->buffer_size - queue->next_read_index) * sizeof(struct continuation_info)); memcpy( &new_buffer[queue->buffer_size - queue->next_read_index], queue->cis, queue->next_read_index * sizeof(struct continuation_info)); heap_dealloc(queue->cis, queue->buffer_size * sizeof(struct continuation_info)); queue->cis = new_buffer; queue->buffer_size *= 2; queue->next_read_index = 0; } memcpy( &queue->cis[(queue->next_read_index + queue->count) % queue->buffer_size], ci, sizeof(struct continuation_info)); ++queue->count; } int take_from_queue(struct continuation_queue *queue, struct continuation_info *ci) { if (queue->count == 0) return 0; memcpy(ci, &queue->cis[queue->next_read_index], sizeof(struct continuation_info)); queue->next_read_index = (queue->next_read_index + 1) % queue->buffer_size; --queue->count; return 1; }