87 lines
3.1 KiB
C
87 lines
3.1 KiB
C
#include "thread.h"
|
|
#include "heap.h"
|
|
#include "../drivers/serial.h" // Подставь свой путь к ком-порту
|
|
|
|
#define STACK_SIZE 1024
|
|
|
|
static thread_t* current_thread = NULL;
|
|
static thread_t* main_thread = NULL;
|
|
static uint32_t next_thread_id = 1;
|
|
|
|
// Объявляем функцию, которая скомпилирована в switch.asm
|
|
extern void asm_switch_context(uint32_t** old_esp, uint32_t* new_esp);
|
|
|
|
void kthread_init(void) {
|
|
kprint_serial("THREADS: Initializing Round-Robin Scheduler...\n");
|
|
|
|
main_thread = (thread_t*)kmalloc(sizeof(thread_t));
|
|
main_thread->id = 0;
|
|
main_thread->state = THREAD_RUNNING;
|
|
main_thread->stack_limit = NULL;
|
|
main_thread->esp = NULL;
|
|
main_thread->next = main_thread; // Зацикливаем на себя
|
|
|
|
current_thread = main_thread;
|
|
kprint_serial("THREADS: Main kernel thread (kmain) registered.\n");
|
|
}
|
|
|
|
thread_t* kthread_create(void (*entry_point)(void)) {
|
|
thread_t* new_thread = (thread_t*)kmalloc(sizeof(thread_t));
|
|
void* stack_mem = kmalloc(STACK_SIZE);
|
|
|
|
if (!new_thread || !stack_mem) {
|
|
kprint_serial("THREADS ERROR: NO MEMORY FOR NEW THREAD!\n");
|
|
return NULL; // или вешай здесь cpu_halt()
|
|
}
|
|
|
|
new_thread->id = next_thread_id++;
|
|
new_thread->stack_limit = stack_mem;
|
|
new_thread->state = THREAD_READY;
|
|
|
|
// Стек растет вниз, встаем на самый конец выделенного куска
|
|
uint32_t* stack_top = (uint32_t*)((uint32_t)stack_mem + STACK_SIZE);
|
|
|
|
// Когда поток вызовет `ret` внутри asm_switch_context,
|
|
// он должен извлечь из стека адрес точки входа.
|
|
stack_top--;
|
|
*stack_top = (uint32_t)entry_point; // Адрес возврата для ret
|
|
|
|
// Теперь имитируем push четырех регистров, которые сохраняет asm_switch_context:
|
|
// edi, esi, ebp, ebx
|
|
stack_top--; *stack_top = 0; // edi
|
|
stack_top--; *stack_top = 0; // esi
|
|
stack_top--; *stack_top = 0; // ebp
|
|
stack_top--; *stack_top = 0; // ebx
|
|
|
|
new_thread->esp = stack_top;
|
|
|
|
new_thread->esp = stack_top;
|
|
|
|
// Круглый список: вставляем новый поток сразу после текущего
|
|
new_thread->next = current_thread->next;
|
|
current_thread->next = new_thread;
|
|
|
|
kprint_serial("THREADS: New thread created successfully.\n");
|
|
return new_thread;
|
|
}
|
|
|
|
void kthread_yield(void) {
|
|
thread_t* old_thread = current_thread;
|
|
thread_t* new_thread = current_thread->next;
|
|
|
|
// Ищем живой поток по кругу
|
|
while (new_thread->state != THREAD_READY && new_thread->state != THREAD_RUNNING) {
|
|
new_thread = new_thread->next;
|
|
}
|
|
|
|
if (new_thread == old_thread) return;
|
|
|
|
current_thread = new_thread;
|
|
if (old_thread->state == THREAD_RUNNING) {
|
|
old_thread->state = THREAD_READY;
|
|
}
|
|
new_thread->state = THREAD_RUNNING;
|
|
|
|
// Сама магия смены контекста
|
|
asm_switch_context(&(old_thread->esp), new_thread->esp);
|
|
}
|