李述铜老师的手写操作系统,复习笔记。
这里需要强调的是原子操作,计算机是需要用硬件来保证,关闭硬件的中断,就是eflags寄存器。
irq_state_t irq_enter_protection (void) {
//开启中断,返回原来eflags的值
irq_state_t state = read_eflags();
irq_disable_global();
return state;
};
void irq_leave_protection (irq_state_t state) {
//关闭中断,设置eflags为原来的值
write_eflags(state);
};
信号量
sem结构描述
/**
* 进程同步用的计数信号量
*/
typedef struct _sem_t {
int count; // 信号量计数
list_t wait_list; // 等待的进程列表
}sem_t;
初始化
void sem_init (sem_t * sem, int init_count){
//信号量初始化
irq_state_t state=irq_enter_protection();
sem->count=init_count;
list_init(&sem->wait_list);
irq_leave_protection(state);
};
sem_wait
void sem_wait (sem_t * sem){
//等待信号
irq_state_t state=irq_enter_protection();
if(sem->count > 0 ){
//有空余的令牌,可以直接执行,但是要获取这个令牌
sem->count--;
}else{
//没有空余的令牌,加入到等待队列中,等待新的令牌
task_t *current_task=get_task_current();
task_set_block(current_task);
list_insert_last(&sem->wait_list,¤t_task->wait_node);
task_dispatch();
}
irq_leave_protection(state);
};
主要是当他等待的时候,需要把他加入到自己的等待队列中,然后通过偏移的方法,获取该结构体。
sem_notify
void sem_notify (sem_t * sem){
irq_state_t state=irq_enter_protection();
// 唤醒一个正在等待的进程
if(list_count(&sem->wait_list)){
// 有正在等待的进程,唤醒他,先进先出
list_node_t *ready_task_wait_node=list_remove_first(&sem->wait_list);
task_t *ready_task=list_node_parent(ready_task_wait_node,task_t,wait_node);
task_set_ready(ready_task);
task_dispatch();
}else{
// 没有,放回自己的令牌
sem->count++;
}
irq_leave_protection(state);
};
唤醒一个正在等待的进程,就是只是将sem_wait的等待列表里wait_node里移出来,然后设置任务的状态,等待任务的调度就行。
sem_count
int sem_count (sem_t * sem){
irq_state_t state=irq_enter_protection();
int count=sem->count;
irq_leave_protection(state);
return count;
};
这个返回的是当前有空余的令牌。
锁
锁的结构描述
/**
* 进程同步用的计数信号量
*/
typedef struct _mutex_t {
task_t * owner;
int locked_count;
list_t wait_list;
}mutex_t;
task_t *owner的描述的是拥有这个锁的任务,locked_count是上锁的次数。
初始化
void mutex_init (mutex_t * mutex){
mutex->owner=(task_t *)0;
mutex->owner=0;
list_init(&mutex->wait_list);
};
只是将所有的数置0
mutex_lock
void mutex_lock (mutex_t * mutex){
irq_state_t state = irq_enter_protection();
task_t *current_task=get_task_current();
if(mutex->locked_count==0){
// 之前没有上锁,让他获取锁
mutex->owner=current_task;
mutex->locked_count++;
}else if(mutex->owner==current_task){
// 这之前就是我的锁
mutex->locked_count++;
}
else{
// 已经上锁,加入到等待队列中
task_set_block(current_task);
list_insert_last(&mutex->wait_list,¤t_task->wait_node);
task_dispatch();
}
irq_leave_protection(state);
};
当需要获取锁的时候,需要把他加入到等待队列中,然后当其他程序释放锁的时候,在等待队列里拿出来一个出来运行就可以。
mutex_unlock
void mutex_unlock (mutex_t * mutex){
irq_state_t state = irq_enter_protection();
task_t *current_task=get_task_current();
if(mutex->owner==current_task){
// 是这个进程的锁
if(--mutex->locked_count==0){
// 释放锁
mutex->owner=(task_t *)0;
// 唤醒等待队列里的进程
if(list_count(&mutex->wait_list)){
list_node_t *wait_task_node=list_remove_first(&mutex->wait_list);
task_t *wait_task=list_node_parent(wait_task_node,task_t,wait_node);
task_set_ready(wait_task);
mutex->owner=wait_task;
mutex->locked_count=1;
task_dispatch();
}
}
}
irq_leave_protection(state);
};