这个实验涉及到内存分配 锁 文件系统 的知识
Memory allocator
这部分任务是解决内存分配中锁争用导致变慢的问题
我们为每个cpu都分给一个 freelist 并带上一把锁
struct {
struct spinlock lock;
struct run *freelist;
} kmem[NCPU];
修改kinit
void
kinit()
{
for(int i=0;i<NCPU;i++)
{
initlock(&kmem[i].lock, "kmem");
}
freerange(end, (void*)PHYSTOP);
}
注意 在对应cpu时 我们要用到cpuid()函数 这个函数要求要关中断
kfree()很好修改
void
kfree(void *pa)
{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
push_off();
int id=cpuid();
pop_off();
acquire(&kmem[id].lock);
r->next = kmem[id].freelist;
kmem[id].freelist = r;
release(&kmem[id].lock);
}
kalloc()函数得满足当一个cpu的freelist不够是 去steal其他cpu的
void *
kalloc(void)
{
struct run *r;
push_off();
int id = cpuid();
pop_off();
acquire(&kmem[id].lock);
if(!kmem[id].freelist)
{
r=(struct run*)findfree(id);
if(r)
{
r->next=kmem[id].freelist;
kmem[id].freelist=r;
}
}
r = kmem[id].freelist;
if(r)
kmem[id].freelist = r->next;
release(&kmem[id].lock);
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
需要一个函数来遍历其他cpu的freelist
void *
findfree(int id)
{
for(int i=0;i<NCPU;i++)
{
if(i==id)
{
continue;
}
if(holding(&kmem[i].lock))
{
continue;
}
acquire(&kmem[i].lock);
struct run *r=kmem[i].freelist;
if(r)
{
kmem[i].freelist = r->next;
release(&kmem[i].lock);
return (void*)r;
}
release(&kmem[i].lock);
}
return 0;
}
注意里面代码的临界区
如何防止死锁 用if判断
中断的关闭和打开
Buffer cache
这部分实验是和上半部分独立的
难度上比上半部分大得多
hints
要把单独的bcache buf设计哈希表映射块
根据提示我们可以设计成 13个buckets
在哈希表中查找 buffer 和未找到分配条目一定要是原子操作
要把所有的关于buffer的链表删除(head) 转而用 ticks in kernel/trap.c作为时间戳的buf
此时,brelse就不需要获取bcache锁,bget可以根据时间戳找到LRU
某些情况必须持有两个锁 一个 bcache锁一个bucket锁 要注意避免死锁
块的替换可能会在两个不同的桶发生,要处理在同一个桶中发生的情况