cow lab initialized
This commit is contained in:
193
user/alarmtest.c
193
user/alarmtest.c
@@ -1,193 +0,0 @@
|
||||
//
|
||||
// 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");
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
sleep(1);
|
||||
exit(0);
|
||||
}
|
||||
17
user/call.c
17
user/call.c
@@ -1,17 +0,0 @@
|
||||
#include "kernel/param.h"
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "user/user.h"
|
||||
|
||||
int g(int x) {
|
||||
return x+3;
|
||||
}
|
||||
|
||||
int f(int x) {
|
||||
return g(x);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
printf("%d %d\n", f(8)+1, 13);
|
||||
exit(0);
|
||||
}
|
||||
240
user/cowtest.c
Normal file
240
user/cowtest.c
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// tests for copy-on-write fork() assignment.
|
||||
//
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/memlayout.h"
|
||||
#include "user/user.h"
|
||||
|
||||
// allocate more than half of physical memory,
|
||||
// then fork. this will fail in the default
|
||||
// kernel, which does not support copy-on-write.
|
||||
void
|
||||
simpletest()
|
||||
{
|
||||
uint64 phys_size = PHYSTOP - KERNBASE;
|
||||
int sz = (phys_size / 3) * 2;
|
||||
|
||||
printf("simple: ");
|
||||
|
||||
char *p = sbrk(sz);
|
||||
if(p == (char*)0xffffffffffffffffL){
|
||||
printf("sbrk(%d) failed\n", sz);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if(pid < 0){
|
||||
printf("fork() failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(pid == 0)
|
||||
exit(0);
|
||||
|
||||
wait(0);
|
||||
|
||||
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
|
||||
printf("sbrk(-%d) failed\n", sz);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
// three processes all write COW memory.
|
||||
// this causes more than half of physical memory
|
||||
// to be allocated, so it also checks whether
|
||||
// copied pages are freed.
|
||||
void
|
||||
threetest()
|
||||
{
|
||||
uint64 phys_size = PHYSTOP - KERNBASE;
|
||||
int sz = phys_size / 4;
|
||||
int pid1, pid2;
|
||||
|
||||
printf("three: ");
|
||||
|
||||
char *p = sbrk(sz);
|
||||
if(p == (char*)0xffffffffffffffffL){
|
||||
printf("sbrk(%d) failed\n", sz);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pid1 = fork();
|
||||
if(pid1 < 0){
|
||||
printf("fork failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
if(pid1 == 0){
|
||||
pid2 = fork();
|
||||
if(pid2 < 0){
|
||||
printf("fork failed");
|
||||
exit(-1);
|
||||
}
|
||||
if(pid2 == 0){
|
||||
for(char *q = p; q < p + (sz/5)*4; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
for(char *q = p; q < p + (sz/5)*4; q += 4096){
|
||||
if(*(int*)q != getpid()){
|
||||
printf("wrong content\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
exit(-1);
|
||||
}
|
||||
for(char *q = p; q < p + (sz/2); q += 4096){
|
||||
*(int*)q = 9999;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
*(int*)q = getpid();
|
||||
}
|
||||
|
||||
wait(0);
|
||||
|
||||
sleep(1);
|
||||
|
||||
for(char *q = p; q < p + sz; q += 4096){
|
||||
if(*(int*)q != getpid()){
|
||||
printf("wrong content\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
|
||||
printf("sbrk(-%d) failed\n", sz);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
char junk1[4096];
|
||||
int fds[2];
|
||||
char junk2[4096];
|
||||
char buf[4096];
|
||||
char junk3[4096];
|
||||
|
||||
// test whether copyout() simulates COW faults.
|
||||
void
|
||||
filetest()
|
||||
{
|
||||
printf("file: ");
|
||||
|
||||
buf[0] = 99;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(pipe(fds) != 0){
|
||||
printf("pipe() failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
int pid = fork();
|
||||
if(pid < 0){
|
||||
printf("fork failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
if(pid == 0){
|
||||
sleep(1);
|
||||
if(read(fds[0], buf, sizeof(i)) != sizeof(i)){
|
||||
printf("error: read failed\n");
|
||||
exit(1);
|
||||
}
|
||||
sleep(1);
|
||||
int j = *(int*)buf;
|
||||
if(j != i){
|
||||
printf("error: read the wrong value\n");
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
if(write(fds[1], &i, sizeof(i)) != sizeof(i)){
|
||||
printf("error: write failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int xstatus = 0;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
wait(&xstatus);
|
||||
if(xstatus != 0) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(buf[0] != 99){
|
||||
printf("error: child overwrote parent\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
//
|
||||
// try to expose races in page reference counting.
|
||||
//
|
||||
void
|
||||
forkforktest()
|
||||
{
|
||||
printf("forkfork: ");
|
||||
|
||||
int sz = 256 * 4096;
|
||||
char *p = sbrk(sz);
|
||||
memset(p, 27, sz);
|
||||
|
||||
int children = 3;
|
||||
|
||||
for(int iter = 0; iter < 100; iter++){
|
||||
for(int nc = 0; nc < children; nc++){
|
||||
if(fork() == 0){
|
||||
sleep(2);
|
||||
fork();
|
||||
fork();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
for(int nc = 0; nc < children; nc++){
|
||||
int st;
|
||||
wait(&st);
|
||||
}
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
for(int i = 0; i < sz; i += 4096){
|
||||
if(p[i] != 27){
|
||||
printf("error: parent's memory was modified!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
simpletest();
|
||||
|
||||
// check that the first simpletest() freed the physical memory.
|
||||
simpletest();
|
||||
|
||||
threetest();
|
||||
threetest();
|
||||
threetest();
|
||||
|
||||
filetest();
|
||||
|
||||
forkforktest();
|
||||
|
||||
printf("ALL COW TESTS PASSED\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -22,8 +22,6 @@ int getpid(void);
|
||||
char* sbrk(int);
|
||||
int sleep(int);
|
||||
int uptime(void);
|
||||
int sigalarm(int, void(*)());
|
||||
int sigreturn(void);
|
||||
|
||||
// ulib.c
|
||||
int stat(const char*, struct stat*);
|
||||
|
||||
@@ -244,7 +244,7 @@ copyinstr3(char *s)
|
||||
// See if the kernel refuses to read/write user memory that the
|
||||
// application doesn't have anymore, because it returned it.
|
||||
void
|
||||
rwsbrk(char* argv)
|
||||
rwsbrk()
|
||||
{
|
||||
int fd, n;
|
||||
|
||||
|
||||
@@ -36,5 +36,3 @@ entry("getpid");
|
||||
entry("sbrk");
|
||||
entry("sleep");
|
||||
entry("uptime");
|
||||
entry("sigalarm");
|
||||
entry("sigreturn");
|
||||
|
||||
Reference in New Issue
Block a user