[SMP] SMP synchronization and scheduling
This commit is contained in:
parent
8961ae33eb
commit
474914ab1e
@ -6,9 +6,13 @@
|
|||||||
#include <vga.h>
|
#include <vga.h>
|
||||||
#include <serial.h>
|
#include <serial.h>
|
||||||
#include <registers.h>
|
#include <registers.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
|
||||||
|
lock_t debug_lock;
|
||||||
|
|
||||||
void debug_init()
|
void debug_init()
|
||||||
{
|
{
|
||||||
|
spin_unlock(&debug_lock);
|
||||||
vga_init();
|
vga_init();
|
||||||
serial_init(PORT_COM1);
|
serial_init(PORT_COM1);
|
||||||
}
|
}
|
||||||
|
@ -30,25 +30,23 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
|
|||||||
pit_init();
|
pit_init();
|
||||||
|
|
||||||
process_t *p1 = process_spawn(0);
|
process_t *p1 = process_spawn(0);
|
||||||
process_t *p2 = process_spawn(p1);
|
|
||||||
|
|
||||||
thread_t *t1 = new_thread(thread_function);
|
thread_t *t1 = new_thread(thread_function);
|
||||||
thread_t *t2 = new_thread(thread_function);
|
|
||||||
thread_t *t3 = new_thread(thread_function);
|
|
||||||
|
|
||||||
process_attach(p1, t1);
|
process_attach(p1, t1);
|
||||||
process_attach(p2, t2);
|
|
||||||
process_attach(p1, t3);
|
|
||||||
|
|
||||||
vmm_set_page(p1->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE);
|
|
||||||
vmm_set_page(p2->P4, 0x10000, pmm_alloc(), PAGE_PRESENT | PAGE_WRITE);
|
|
||||||
|
|
||||||
vmm_p4_memcpy(p1->P4, (void *)0x10000, 0, "Hello, 1", 9);
|
|
||||||
vmm_p4_memcpy(p2->P4, (void *)0x10000, 0, "Hello, 2", 9);
|
|
||||||
|
|
||||||
scheduler_insert(t1);
|
scheduler_insert(t1);
|
||||||
scheduler_insert(t2);
|
t1 = new_thread(thread_function);
|
||||||
scheduler_insert(t3);
|
process_attach(p1, t1);
|
||||||
|
scheduler_insert(t1);
|
||||||
|
t1 = new_thread(thread_function);
|
||||||
|
process_attach(p1, t1);
|
||||||
|
scheduler_insert(t1);
|
||||||
|
t1 = new_thread(thread_function);
|
||||||
|
process_attach(p1, t1);
|
||||||
|
scheduler_insert(t1);
|
||||||
|
t1 = new_thread(thread_function);
|
||||||
|
process_attach(p1, t1);
|
||||||
|
scheduler_insert(t1);
|
||||||
|
|
||||||
asm("sti");
|
asm("sti");
|
||||||
debug_info("BOOT COMPLETE\n");
|
debug_info("BOOT COMPLETE\n");
|
||||||
|
@ -62,7 +62,9 @@ void cpu_init()
|
|||||||
all_ap_started = 1;
|
all_ap_started = 1;
|
||||||
|
|
||||||
vmm_set_page(0, TRAMPOLINE_ADDR, 0, 0);
|
vmm_set_page(0, TRAMPOLINE_ADDR, 0, 0);
|
||||||
pmm_free(page);
|
// Keep the GDT mapped for now
|
||||||
|
/* vmm_set_page(0, TRAMPOLINE_GDT, 0, 0); */
|
||||||
|
/* pmm_free(page); */
|
||||||
|
|
||||||
debug_info("CPU - Status\n");
|
debug_info("CPU - Status\n");
|
||||||
for(unsigned int i = 0; i < num_cpu; i++)
|
for(unsigned int i = 0; i < num_cpu; i++)
|
||||||
|
@ -49,5 +49,7 @@ void ap_start()
|
|||||||
while(!all_ap_started);
|
while(!all_ap_started);
|
||||||
cpu_t *cpu = get_cpu();
|
cpu_t *cpu = get_cpu();
|
||||||
debug_ok("STARTED CPU:%x\n", cpu->id);
|
debug_ok("STARTED CPU:%x\n", cpu->id);
|
||||||
|
schedule();
|
||||||
|
debug_error("PANIC: SMP - This line should be unreachable\n");
|
||||||
for(;;)asm("hlt");
|
for(;;)asm("hlt");
|
||||||
}
|
}
|
||||||
|
16
kernel/cpu/sync.S
Normal file
16
kernel/cpu/sync.S
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
.global spin_lock
|
||||||
|
spin_lock:
|
||||||
|
mov rdx, rdi
|
||||||
|
mov rax, 0x0
|
||||||
|
mov rcx, 0x1
|
||||||
|
.retry:
|
||||||
|
xor rax, rax
|
||||||
|
lock cmpxchg [rdx], cl
|
||||||
|
jnz .retry
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global spin_unlock
|
||||||
|
spin_unlock:
|
||||||
|
movq [rdi], 0x0
|
||||||
|
ret
|
@ -20,6 +20,7 @@
|
|||||||
#include <gdt.h>
|
#include <gdt.h>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <scheduler.h>
|
||||||
|
|
||||||
typedef struct cpu_t
|
typedef struct cpu_t
|
||||||
{
|
{
|
||||||
@ -51,6 +52,7 @@ void ap_init(cpu_t *cpu);
|
|||||||
|
|
||||||
void trampoline();
|
void trampoline();
|
||||||
void trampoline_GDT();
|
void trampoline_GDT();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
|
#include <sync.h>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define debug(...) debug_printf(__VA_ARGS__)
|
#define debug(...) ({spin_lock(&debug_lock);debug_printf(__VA_ARGS__);spin_unlock(&debug_lock);})
|
||||||
#else
|
#else
|
||||||
#define debug(...) ((void)0)
|
#define debug(...) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
@ -12,6 +13,8 @@
|
|||||||
#define debug_warning(...) do{debug("[WARNING] ");debug(__VA_ARGS__);}while(0)
|
#define debug_warning(...) do{debug("[WARNING] ");debug(__VA_ARGS__);}while(0)
|
||||||
#define debug_error(...) do{debug("[ERROR] ");debug(__VA_ARGS__);}while(0)
|
#define debug_error(...) do{debug("[ERROR] ");debug(__VA_ARGS__);}while(0)
|
||||||
|
|
||||||
|
extern lock_t debug_lock;
|
||||||
|
|
||||||
void debug_init();
|
void debug_init();
|
||||||
void debug_putch(char c);
|
void debug_putch(char c);
|
||||||
void debug_putsn(char *s, size_t n);
|
void debug_putsn(char *s, size_t n);
|
||||||
|
@ -4,12 +4,14 @@ typedef struct process_st process_t;
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <mem.h>
|
#include <mem.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
#include <sync.h>
|
||||||
|
|
||||||
typedef struct process_st
|
typedef struct process_st
|
||||||
{
|
{
|
||||||
uint64_t pid;
|
uint64_t pid;
|
||||||
uint64_t state;
|
uint64_t state;
|
||||||
uint64_t status;
|
uint64_t status;
|
||||||
|
lock_t lock;
|
||||||
struct process_st *parent;
|
struct process_st *parent;
|
||||||
page_table *P4;
|
page_table *P4;
|
||||||
LIST(struct process_st, children);
|
LIST(struct process_st, children);
|
||||||
|
6
kernel/include/sync.h
Normal file
6
kernel/include/sync.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef uint64_t lock_t;
|
||||||
|
|
||||||
|
void spin_lock(lock_t *lock);
|
||||||
|
void spin_unlock(lock_t *lock);
|
@ -2,6 +2,7 @@
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
|
#include <sync.h>
|
||||||
|
|
||||||
uint64_t pid = 1;
|
uint64_t pid = 1;
|
||||||
process_t *init_proc = 0;
|
process_t *init_proc = 0;
|
||||||
@ -20,7 +21,9 @@ process_t *process_spawn(process_t *parent)
|
|||||||
|
|
||||||
if(parent)
|
if(parent)
|
||||||
{
|
{
|
||||||
|
spin_lock(&parent->lock);
|
||||||
LIST_APPEND(parent->children, proc, siblings);
|
LIST_APPEND(parent->children, proc, siblings);
|
||||||
|
spin_unlock(&parent->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proc->pid == 1)
|
if(proc->pid == 1)
|
||||||
@ -31,8 +34,10 @@ process_t *process_spawn(process_t *parent)
|
|||||||
|
|
||||||
void process_attach(process_t *proc, thread_t *th)
|
void process_attach(process_t *proc, thread_t *th)
|
||||||
{
|
{
|
||||||
|
spin_lock(&proc->lock);
|
||||||
LIST_APPEND(proc->threads, th, process_threads);
|
LIST_APPEND(proc->threads, th, process_threads);
|
||||||
th->process = proc;
|
th->process = proc;
|
||||||
|
spin_unlock(&proc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_process(process_t *proc)
|
void switch_process(process_t *proc)
|
||||||
@ -60,6 +65,7 @@ void switch_process(process_t *proc)
|
|||||||
|
|
||||||
void process_exit(process_t *proc, uint64_t status)
|
void process_exit(process_t *proc, uint64_t status)
|
||||||
{
|
{
|
||||||
|
spin_lock(&proc->lock);
|
||||||
proc->status = status;
|
proc->status = status;
|
||||||
LIST_FOREACH(proc->children, process_t, c, siblings)
|
LIST_FOREACH(proc->children, process_t, c, siblings)
|
||||||
{
|
{
|
||||||
@ -69,6 +75,7 @@ void process_exit(process_t *proc, uint64_t status)
|
|||||||
LIST_APPEND(init_proc->children, c, siblings);
|
LIST_APPEND(init_proc->children, c, siblings);
|
||||||
}
|
}
|
||||||
proc->state = PROC_STATE_ZOMBIE;
|
proc->state = PROC_STATE_ZOMBIE;
|
||||||
|
spin_unlock(&proc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_free(process_t *proc)
|
void process_free(process_t *proc)
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <sse.h>
|
#include <sse.h>
|
||||||
#include <apic.h>
|
#include <apic.h>
|
||||||
|
#include <sync.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
LIST(thread_t, ready_queue);
|
LIST(thread_t, ready_queue);
|
||||||
|
|
||||||
@ -11,29 +13,37 @@ thread_t *scheduler_th;
|
|||||||
#define set_last_thread(new) (get_cpu()->last_thread = (new))
|
#define set_last_thread(new) (get_cpu()->last_thread = (new))
|
||||||
|
|
||||||
int scheduler_started = 0;
|
int scheduler_started = 0;
|
||||||
|
lock_t scheduler_lock = 0;
|
||||||
|
|
||||||
void scheduler_insert(thread_t *th)
|
void scheduler_insert(thread_t *th)
|
||||||
{
|
{
|
||||||
// Append thread to the ready queue and prepare it for running
|
// Append thread to the ready queue and prepare it for running
|
||||||
|
spin_lock(&scheduler_lock);
|
||||||
LIST_APPEND(ready_queue, th, ready_queue);
|
LIST_APPEND(ready_queue, th, ready_queue);
|
||||||
th->state = THREAD_STATE_READY;
|
th->state = THREAD_STATE_READY;
|
||||||
|
spin_unlock(&scheduler_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduler_remove(thread_t *th)
|
void scheduler_remove(thread_t *th)
|
||||||
{
|
{
|
||||||
// Remove thread from the ready queue
|
// Remove thread from the ready queue
|
||||||
|
spin_lock(&scheduler_lock);
|
||||||
LIST_REMOVE(ready_queue, th, ready_queue);
|
LIST_REMOVE(ready_queue, th, ready_queue);
|
||||||
|
spin_unlock(&scheduler_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_t *scheduler_next()
|
thread_t *scheduler_next()
|
||||||
{
|
{
|
||||||
// Get the next thread from the ready queue
|
// Get the next thread from the ready queue
|
||||||
|
spin_lock(&scheduler_lock);
|
||||||
if(!LIST_EMPTY(ready_queue))
|
if(!LIST_EMPTY(ready_queue))
|
||||||
{
|
{
|
||||||
thread_t *th = LIST_FIRST(ready_queue);
|
thread_t *th = LIST_FIRST(ready_queue);
|
||||||
scheduler_remove(th);
|
LIST_REMOVE(ready_queue, th, ready_queue);
|
||||||
|
spin_unlock(&scheduler_lock);
|
||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&scheduler_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
uint64_t tid = 1;
|
uint64_t tid = 1;
|
||||||
|
|
||||||
|
|
||||||
thread_t *new_thread(void (*func)(void))
|
thread_t *new_thread(void (*func)(void))
|
||||||
{
|
{
|
||||||
// Set up original stack of thread
|
// Set up original stack of thread
|
||||||
|
Loading…
x
Reference in New Issue
Block a user