100 lines
2.9 KiB
C
100 lines
2.9 KiB
C
/* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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;
|
|
|
|
}
|