Add new threads to runnable threads list

More safely handle nested interrupts.
Switch to newly created thread immediately.
This commit is contained in:
Josh Holtrop 2023-12-08 12:16:35 -05:00
parent 44a305721e
commit 9874802ee4
4 changed files with 73 additions and 20 deletions

View File

@ -254,8 +254,7 @@ void cpuid1(uint * ebx, uint * ecx, uint * edx)
__asm("cpuid", "=*{ebx},=*{ecx},=*{edx},{eax}", ebx, ecx, edx, 1u);
}
void swint(int swint_id)()
void swint(ubyte swint_id)()
{
static assert((0 <= swint_id) && (swint_id <= 255));
mixin(`__asm("int $$`, swint_id, `", "");`);
mixin(`__asm("int $$`, cast(int)cast(uint)swint_id, `", "");`);
}

View File

@ -236,6 +236,7 @@ struct Him
mov %rsp, %rbp
mov %rsp, %rsi
and $$0xFFFFFFFFFFFFFFF0, %rsp
mov %rsp, %rdx
mov %rax, %rdi
movabs $$isr, %rax
callq *%rax
@ -273,10 +274,13 @@ struct Him
* This function returns the stack pointer of the thread to execute when
* returning from this function.
*/
public extern(C) ulong * isr(ulong vector, ulong * stack_frame)
public extern(C) ulong * isr(ulong vector, ulong * stack_frame, ulong * rsp)
{
interrupt_level++;
Thread.current_thread.stack_pointer = stack_frame;
if (interrupt_level == 1)
{
Thread.current_thread.stack_pointer = stack_frame;
}
if ((vector >= INT_APIC_BASE) && (vector < (INT_APIC_BASE + INT_APIC_COUNT)))
{
Apic.isr(vector);
@ -292,6 +296,10 @@ public extern(C) ulong * isr(ulong vector, ulong * stack_frame)
Apic.isr(vector);
break;
case INT_KERNEL_SWINT:
Thread.handle_swint(stack_frame);
break;
default:
Fb.rect(0, 0, Fb.width, Kfont.line_height, 0xCC0000u);
Klog.writefln("\n **** Unhandled ISR %u ****", vector);
@ -310,5 +318,12 @@ public extern(C) ulong * isr(ulong vector, ulong * stack_frame)
}
Thread.current_thread = Thread.current_thread.list_next;
interrupt_level--;
return Thread.current_thread.stack_pointer;
if (interrupt_level == 0)
{
return Thread.current_thread.stack_pointer;
}
else
{
return rsp;
}
}

View File

@ -92,11 +92,22 @@ void hulk_start()
/* Run kernel tests. */
Test.run();
Klog.writefln("\a5HULK Initialization Complete!");
Thread.start(&th);
/* Idle loop. */
Time.msleep(1);
Time.msleep(500);
Klog.writefln("Main thread!");
for (;;)
{
hlt();
}
}
void th()
{
for (;;)
{
Klog.writefln("Hello from thread.");
Time.msleep(1000);
}
}

View File

@ -10,12 +10,15 @@ import hulk.memory;
import hulk.list;
import hulk.cpu;
import hulk.hurl;
import ldc.llvmasm;
struct Thread
{
/* TODO: currently kernel thread stack size is fixed. */
enum STACK_SIZE = 16 * 1024;
enum ulong INT_TCTRL_YIELD = 0;
/** Interrupt stack template. */
static immutable __gshared ulong[ISF_COUNT] interrupt_stack_template = [
0x16161616_16161616u, /* RBP */
@ -41,8 +44,8 @@ struct Thread
Gdt.SELECTOR_KERNEL_DATA, /* SS */
];
/** List of all kernel threads. */
private static __gshared Thread * threads;
/** List of all runnable kernel threads. */
private static __gshared Thread * runnable_threads;
/** Currently executing kernel thread. */
static __gshared Thread * current_thread;
@ -62,11 +65,9 @@ struct Thread
public void initialize(void function() fn)
{
list_init();
if (threads == null)
{
threads = &this;
}
suspend_interrupts();
list_insert_after(current_thread);
resume_interrupts();
stack_addr = A1.allocate(STACK_SIZE);
ulong * stack_top = cast(ulong *)(stack_addr + STACK_SIZE);
stack_pointer = stack_top - ISF_COUNT;
@ -77,15 +78,12 @@ struct Thread
}
/**
* Initialize main kernel thread.
* Initialize first kernel thread.
*/
public void initialize_main_thread()
public void initialize_first_thread()
{
list_init();
if (threads == null)
{
threads = &this;
}
runnable_threads = &this;
stack_addr = cast(void *)(Hurl.HULK_STACK_TOP - STACK_SIZE);
}
@ -95,7 +93,7 @@ struct Thread
public static void initialize()
{
Thread * thread = A1.allocate!Thread();
thread.initialize_main_thread();
thread.initialize_first_thread();
current_thread = thread;
}
@ -110,6 +108,36 @@ struct Thread
{
Thread * thread = A1.allocate!Thread();
thread.initialize(fn);
swint(INT_TCTRL_YIELD);
return thread;
}
/**
* Trigger a thread management software interrupt.
*/
public static void swint(T1)(T1 v1)
{
mixin(`__asm("int $$`, cast(int)INT_KERNEL_SWINT, `", "{rax}", v1);`);
}
/**
* Handle a thread management software interrupt.
*
* This function is called in interrupt context.
*
* @param stack_frame
* Pointer to the stack frame.
*/
public static void handle_swint(ulong * stack_frame)
{
switch (stack_frame[ISF_RAX])
{
case INT_TCTRL_YIELD:
Thread.current_thread = Thread.current_thread.list_next;
break;
default:
break;
}
}
}