练习0:填写已有实验
请把你做的实验代码填入本实验中代码中有“LAB1”/“LAB2”/“LAB3”/“LAB4”/“LAB5”/“LAB6”的注释相应部分。并确保编译通过。注意:为了能够正确执行lab7的测试应用程序,可能需对已完成的实验1/2/3/4/5/6的代码进行进一步改进。
1 2 3 4 5 6 7 8 9 10
| 这次又是要修改 trap.c vmm.c trap.c default_pmm.c pmm.c proc.c swap_fifo.c trap.c: static void trap_dispatch(struct trapframe *tf) { ++ticks;
run_timer_list(); }
|
练习1: 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题
请在实验报告中给出内核级信号量的设计描述,并说其大致执行流流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| typedef struct { int value; wait_queue_t wait_queue; } semaphore_t;
typedef struct { struct proc_struct *proc; uint32_t wakeup_flags; wait_queue_t *wait_queue; list_entry_t wait_link; } wait_t;
void sem_init(semaphore_t *sem, int value) { sem->value = value; wait_queue_init(&(sem->wait_queue)); }
static __noinline uint32_t __down(semaphore_t *sem, uint32_t wait_state) { bool intr_flag; local_intr_save(intr_flag); if (sem->value > 0) { sem->value --; local_intr_restore(intr_flag); return 0; } wait_t __wait, *wait = &__wait; wait_current_set(&(sem->wait_queue), wait, wait_state); local_intr_restore(intr_flag);
schedule();
local_intr_save(intr_flag); wait_current_del(&(sem->wait_queue), wait); local_intr_restore(intr_flag);
if (wait->wakeup_flags != wait_state) { return wait->wakeup_flags; } return 0; }
static __noinline void __up(semaphore_t *sem, uint32_t wait_state) { bool intr_flag; local_intr_save(intr_flag); { wait_t *wait; if ((wait = wait_queue_first(&(sem->wait_queue))) == NULL) { sem->value ++; } else { assert(wait->proc->wait_state == wait_state); wakeup_wait(&(sem->wait_queue), wait, wait_state, 1); } } local_intr_restore(intr_flag); }
|
请在实验报告中给出给用户态进程/线程提供信号量机制的设计方案,并比较说明给内核级提供信号量机制的异同。
1 2 3
| 可以将内核级信号量 包装成系统调用 供用户进程使用 但不能直接使用信号量结构体的指针作为参数 不能持有或访问内核的指针 可以在每个进程的PCB里维护一个信号量指针数组 供用户态进程及其进程下的多线程使用 不同的地方在于 需要通过系统调用进入 内核态 进行操作
|
练习2: 完成内核级条件变量和基于内核级条件变量的哲学家就餐问题
首先掌握管程机制,然后基于信号量实现完成条件变量实现,然后用管程机制实现哲学家就餐问题的解决方案(基于条件变量)。
请在实验报告中给出内核级条件变量的设计描述,并说其大致执行流流程。
首先可以确定 这里实现的是 Hoare管程 因为 等待条件变量的进程的优先级更高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| typedef struct monitor{ semaphore_t mutex; semaphore_t next; int next_count; condvar_t *cv; } monitor_t;
typedef struct condvar{ semaphore_t sem; int count; monitor_t * owner; } condvar_t;
void monitor_init (monitor_t * mtp, size_t num_cv) { int i; assert(num_cv>0); mtp->next_count = 0; mtp->cv = NULL; sem_init(&(mtp->mutex), 1); sem_init(&(mtp->next), 0); mtp->cv =(condvar_t *) kmalloc(sizeof(condvar_t)*num_cv); assert(mtp->cv!=NULL); for(i=0; i<num_cv; i++){ mtp->cv[i].count=0; sem_init(&(mtp->cv[i].sem),0); mtp->cv[i].owner=mtp; } }
void cond_wait (condvar_t *cvp) { cprintf("cond_wait begin: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
cvp->count++; if (cvp->owner->next_count > 0) { up(&(cvp->owner->next)); } else { up(&(cvp->owner->mutex)); }
down(&(cvp->sem)); cvp->count--;
cprintf("cond_wait end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); }
void cond_signal (condvar_t *cvp) { cprintf("cond_signal begin: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
if (cvp->count > 0) { up(&(cvp->sem)); cvp->owner->next_count++; down(&(cvp->owner->next)); cvp->owner->next_count--; } cprintf("cond_signal end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| check_sync.c:
void phi_test_condvar (i) { if(state_condvar[i]==HUNGRY&&state_condvar[LEFT]!=EATING &&state_condvar[RIGHT]!=EATING) { cprintf("phi_test_condvar: state_condvar[%d] will eating\n",i); state_condvar[i] = EATING ; cprintf("phi_test_condvar: signal self_cv[%d] \n",i); cond_signal(&mtp->cv[i]) ; } }
void phi_take_forks_condvar(int i) { down(&(mtp->mutex)); state_condvar[i] = HUNGRY; phi_test_condvar(i); while (state_condvar[i] != EATING) { cond_wait(&mtp->cv[i]); } if(mtp->next_count>0) up(&(mtp->next)); else up(&(mtp->mutex)); }
void phi_put_forks_condvar(int i) { down(&(mtp->mutex)); state_condvar[i] = THINKING; phi_test_condvar(LEFT); phi_test_condvar(RIGHT); if(mtp->next_count>0) up(&(mtp->next)); else up(&(mtp->mutex)); }
|
1 2 3 4 5 6
| 哲学家->试试拿刀叉->能拿->signal 唤醒被wait阻塞的进程->阻塞自己 | | A | V | ->不能拿->wait阻塞自己 | | 哲学家->放刀叉->让左右两边试试拿刀叉->有哲学家睡在signal 唤醒他
|
请在实验报告中给出给用户态进程/线程提供条件变量机制的设计方案,并比较说明给内核级提供条件变量机制的异同。
请在实验报告中回答:能否不用基于信号量机制来完成条件变量?如果不能,请给出理由,如果能,请给出设计说明和具体实现。
实验完成结果