Решил вынести это в отдельную тему.
Поковырялся с многозадачностью. Плюнул на примеры кода, практически полностью переработал менеджер памяти, планировщик написал сам.
Пока решил поиграться с потоками - чуть проще, так как исполняются в одном адресном пространстве. Переключение между потоками удалось реализвать, осталась одна проблема - через некоторое время машина перезагружается, основное подозрение - переполнение стеков потоков, так как в процессе переключения esp потока сползает всё ниже и ниже. При увеличении интервала таймера и размера стека всё это живет чуть дольше.
Приведу код
Инициализация планировщикаКод:
/*-----------------------------------------------------------------------------
*
*---------------------------------------------------------------------------*/
void init_task_manager(void)
{
/* Запоминаем текущий контекст выполнения */
u32int eip = read_eip();
u32int esp = read_esp();
u32int ebp = read_ebp();
/* Выход, если прошла инициализация */
if (multi_task)
{
return;
}
/* Вырубаем прерывания */
asm volatile ("cli");
list_init(&process_list);
list_init(&thread_list);
/* Создаем процесс ядра */
kernel_proc = (process_t*) kmalloc(sizeof(process_t));
memset(kernel_proc, 0, sizeof(process_t));
kernel_proc->pid = next_pid++;
kernel_proc->page_dir = get_kernel_dir();
kernel_proc->list_item.list = NULL;
kernel_proc->threads_count = 1;
strcpy(kernel_proc->name, "Kernel");
kernel_proc->suspend = false;
list_add(&process_list, &kernel_proc->list_item);
/* Создаем главный поток ядра */
kernel_thread = (thread_t*) kmalloc(sizeof(thread_t));
memset(kernel_thread, 0, sizeof(thread_t));
kernel_thread->process = kernel_proc;
kernel_thread->list_item.list = NULL;
kernel_thread->id = next_thread_id++;
kernel_thread->stack_size = 0x4000;
kernel_thread->suspend = false;
kernel_thread->state.eip = eip;
kernel_thread->state.esp = esp;
kernel_thread->state.ebp = ebp;
list_add(&thread_list, &kernel_thread->list_item);
current_proc = kernel_proc;
current_thread = kernel_thread;
/* Включаем прерывания */
multi_task = true;
asm volatile ("sti");
}
Переключение потоковКод:
/*-----------------------------------------------------------------------------
*
*---------------------------------------------------------------------------*/
void switch_task(registers_t regs)
{
if (multi_task)
{
/* Вырубаем прерывания */
asm volatile ("cli");
/* Запоминаем состояние текущего потока */
current_thread->state.eip = regs.eip;
current_thread->state.esp = regs.esp;
/* Берем новый поток из кольцевой очереди */
current_thread = (thread_t*) current_thread->list_item.next;
/* Помещаем адрес перехода в новую задачу в ECX */
asm volatile ("mov %0, %%ecx"::"a"(current_thread->state.eip));
/* Меняем директорию страниц */
asm volatile ("mov %0, %%cr3"::"a"(current_proc->page_dir));
/* Устанавливаем ESP */
asm volatile ("mov %0, %%esp"::"a"(current_thread->state.esp));
/* Включаем прерывания */
asm volatile ("sti");
/* Прыгаем на новый поток */
asm volatile ("jmp *%ecx");
}
}
Создание потокаКод:
/*-----------------------------------------------------------------------------
*
*---------------------------------------------------------------------------*/
void create_thread(process_t* proc, /* Process */
void* entry_point, /* Entry point of thread */
size_t stack_size, /* Size of thread's stack */
bool kernel, /* Kernel CPL */
bool suspend, /* Suspended thread */
thread_t* thread) /* Thread's handler */
{
void* stack = NULL;
/* Выключаем прерывания */
asm volatile ("cli");
/* Создаем новый описатель потока */
thread_t* tmp_thread = (thread_t*) kmalloc(sizeof(thread_t));
/* Чистим выделеную память */
memset(tmp_thread, 0, sizeof(thread_t));
/* Инициализируем поток */
tmp_thread->id = next_thread_id++;
tmp_thread->list_item.list = NULL;
tmp_thread->process = proc;
tmp_thread->stack_size = stack_size;
tmp_thread->suspend = suspend;/* */
tmp_thread->state.eip = (u32int) entry_point;
/* Создаем свой стек для потока */
stack = kmalloc(stack_size);
tmp_thread->state.esp = (u32int) stack + stack_size;
tmp_thread->state.ebp = 0;
/* Ставим поток в очередь на выполнение */
list_add(&thread_list, &tmp_thread->list_item);
/* Увеличиваем счетчик потоков процесса которому принадлежит данный поток */
proc->threads_count++;
/* Возвращаем описатель */
thread = tmp_thread;
/* Включаем прерывания */
asm volatile ("sti");
}
Реализована кольцевая очередь, спасибо
phantom-84 за идею
При тестировании всё это запускается вот так
Код:
/*------------------------------------------------------------------------------
//
// PhantomEx main kernel module
// (c) maisvendoo, 04.07.2013
//
//----------------------------------------------------------------------------*/
#include "main.h"
u32int init_esp;
thread_t* thread01;
thread_t* thread02;
thread_t* thread03;
void task01(void)
{
print_text("I'm task #1\n");
while (1);
}
void task02(void)
{
print_text("I'm task #2\n");
while (1);
}
void task03(void)
{
print_text("I'm task #3\n");
while (1);
}
/*------------------------------------------------------------------------------
// Startup function
//----------------------------------------------------------------------------*/
int main(multiboot_header_t* mboot, u32int initial_esp)
{
init_esp = initial_esp;
init_descriptor_tables();
/* Регистрация обработчиков процессорных исключений */
register_interrupt_handler(INT_0, &division_by_zero);
register_interrupt_handler(INT_6, &fault_opcode);
register_interrupt_handler(INT_8, &double_error);
register_interrupt_handler(INT_10, &invalid_tss);
register_interrupt_handler(INT_11, &segment_is_not_available);
register_interrupt_handler(INT_12, &stack_error);
register_interrupt_handler(INT_13, &general_protection_error);
register_interrupt_handler(INT_14, &page_fault);
/* Инициализация менеджера памяти */
check_memory_map((memory_map_entry_t*) mboot->mmap_addr, mboot->mmap_length);
init_memory_manager(init_esp);
/* Инициализация таймера */
init_timer(BASE_FREQ);
/* Врубаем прерывания */
asm volatile ("sti");
/* Инициализируем планировщик */
init_task_manager();
/* Получаем описатель текущего процесса */
process_t* kern_proc = get_current_proc();
/* Создаем потоки */
create_thread(kern_proc,
&task01,
0x4000,
true,
false,
thread01);
create_thread(kern_proc,
&task02,
0x4000,
true,
false,
thread02);
create_thread(kern_proc,
&task03,
0x4000,
true,
false,
thread03);
while (1);
return 0;
}
Ну вот такой результат...