《操作系统真象还原》第十篇:实现线程相关数据结构和双向链表

第十篇:实现线程相关数据结构和双向链表

实现线程相关数据结构

线程主要包含三个数据结构,中断栈,线程栈和进程控制块

中断栈

//中断栈,用于发生中断时保护程序的上下文,此栈在内核栈所在页的顶端
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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值