194 lines
3.7 KiB
C
194 lines
3.7 KiB
C
//
|
|
// test program for the alarm lab.
|
|
// you can modify this file for testing,
|
|
// but please make sure your kernel
|
|
// modifications pass the original
|
|
// versions of these tests.
|
|
//
|
|
|
|
#include "kernel/param.h"
|
|
#include "kernel/types.h"
|
|
#include "kernel/stat.h"
|
|
#include "kernel/riscv.h"
|
|
#include "user/user.h"
|
|
|
|
void test0();
|
|
void test1();
|
|
void test2();
|
|
void test3();
|
|
void periodic();
|
|
void slow_handler();
|
|
void dummy_handler();
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
test0();
|
|
test1();
|
|
test2();
|
|
test3();
|
|
exit(0);
|
|
}
|
|
|
|
volatile static int count;
|
|
|
|
void
|
|
periodic()
|
|
{
|
|
count = count + 1;
|
|
printf("alarm!\n");
|
|
sigreturn();
|
|
}
|
|
|
|
// tests whether the kernel calls
|
|
// the alarm handler even a single time.
|
|
void
|
|
test0()
|
|
{
|
|
int i;
|
|
printf("test0 start\n");
|
|
count = 0;
|
|
sigalarm(2, periodic);
|
|
for(i = 0; i < 1000*500000; i++){
|
|
if((i % 1000000) == 0)
|
|
write(2, ".", 1);
|
|
if(count > 0)
|
|
break;
|
|
}
|
|
sigalarm(0, 0);
|
|
if(count > 0){
|
|
printf("test0 passed\n");
|
|
} else {
|
|
printf("\ntest0 failed: the kernel never called the alarm handler\n");
|
|
}
|
|
}
|
|
|
|
void __attribute__ ((noinline)) foo(int i, int *j) {
|
|
if((i % 2500000) == 0) {
|
|
write(2, ".", 1);
|
|
}
|
|
*j += 1;
|
|
}
|
|
|
|
//
|
|
// tests that the kernel calls the handler multiple times.
|
|
//
|
|
// tests that, when the handler returns, it returns to
|
|
// the point in the program where the timer interrupt
|
|
// occurred, with all registers holding the same values they
|
|
// held when the interrupt occurred.
|
|
//
|
|
void
|
|
test1()
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
printf("test1 start\n");
|
|
count = 0;
|
|
j = 0;
|
|
sigalarm(2, periodic);
|
|
for(i = 0; i < 500000000; i++){
|
|
if(count >= 10)
|
|
break;
|
|
foo(i, &j);
|
|
}
|
|
if(count < 10){
|
|
printf("\ntest1 failed: too few calls to the handler\n");
|
|
} else if(i != j){
|
|
// the loop should have called foo() i times, and foo() should
|
|
// have incremented j once per call, so j should equal i.
|
|
// once possible source of errors is that the handler may
|
|
// return somewhere other than where the timer interrupt
|
|
// occurred; another is that that registers may not be
|
|
// restored correctly, causing i or j or the address ofj
|
|
// to get an incorrect value.
|
|
printf("\ntest1 failed: foo() executed fewer times than it was called\n");
|
|
} else {
|
|
printf("test1 passed\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// tests that kernel does not allow reentrant alarm calls.
|
|
void
|
|
test2()
|
|
{
|
|
int i;
|
|
int pid;
|
|
int status;
|
|
|
|
printf("test2 start\n");
|
|
if ((pid = fork()) < 0) {
|
|
printf("test2: fork failed\n");
|
|
}
|
|
if (pid == 0) {
|
|
count = 0;
|
|
sigalarm(2, slow_handler);
|
|
for(i = 0; i < 1000*500000; i++){
|
|
if((i % 1000000) == 0)
|
|
write(2, ".", 1);
|
|
if(count > 0)
|
|
break;
|
|
}
|
|
if (count == 0) {
|
|
printf("\ntest2 failed: alarm not called\n");
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
wait(&status);
|
|
if (status == 0) {
|
|
printf("test2 passed\n");
|
|
}
|
|
}
|
|
|
|
void
|
|
slow_handler()
|
|
{
|
|
count++;
|
|
printf("alarm!\n");
|
|
if (count > 1) {
|
|
printf("test2 failed: alarm handler called more than once\n");
|
|
exit(1);
|
|
}
|
|
for (int i = 0; i < 1000*500000; i++) {
|
|
asm volatile("nop"); // avoid compiler optimizing away loop
|
|
}
|
|
sigalarm(0, 0);
|
|
sigreturn();
|
|
}
|
|
|
|
//
|
|
// dummy alarm handler; after running immediately uninstall
|
|
// itself and finish signal handling
|
|
void
|
|
dummy_handler()
|
|
{
|
|
sigalarm(0, 0);
|
|
sigreturn();
|
|
}
|
|
|
|
//
|
|
// tests that the return from sys_sigreturn() does not
|
|
// modify the a0 register
|
|
void
|
|
test3()
|
|
{
|
|
uint64 a0;
|
|
|
|
sigalarm(1, dummy_handler);
|
|
printf("test3 start\n");
|
|
|
|
asm volatile("lui a5, 0");
|
|
asm volatile("addi a0, a5, 0xac" : : : "a0");
|
|
for(int i = 0; i < 500000000; i++)
|
|
;
|
|
asm volatile("mv %0, a0" : "=r" (a0) );
|
|
|
|
if(a0 != 0xac)
|
|
printf("test3 failed: register a0 changed\n");
|
|
else
|
|
printf("test3 passed\n");
|
|
}
|