内核线程参考的是郑钢先生《操作系统真相还原》,主要是觉得这种实现线程和进程的方式非常的巧妙,另外在这方面想要创新的话,空间也是很小的。
为了编程方便,thread当中包含了进程的阻塞和唤醒以及二元信号量和锁,这些是实现互斥和同步的基础。
// thread.h
#ifndef __THREAD_H
#define __THREAD_H
#include "list.h"
#include "sync.h"
typedef void thread_func(void*);
enum task_status {
RUNNING, READY, BLOCKED, WAITING, HANDING, DIED
};
/*
_exit:
pop gs
pop fs
pop es
pop ds
popa
add esp, 2 * 4
iret
*/
struct mem_desc {
struct list_elem tag; //用它来串成链表
unsigned int start, size; // start页的起始地址,size内存的字节大小
int status; // status 正在被free使用0,或者正在被used使用1,或者空闲-1
};
struct mem_man {
struct mem_desc* md_a;
struct list free, used; // 两个链表一个是空闲,一个是使用
struct lock lock;
};
struct intr_stack {
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp_dummy;
unsigned int ebx, edx, ecx, eax;
unsigned int vector_no_dummy, err_code_dummy;
unsigned int eip, cs, eflags, esp, ss;
};
struct thread_stack {
unsigned int edi, esi, ebp, esp_dummy;
unsigned int ebx, edx, ecx, eax;
unsigned int kernel_thread;
unsigned int retaddr_dummy, func, func_arg;
};
struct task {
unsigned int* self_kstack;
unsigned int level;
unsigned short pid;
enum task_status status;
char name[16];
unsigned char priority;
unsigned char ticks;
unsigned int elapsed_ticks;
struct list_elem general_tag;
struct list_elem all_list_tag;
unsigned int* pgdir;
struct mem_man user_vir;
unsigned int stack_magic;
};
struct task* running_thread(void);
void kernel_thread(thread_func* function, void* func_arg);
void thread_create(struct task* pthread, thread_func function,
void* func_arg);
void init_thread(struct task* pthread, char* name, int prio, unsigned int level);
struct task* thread_start(char* name, int prio, thread_func function,
void * func_arg, unsigned int level);
void make_main_thread(void);
void schedule(void);
void thread_init(void);
void thread_block(enum task_status stat);
void thread_unblock(struct task* pthead);
struct task* main_thread;
struct list ready_list[8];
struct list* thread_ready_list;
struct list thread_all_list;
static struct list_elem* thread_tag;
void ticks_to_sleep(unsigned int sleep_ticks);
void mtime_sleep(unsigned int msecond);
struct lock pid_lock;
#endif
// thread.c
#include "list.h"
#include "thread.h"
#include "intr_status_op.h"
#include "memory.h"
#include "string.h"
#include "debug.h"
#include "sync.h"
#include "process.h"
extern void switch_to(struct task* cur, struct task* next);
extern unsigned int ticks;
struct task* running_thread(void) {
unsigned int esp;
__asm__ __volatile__("movl %%esp, %0":"=g"(esp));
return (struct task*)(esp & 0xfffff000);
}
void kernel_thread(thread_func* function, void* func_arg) {
intr_enable();
function(func_arg);
}
void thread_create(struct task* pthread, thread_func function, void* func_arg) {
pthread->self_kstack -= sizeof(struct intr_stack);
pthread->self_kstack -= sizeof(struct thread_stack);
struct thread_stack* kthread_stack =
(struct thread_stack*)pthread->self_kstack;
kthread_stack->kernel_thread = (unsigned int)kernel_thread;
kthread_stack->func = (unsigned int)function;
kthread_stack->func_arg = (unsigned int)func_arg;
kthread_stack->eax = kthread_stack->ecx = kthread_stack->edx =
kthread_stack->ebx = kthread_stack->esp_dummy = kthread_stack->ebp =
kthread_stack->esi = kthread_stack->edi = 0;
}
unsigned short alloc_pid(void) {
static unsigned int next_pid = 0;
lock_acquire(&pid_lock);
next_pid++;
lock_release(&pid_lock);
return next_pid;
}
void init_thread(struct task* pthread, char* name, int prio, unsigned int level) {
memset_(pthread, 0, sizeof(*pthread));
pthread->pid = alloc_pid();
strcpy_(pthread->name, name);
if(pthread == main_thread) {
pthread->status = RUNNING;
} else {
pthread->status = READY;
}
pthread->self_kstack = (unsigned int*)((unsigned int)pthread + 4096);
pthread->priority = prio;
pthread->ticks = prio;
pthread->level = level;
pthread->elapsed_ticks = 0;
pthread->pgdir = NULL;
pthread->stack_magic = 0x19810602;
}
struct task* thread_start(char* name, int prio, thread_func function,
void * func_arg, unsigned int level) {
struct task* thread = get_kernel_pages(1);
init_thread(thread, name, prio, level);
thread_create(thread, function, func_arg);
ASSERT((level >= 0) && (level <= 7));
thread_ready_list = &ready_list[thread->level];
ASSERT(!elem_find(thread_ready_list, &thread->general_tag));
list_append(thread_ready_list, &thread->general_tag);
ASSERT(!elem_find(&thread_all_list, &thread->all_list_tag));
list_append(&thread_all_list, &thread->all_list_tag);
return thread;
}
void make_main_thread(void) {
main_thread = running_thread();
init_thread(main_thread, "main", 31, 0);
ASSERT(!elem_find(&thread_all_list, &main_thread->all_list_tag));
list_append(&thread_all_list, &main_thread->all_list_tag);
}
void schedule(void) {
ASSERT((intr_get_status() == INTR_OFF));
struct task* cur = running_thread();
if(cur->status == RUNNING) {
ASSERT(!elem_find(thread_ready_list, &cur->general_tag));
list_append(thread_ready_list, &cur->general_tag);
cur->ticks = cur->priority;
cur->status = READY;
} else {
}
int i;
for(i = 0; i < 8; i++) {
thread_ready_list = &ready_list[i];
if(!list_empty(thread_ready_list)) {
break;
}
}
ASSERT(!list_empty(thread_ready_list));
thread_tag = list_pop(thread_ready_list);
struct task* next = elem2entry(struct task, general_tag, thread_tag);
next->status = RUNNING;
process_activate(next);
switch_to(cur, next);
}
void thread_init(void) {
int i;
for(i = 0; i < 8; i++) {
list_init(&ready_list[i]);
}
list_init(&thread_all_list);
lock_init(&pid_lock);
make_main_thread();
}
void thread_block(enum task_status stat) {
enum intr_status old_status = intr_disable();
ASSERT(((stat == BLOCKED) || (stat == HANDING) || (stat == WAITING)));
struct task* cur = running_thread();
cur->status = stat;
schedule();
intr_set_status(old_status);
}
void thread_unblock(struct task* pthread) {
enum intr_status old_status = intr_disable();
// ASSERT(((pthread->status == BLOCKED) ||
// (pthread->status == HANDING) ||
// (pthread->status == WAITING)));
if(pthread->status != READY) {
ASSERT(!(elem_find(thread_ready_list, &pthread->general_tag)));
if(elem_find(thread_ready_list, &pthread->general_tag)) {
PANIC("thread_unblock: blocked thread in ready_list\n");
}
list_push(thread_ready_list, &pthread->general_tag);
pthread->status = READY;
}
intr_set_status(old_status);
}
void yield(void) {
struct task* cur = running_thread();
enum intr_status old_status = intr_disable();
ASSERT(!elem_find(thread_ready_list, &cur->general_tag));
list_append(thread_ready_list, &cur->general_tag);
cur->status = READY;
schedule();
intr_set_status(old_status);
}
void ticks_to_sleep(unsigned int sleep_ticks) {
unsigned int short start_ticks = ticks;
while(ticks - start_ticks < sleep_ticks) {
yield();
}
}
void mtime_sleep(unsigned int msecond) {
unsigned sleep_ticks = msecond / 10 + 1;
ASSERT(sleep_ticks > 0);
ticks_to_sleep(sleep_ticks);
}
// sync.h
#ifndef __SYNC_H
#define __SYNC_H
#include "list.h"
#include "thread.h"
struct semaphore {
unsigned char value;
struct list waiters;
};
struct lock {
struct task* holder;
struct semaphore semaphore;
unsigned int holder_repeat_nr;
};
void sema_init(struct semaphore* psema, unsigned char value);
void lock_init(struct lock* plock);
void sema_down(struct semaphore* psema);
void sema_up(struct semaphore* psema);
void lock_acquire(struct lock* plock);
void lock_release(struct lock* plock);
#endif
// sync.c
#include "memory.h"
#include "intr_status_op.h"
#include "debug.h"
void sema_init(struct semaphore* psema, unsigned char value) {
psema->value = value;
list_init(&psema->waiters);
}
void lock_init(struct lock* plock) {
plock->holder = NULL;
plock->holder_repeat_nr = 0;
sema_init(&plock->semaphore, 1);
}
void sema_down(struct semaphore* psema) {
enum intr_status old_status = intr_disable();
while(psema->value == 0) {
ASSERT(!elem_find(&psema->waiters, &running_thread()->general_tag));
if(elem_find(&psema->waiters, &running_thread()->general_tag)) {
PANIC("seam_down: thread blocked has been in waiters_list\n");
}
list_append(&psema->waiters, &running_thread()->general_tag);
thread_block(BLOCKED);
}
psema->value--;
ASSERT(psema->value == 0);
intr_set_status(old_status);
}
void sema_up(struct semaphore* psema) {
enum intr_status old_status = intr_disable();
ASSERT(psema->value == 0);
if(!list_empty(&psema->waiters)) {
struct task* thread_blocked = elem2entry(struct task, general_tag,
list_pop(&psema->waiters));
thread_unblock(thread_blocked);
}
psema->value++;
ASSERT(psema->value == 1);
intr_set_status(old_status);
}
void lock_acquire(struct lock* plock) {
if(plock->holder != running_thread()) {
sema_down(&plock->semaphore);
plock->holder = running_thread();
ASSERT(plock->holder_repeat_nr == 0);
plock->holder_repeat_nr = 1;
} else {
plock->holder_repeat_nr++;
}
}
void lock_release(struct lock* plock) {
ASSERT(plock->holder == running_thread());
if(plock->holder_repeat_nr > 1) {
plock->holder_repeat_nr--;
return;
}
ASSERT(plock->holder_repeat_nr == 1);
plock->holder = NULL;
plock->holder_repeat_nr = 0;
sema_up(&plock->semaphore);
}