发布于 

MIT 6.828 HW5 xv6 CPU alarm

Notes of MIT 6.828 HW5

Add a new alarm(interval, handler) system call.
If an application calls alarm(n, fn), then after every n ticks of CPU time that the program consumes, the kernel will cause application function fn to be called. When fn returns, the application will resume where it left off.

First, we modify the struct proc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct proc {
uint sz; // Size of process memory (bytes)
pde_t* pgdir; // Page table
char *kstack; // Bottom of kernel stack for this process
enum procstate state; // Process state
int pid; // Process ID
struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall
struct context *context; // swtch() here to run process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
// fields for alarm
int alarmticks;
int current_tick;
void (*alarmhandler)();
};

We also need to modify allocproc() in proc.c to initialize the fields we added.

1
2
p->current_tick = 0;
p->alarmticks = -1; // initialize alarmticks to -1

In syscall.c, add a function sys_alarm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int
sys_alarm(void)
{
int ticks;
void (*handler)();

if(argint(0, &ticks) < 0)
return -1;
if(argptr(1, (char**)&handler, 1) < 0)
return -1;
myproc()->alarmticks = ticks;
myproc()->alarmhandler = handler;
return 0;
}

In trap.c, add code handle case IRQ_TIMER.
In kernel mode, we can’t directly call alarmhandler. However, we need to modify the trapframe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
case T_IRQ0 + IRQ_TIMER:
if(cpuid() == 0){
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
}
lapiceoi();

// alarm
struct proc* p = myproc();
if(p != 0 && (tf->cs & 3) == 3) {
p->current_tick++;
if (p->current_tick == p->alarmticks) {
p->current_tick = 0;
// push old eip
tf->esp -= 4;
*(uint *)(tf->esp) = tf->eip;
// set eip to alarmhandler
tf->eip = (uint)p->alarmhandler;;
}
}

break;