Kernel Threads
Kernel Threads
If the only form of multiprocessing I want to implement are kernel threads (no processes, nothing in userland) is copying the kernel's address space necessary for each new thread?
I guess more specifically I'd like to know what are the exact steps to make this happen. I /have/ searched the wiki and these forums, and I'm wondering if it's as simple as this to enter a new thread:
- save stack pointers and instruction pointer
- create a new stack
- point to new stack
- set new instruction pointer equal to old one
- jump to new instruction pointer
- every 10 or so clock cycles, cycle between threads
Or is there more I need to do?
My kernel will not have a traditional usermode, so it will be the only binary ever being directly executed by the CPU. Instead, all userland application will be interpreted. For this reason, I *think* that separate processes are unnecessary. Threads ought to be able to give the illusion of multiple processes without needing to copy a bunch of code.
I guess more specifically I'd like to know what are the exact steps to make this happen. I /have/ searched the wiki and these forums, and I'm wondering if it's as simple as this to enter a new thread:
- save stack pointers and instruction pointer
- create a new stack
- point to new stack
- set new instruction pointer equal to old one
- jump to new instruction pointer
- every 10 or so clock cycles, cycle between threads
Or is there more I need to do?
My kernel will not have a traditional usermode, so it will be the only binary ever being directly executed by the CPU. Instead, all userland application will be interpreted. For this reason, I *think* that separate processes are unnecessary. Threads ought to be able to give the illusion of multiple processes without needing to copy a bunch of code.
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
Re: Kernel Threads
No. All threads exist in the same address space as the kernel already.xvedejas wrote:is copying the kernel's address space necessary for each new thread?
Set your new instruction pointer to your thread's entry point (i.e. function pointer).
Re: Kernel Threads
When creating a new stack, I need to disable paging though, since the stack is accessed by physical, not virtual memory address, correct?
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
- salil_bhagurkar
- Member
- Posts: 261
- Joined: Mon Feb 19, 2007 10:40 am
- Location: India
Re: Kernel Threads
No.. When you are creating a new stack, you are simply allocating a block of memory. It is similar to normal allocations and you do not need to disable paging.
Re: Kernel Threads
Right, so I've written code for this, but when I try to fork, I get a triple fault when switching to the new thread. Here's the code, I wonder where the error is:
Code: Select all
#include <system.h>
extern u32int read_eip();
u32int next_thread_id = 1;
volatile thread_t *current_thread;
void threads_install()
{
current_thread = (thread_t*)kmalloc(sizeof(thread_t));
current_thread->id = next_thread_id++;
current_thread->esp = initial_esp;
current_thread->ebp = initial_esp;
current_thread->eip = 0;
current_thread->status = 0;
current_thread->stack_size = 0;
current_thread->stack_start = initial_esp;
current_thread->next = current_thread;
current_thread->previous = current_thread;
current_thread->priority = 20;
current_thread->counter = 20;
}
u32int fork()
{ // make new thread
thread_t *parent_thread = (thread_t*)current_thread;
thread_t *new_thread = (thread_t*)kmalloc(sizeof(thread_t));
new_thread->id = next_thread_id++;
new_thread->next = parent_thread->next;
new_thread->next->previous = new_thread;
parent_thread->next = new_thread;
new_thread->previous = parent_thread;
new_thread->priority = parent_thread->priority;
new_thread->counter = new_thread->priority;
// entry point
asm volatile("cli");
u32int eip = read_eip();
if (current_thread == parent_thread)
{
u32int current_esp, current_ebp;
// state of current stack
asm volatile("mov %%esp, %0" :: "r"(current_esp));
asm volatile("mov %%ebp, %0" :: "r"(current_ebp));
current_thread->stack_size = current_thread->stack_start - current_esp;
u32int size = current_thread->stack_size;
u32int *stack = kmalloc_a(0x2000); // reserve 8192 bytes for stack
// start of stack is at _end_ of allocation
new_thread->stack_start = stack + 0x2000;
u32int offset = new_thread->stack_start - current_thread->stack_start;
// find the esp and ebp for the new stack
u32int *new_esp = offset + current_esp;
u32int *new_ebp = offset + current_ebp;
// copy over the old stack to the new one
memcpy(new_esp, current_esp, size);
// make sure all else is zeros
memset(stack, 0, 0x2000 - size);
// make changes to thread stuct
new_thread->esp = new_esp;
new_thread->ebp = new_ebp;
new_thread->stack_size = size;
new_thread->eip = eip;
asm volatile("sti");
return new_thread->id;
}
else return 0;
}
void switch_thread()
{ // this function is called every timer tick
if (current_thread->counter)
{
// let thread run some more
current_thread->counter--;
}
else // time to switch
{
asm volatile("cli");
// reset counter
current_thread->counter = current_thread->priority;
// save stack
u32int esp, ebp, eip;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
// get the eip
eip = read_eip();
if (eip == 0x12345) return;
current_thread->eip = eip;
current_thread->esp = esp;
current_thread->ebp = ebp;
// advance current_thread
current_thread = current_thread->next;
esp = current_thread->esp;
ebp = current_thread->ebp;
asm volatile(" \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx " :: "r"(eip), "r"(esp), "r"(ebp) : "%eax", "%ecx");
}
}
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
- alethiophile
- Member
- Posts: 90
- Joined: Sat May 30, 2009 10:28 am
Re: Kernel Threads
Do you have a double fault handler? If so, then triple faults perhaps are the result of a page fault in your stack (which, of course, repeats whenever the processor tries to call an interrupt handler).
If I had an OS, there would be a link here.
Re: Kernel Threads
I realized the reason for the triple fault was because these lines were incorrect:
they should have been:
Now, instead of a triple fault on fork(), the parent process correctly returns 0x02, but the child process is returning 0x12345 instead of 0x00. I think this is because of a stack issue, but I'm not quite sure what's going on here or how the value 0x12345 got from switch_thread() to fork()...
Code: Select all
// state of current stack
asm volatile("mov %%esp, %0" :: "r"(current_esp));
asm volatile("mov %%ebp, %0" :: "r"(current_ebp));
Code: Select all
// state of current stack
asm volatile("mov %%esp, %0" : "=r"(current_esp));
asm volatile("mov %%ebp, %0" : "=r"(current_ebp));
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
Re: Kernel Threads
Alright, one more!
Should have been
Now fork() seems to work, but once switch_thread() jumps to the child thread, it stops switching threads and keyboard input doesn't work...
Code: Select all
esp = current_thread->esp;
ebp = current_thread->ebp;
Code: Select all
esp = current_thread->esp;
ebp = current_thread->ebp;
eip = current_thread->eip;
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
Re: Kernel Threads
On a second look, it seems like interrupt 0 isn't firing anymore... This is strange, as if "sti" isn't working...
Valix is an experiment in an interpreted userspace with object-oriented and functional design patterns. Developers needed! Join #valix on irc.freenode.net
-
- Member
- Posts: 153
- Joined: Sun Jan 07, 2007 9:40 am
- Contact:
Re: Kernel Threads
dont forget to send EOI to the PICxvedejas wrote:On a second look, it seems like interrupt 0 isn't firing anymore... This is strange, as if "sti" isn't working...