第十篇:实现线程相关数据结构和双向链表
实现线程相关数据结构
线程主要包含三个数据结构,中断栈,线程栈和进程控制块
中断栈
//中断栈,用于发生中断时保护程序的上下文,此栈在内核栈所在页的顶端
struct intr_stack {
//中断号
uint32_t vec_no;
//寄存器现场
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp_dummy;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t gs;
uint32_t fs;
uint32_t es;
uint32_t ds;
//当发生特权级转移时压入
uint32_t err_code;
void (*eip)(void);
uint32_t cs;
uint32_t eflags;
void* esp;
uint32_t ss;
};
线程栈
当线程从就绪队列加载上cpu时,需要从线程栈中获取保存的寄存器和返回地址。
//线程栈,用于存储线程中待执行的函数
//位置不固定,用于switch_to时保存线程环境
struct thread_stack {
uint32_t ebp;
uint32_t ebx;
uint32_t edi;
uint32_t esi;
//线程第一次执行时,eip指向待调用的函数kernel_thread
//其他时候,eip是指向switch_to的返回地址
void (*eip)(thread_func* func, void* func_args);
//以下仅供第一次被调度上cpu时使用
//返回地址,占位
void (*unused_rtnaddr);
//由kernel_thread调用的函数名
thread_func* function;
//由kernel_thread调用的函数的参数
void* func_args;
};
进程控制块PCB
进程控制块包含进程相关的属性,并且将用双向链表将所有进程控制块连接在一起。
//进程的PCB,位于内核栈所在页的低端
struct task_struct {
//内核栈的地址
uint32_t* self_kstack;
//线程状态
enum task_status status;
//线程名
char name[16];
//线程的优先级
uint8_t priority;
//每次在处理器上执行的滴答数
uint8_t ticks;
//此任务上cpu后执行的总滴答数
uint32_t elapsed_ticks;
//用于在一般的thread_ready_list中
struct list_node general_tag;
//用于在thrad_all_list中
struct list_node all_list_tag;
//进程自己的页表地址
uint32_t* pgdir;
//魔数,用于检测栈的溢出
uint32_t stack_magic;
};
初始化函数
//由kernel_thread去执行function(args)
void kernel_thread(thread_func* function, void* func_args) {
//执行线程前要开启中断,避免后面的时钟中断被屏蔽,而无法调度其他线程
intr_enable();
function(func_args);
}
//初始化线程栈
void thread_create(struct task_struct* pthread, thread_func function, void* func_args) {
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->eip = kernel_thread;
kthread_stack->function = function;
kthread_stack->func_args = func_args;
kthread_stack->ebp = 0;
kthread_stack->ebx = 0;
kthread_stack->esi = 0;
kthread_stack->edi = 0;
}
//初始化线程基本信息PCB
void init_thread(struct task_struct* pthread, char* name, uint8_t priority) {
//将PCB清0
memset(pthread, 0, sizeof(*pthread));
if (pthread == main_thread) {
pthread->status = TASK_RUNNING;
} else {
pthread->status = TASK_READY;
}
pthread->self_kstack = (uint32_t*)((uint32_t)pthread + PG_SIZE);
pthread->priority = priority;
pthread->ticks = priority;
pthread->elapsed_ticks = 0;
pthread->pgdir = NULL;
strcpy(pthread->name, name);
//自定义魔数
pthread->stack_magic = 0x20030621;
}
//创建线程并执行
struct task_struct* thread_start(char* name, uint8_t priority, thread_func function, void* func_args) {
//pcb都在内核空间
struct task_struct* thread = get_kernel_pages(1);
init_thread(thread, name, priority);
thread_create(thread, function, func_args);
//确保之前不再队列中
ASSERT(!node_find(&thread_ready_list, &thread->general_tag));
//加入就绪线程队列
list_append(&thread_ready_list, &thread->general_tag);
//确保之前不再队列中
ASSERT(!node_find(&thread_all_list, &thread->all_list_tag));
//加入全部线程队列
list_append(&thread_all_list, &thread->all_list_tag);
return thread;
}
实现双向链表
结构体定义
//双向链表的结点,因为我们只需要结点本身的地址,所以不需要数据成员
struct list_node {
//前驱结点
struct list_node* prev;
//后继结点
struct list_node* next;
};
//双向链表数据结构
struct list {
struct list_node head;
struct list_node tail;
};
操作函数
//初始化双向链表
void list_init(struct list* list) {
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
//把node插入在before之前
void list_insert_before(struct list_node* before, struct list_node* node) {
//关闭中断
enum intr_status old_status = intr_disable();
//修改结点指针
before->prev->next = node;
node->prev = before->prev;
node->next = before;
before->prev = node;
//恢复中断
set_intr_status(old_status);
}
//把node结点插入到链表首
void list_push(struct list* list, struct list_node* node) {
list_insert_before(list->head.next, node);
}
//把node结点插入到链表末端
void list_append(struct list* list, struct list_node* node) {
list_insert_before(&list->tail, node);
}
//使node脱离链表
void list_remove(struct list_node* node) {
//关闭中断
enum intr_status old_status = intr_disable();
node->prev->next = node->next;
node->next->prev = node->prev;
//恢复中断
set_intr_status(old_status);
}
//将链表第一个元素弹出并返回
struct list_node* list_pop(struct list* list) {
struct list_node* top = list->head.next;
list_remove(top);
return top;
}
//从链表中寻找node元素
uint32_t node_find(struct list* list, struct list_node* node) {
struct list_node* curr = list->head.next;
//遍历链表并比较
while (curr != &list->tail) {
if (curr == node) {
return 1;
}
curr = curr->next;
}
return 0;
}
//遍历链表所有元素,逐个判断是否有符合条件的元素
struct list_node* list_traversal(struct list* list, function func, uint32_t args) {
struct list_node* curr = list->head.next;
while (curr != &list->tail) {
if (func(curr, args)) {
//如果curr符合回调函数的条件,则返回
return curr;
}
curr = curr->next;
}
return NULL;
}
//返回链表长度
uint32_t list_len(struct list* list) {
struct list_node* curr = list->head.next;
uint32_t len = 0;
while (curr != &list->tail) {
len++;
curr = curr->next;
}
return len;
}
//判断链表是否为空
uint32_t list_empty(struct list* list) {
return (list->head.next == &list->tail ? 1 : 0);
}