summaryrefslogtreecommitdiff
path: root/user
diff options
context:
space:
mode:
Diffstat (limited to 'user')
-rw-r--r--user/cow.c196
-rw-r--r--user/usertests.c13
2 files changed, 206 insertions, 3 deletions
diff --git a/user/cow.c b/user/cow.c
new file mode 100644
index 0000000..45efc98
--- /dev/null
+++ b/user/cow.c
@@ -0,0 +1,196 @@
+//
+// 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(1, "simple: ");
+
+ char *p = sbrk(sz);
+ if(p == (char*)0xffffffffffffffffL){
+ printf(1, "sbrk(%d) failed\n", sz);
+ exit();
+ }
+
+ for(char *q = p; q < p + sz; q += 4096){
+ *(int*)q = getpid();
+ }
+
+ int pid = fork();
+ if(pid < 0){
+ printf(1, "fork() failed\n");
+ exit();
+ }
+
+ if(pid == 0)
+ exit();
+
+ wait();
+
+ if(sbrk(-sz) == (char*)0xffffffffffffffffL){
+ printf(1, "sbrk(-%d) failed\n", sz);
+ exit();
+ }
+
+ printf(1, "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(1, "three: ");
+
+ char *p = sbrk(sz);
+ if(p == (char*)0xffffffffffffffffL){
+ printf(1, "sbrk(%d) failed\n", sz);
+ exit();
+ }
+
+ pid1 = fork();
+ if(pid1 < 0){
+ printf(1, "fork failed\n");
+ exit();
+ }
+ if(pid1 == 0){
+ pid2 = fork();
+ if(pid2 < 0){
+ printf(1, "fork failed");
+ exit();
+ }
+ 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(1, "wrong content\n");
+ exit();
+ }
+ }
+ exit();
+ }
+ for(char *q = p; q < p + (sz/2); q += 4096){
+ *(int*)q = 9999;
+ }
+ exit();
+ }
+
+ for(char *q = p; q < p + sz; q += 4096){
+ *(int*)q = getpid();
+ }
+
+ wait();
+
+ sleep(1);
+
+ for(char *q = p; q < p + sz; q += 4096){
+ if(*(int*)q != getpid()){
+ printf(1, "wrong content\n");
+ exit();
+ }
+ }
+
+ if(sbrk(-sz) == (char*)0xffffffffffffffffL){
+ printf(1, "sbrk(-%d) failed\n", sz);
+ exit();
+ }
+
+ printf(1, "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()
+{
+ int parent = getpid();
+
+ printf(1, "file test: ");
+
+ buf[0] = 99;
+
+ for(int i = 0; i < 4; i++){
+ if(pipe(fds) != 0){
+ printf(1, "pipe() failed\n");
+ exit();
+ }
+ int pid = fork();
+ if(pid < 0){
+ printf(1, "fork failed\n");
+ exit();
+ }
+ if(pid == 0){
+ sleep(1);
+ if(read(fds[0], buf, sizeof(i)) != sizeof(i)){
+ printf(1, "read failed\n");
+ kill(parent);
+ exit();
+ }
+ sleep(1);
+ int j = *(int*)buf;
+ if(j != i){
+ printf(1, "read the wrong value\n");
+ kill(parent);
+ exit();
+ }
+ exit();
+ }
+ if(write(fds[1], &i, sizeof(i)) != sizeof(i)){
+ printf(1, "write failed\n");
+ exit();
+ }
+ }
+
+ for(int i = 0; i < 4; i++)
+ wait();
+
+ if(buf[0] != 99){
+ printf(1, "child overwrote parent\n");
+ exit();
+ }
+
+ printf(1, "ok\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ simpletest();
+
+ // check that the first simpletest() freed the physical memory.
+ simpletest();
+
+ threetest();
+ threetest();
+ threetest();
+
+ filetest();
+
+ printf(1, "ALL COW TESTS PASSED\n");
+
+ exit();
+}
diff --git a/user/usertests.c b/user/usertests.c
index beca8f9..ef70bfb 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -1438,6 +1438,13 @@ sbrktest(void)
printf(stdout, "sbrk test\n");
oldbrk = sbrk(0);
+ // does sbrk() return the expected failure value?
+ a = sbrk(1024*1024*1024);
+ if(a != (char*)0xffffffffffffffffL){
+ printf(stdout, "sbrk(<toomuch>) returned %p\n", a);
+ exit();
+ }
+
// can one sbrk() less than a page?
a = sbrk(0);
for(i = 0; i < 5000; i++){
@@ -1466,7 +1473,7 @@ sbrktest(void)
// can one grow address space to something big?
a = sbrk(0);
- amt = (BIG) - (uint64)a;
+ amt = BIG - (uint64)a;
p = sbrk(amt);
if (p != a) {
printf(stdout, "sbrk test failed to grow big address space; enough phys mem?\n");
@@ -1478,7 +1485,7 @@ sbrktest(void)
// can one de-allocate?
a = sbrk(0);
c = sbrk(-4096);
- if(c == (char*)0xffffffff){
+ if(c == (char*)0xffffffffffffffffL){
printf(stdout, "sbrk could not deallocate\n");
exit();
}
@@ -1551,7 +1558,7 @@ sbrktest(void)
kill(pids[i]);
wait();
}
- if(c == (char*)0xffffffff){
+ if(c == (char*)0xffffffffffffffffL){
printf(stdout, "failed sbrk leaked memory\n");
exit();
}