phantom-84 писал(а):
С тем, что пишущие под виндами - извращенцы, не согласен
Ну конечно же нет, это я несколько погорячился, просто уже привык очевидной простоте многих инструментов используемых в *nix, и достаточно надуманной сложности тех же инструментов в win.
Насчет отладки, ну не скажите. До вчера довольствовался лишь самописным ASSERT-ом и выводом на экран каждого чиха, и было довольно тяжко. Есть виртуальная FS содранная у того же Molloy, но пока не использую, логов не веду. Так что отладка из среды в относительной динамике это подспорье
Насчет же многозадачности, James Molloy предлагает алгоритм на основе вызова fork() вида
Код:
/*-----------------------------------------------------------------------------
*
* --------------------------------------------------------------------------*/
int fork(void)
{
int pid = 0;
volatile task_t* parent_task;
volatile task_t* new_task;
volatile task_t* tmp_task;
page_directory_t* dir;
u32int eip;
u32int esp;
u32int ebp;
print_text("Forking kernel task........................\n");
/* Disable interrupts */
asm volatile ("cli");
/* Parent task is our current task */
parent_task = (task_t*) current_task;
/* Clone current page directory */
dir = (page_directory_t*) clone_directory(current_dir);
debug_msg("Page directory for new task addr = ", (u32int) dir->phys_addr);
/* Create and initialize new task */
new_task = (task_t*) kmalloc(sizeof(task_t));
new_task->pid = next_pid++;
new_task->esp = 0;
new_task->ebp = 0;
new_task->eip = 0;
new_task->page_dir = dir;
new_task->next = 0;
/* Place new task to tail of queue */
tmp_task = (task_t*) ready_queue;
/* find tail of queue */
while (tmp_task->next)
{
tmp_task = (task_t*) tmp_task->next;
}
tmp_task->next = (struct task_t*) new_task; /* place new task to tail */
/* Get current EIP */
eip = read_eip();
/* Here we must been after task switch */
if (current_task == parent_task)
{
/* We in parent task */
asm volatile ("mov %%esp, %0":"=r"(esp));
asm volatile ("mov %%ebp, %0":"=r"(ebp));
new_task->esp = esp;
new_task->ebp = ebp;
new_task->eip = eip;
asm volatile ("sti");
return new_task->pid;
}
else
{
return 0;
}
}
прототипа планировщика вида
Код:
/*-----------------------------------------------------------------------------
*
* --------------------------------------------------------------------------*/
void switch_task(void)
{
u32int esp;
u32int ebp;
u32int eip;
/* If we have't task, then exit */
if (!current_task)
return;
/* Read ESP and EBP registers */
asm volatile ("mov %%esp, %0":"=r"(esp));
asm volatile ("mov %%ebp, %0":"=r"(ebp));
eip = read_eip();
if (eip == 0x12345)
{
return;
}
/* Switch task */
current_task->esp = esp;
current_task->ebp = ebp;
current_task->eip = eip;
current_task = (task_t*) current_task->next;
if (!current_task)
current_task = ready_queue;
esp = current_task->esp;
ebp = current_task->ebp;
eip = current_task->eip;
current_dir = (page_directory_t*) current_task->page_dir;
asm volatile ("\
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx"
::"r"(eip),"r"(esp),"r"(ebp),"r"(current_dir->phys_addr));
}
где функция взятия значения EIP имеет вид
Код:
/*------------------------------------------------------------------------------
// Function for read EIP
//----------------------------------------------------------------------------*/
.global read_eip
read_eip:
pop %eax
jmp *%eax
Причем дочерняя задача создается из основной, копируется директория страниц, но вот на этом участке, в родительском процессе
Код:
/* Get current EIP */
eip = read_eip();
/* Here we must been after task switch */
if (current_task == parent_task)
{
/* We in parent task */
asm volatile ("mov %%esp, %0":"=r"(esp));
asm volatile ("mov %%ebp, %0":"=r"(ebp));
new_task->esp = esp;
new_task->ebp = ebp;
new_task->eip = eip;
asm volatile ("sti");
return new_task->pid;
}
else
{
return 0;
}
При возврате в fork() из "дочки" движение должно идти по ветке else, и оно идет, но управление потом передается на адрес в секции данных как раз где лежит current_task, помещенная в EAX при сравнении, и естественно в коде имеем исключение #UD, так как процессор пытается выполнить не родительскую задачу, а белеберду.
Код сопровождаемый вызовом fork() таков (функция main.c)
Код:
asm volatile ("sti");
init_timer(BASE_FREQ);
init_tasking();
ret = fork();
asm volatile ("cli");
if (ret == 0)
print_text("Parent task!!!\n");
else
print_text("New task\n!!!");
asm volatile ("sti");
return 0;
Данный код многократно и вдумчиво переписан, и вот возникает вопрос, что хороший в принципе мануал JM не работает на 9 главе... Или я что-то не понимаю до конца