XV6 Series: MIT Labs 2024
Write-ups for Lab: Lock
Memory allocator
There are two requirements of this problem:
- Each CPU should have its own
freelist
andlock
. - In case, the current
freelist
is empty, the allocator should be able to steal thefreelist
of another CPU.
For the first requirement, we need to modify the kmem structure to the array of kmems as follows: From
struct {
struct spinlock lock;
struct run *freelist;
} kmem;
To
struct {
struct spinlock lock;
struct run *freelist;
} kmem[NCPU];
Then we need to modify the knit
and kfree
function to adapt to the new data structure.
void
()
kinit{
char lock_name[10]; // Each CPU should have a lock name
for (int i = 0; i < NCPU; i++) {
(lock_name, 10, "kmem_CPU%d", i); // Format the lock name
snprintf(&(kmem[i].lock), lock_name);
initlock}
(end, (void*)PHYSTOP); // Allocate all the free space to the CPU that executes this line.
freerange}
void
(void *pa)
kfree{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
("kfree");
panic
// Fill with junk to catch dangling refs.
(pa, 1, PGSIZE);
memset= (struct run*)pa;
r (); // Disable Interrupt
push_offint cpu = cpuid();
(); // Enable Interrupt
pop_off(&(kmem[cpu].lock));
acquire->next = kmem[cpu].freelist;
r[cpu].freelist = r;
kmem(&(kmem[cpu].lock));
release}
Finally, we modify the kalloc
function as follows:
void *
(void)
kalloc{
struct run *r;
(); // Disable Interrupt
push_offint cpu = cpuid();
(); // Enable Interrupt
pop_off(&kmem[cpu].lock);
acquire= kmem[cpu].freelist;
r if(r)
[cpu].freelist = r->next;
kmemelse {
// In case the current freelist is empty, we check the other lists of other CPUs
// and take the free spaces if they exist.
struct run *tmp;
// Loop through the list of CPUs
for (int i = 0; i < NCPU; i++) {
if (i == cpu) continue; // Skip if the CPU is the current CPU
(&kmem[i].lock);
acquire= kmem[i].freelist;
tmp if (tmp == 0) { // Skip if the freelist is empty
(&(kmem[i].lock));
release} else {
// steal 10 pages
for (int j = 0; j < 10; j++) {
if (tmp->next)
= tmp->next;
tmp else break;
}
[cpu].freelist = kmem[i].freelist;
kmem[i].freelist = tmp->next;
kmem->next = 0;
tmp(&(kmem[i].lock));
releasebreak;
}
}
= kmem[cpu].freelist;
r if (r)
[cpu].freelist = r->next;
kmem}
(&(kmem[cpu].lock));
release
if(r)
((char*)r, 5, PGSIZE); // fill with junk
memsetreturn (void*)r;
}