diff options
| author | Sanjit Bhat <sanjit.bhat@gmail.com> | 2023-11-01 14:12:57 -0400 | 
|---|---|---|
| committer | Sanjit Bhat <sanjit.bhat@gmail.com> | 2023-11-01 14:12:57 -0400 | 
| commit | 4dc51124c8a8e3f1914add43bf1376663eb9a9b8 (patch) | |
| tree | a20df7f896f1618a0750c541975a71dd49a38259 /user | |
| parent | 74c1eba516fdb0ec1a17b16be7e76613ccba92bf (diff) | |
| download | xv6-labs-4dc51124c8a8e3f1914add43bf1376663eb9a9b8.tar.gz xv6-labs-4dc51124c8a8e3f1914add43bf1376663eb9a9b8.tar.bz2 xv6-labs-4dc51124c8a8e3f1914add43bf1376663eb9a9b8.zip | |
mmap: release lab
Diffstat (limited to 'user')
| -rw-r--r-- | user/mmaptest.c | 297 | 
1 files changed, 297 insertions, 0 deletions
| diff --git a/user/mmaptest.c b/user/mmaptest.c new file mode 100644 index 0000000..0819622 --- /dev/null +++ b/user/mmaptest.c @@ -0,0 +1,297 @@ +#include "kernel/param.h" +#include "kernel/fcntl.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "kernel/riscv.h" +#include "kernel/fs.h" +#include "user/user.h" + +void mmap_test(); +void fork_test(); +char buf[BSIZE]; + +#define MAP_FAILED ((char *) -1) + +int +main(int argc, char *argv[]) +{ +  mmap_test(); +  fork_test(); +  printf("mmaptest: all tests succeeded\n"); +  exit(0); +} + +char *testname = "???"; + +void +err(char *why) +{ +  printf("mmaptest: %s failed: %s, pid=%d\n", testname, why, getpid()); +  exit(1); +} + +// +// check the content of the two mapped pages. +// +void +_v1(char *p) +{ +  int i; +  for (i = 0; i < PGSIZE*2; i++) { +    if (i < PGSIZE + (PGSIZE/2)) { +      if (p[i] != 'A') { +        printf("mismatch at %d, wanted 'A', got 0x%x\n", i, p[i]); +        err("v1 mismatch (1)"); +      } +    } else { +      if (p[i] != 0) { +        printf("mismatch at %d, wanted zero, got 0x%x\n", i, p[i]); +        err("v1 mismatch (2)"); +      } +    } +  } +} + +// +// create a file to be mapped, containing +// 1.5 pages of 'A' and half a page of zeros. +// +void +makefile(const char *f) +{ +  int i; +  int n = PGSIZE/BSIZE; + +  unlink(f); +  int fd = open(f, O_WRONLY | O_CREATE); +  if (fd == -1) +    err("open"); +  memset(buf, 'A', BSIZE); +  // write 1.5 page +  for (i = 0; i < n + n/2; i++) { +    if (write(fd, buf, BSIZE) != BSIZE) +      err("write 0 makefile"); +  } +  if (close(fd) == -1) +    err("close"); +} + +void +mmap_test(void) +{ +  int fd; +  int i; +  const char * const f = "mmap.dur"; +  printf("mmap_test starting\n"); +  testname = "mmap_test"; + +  // +  // create a file with known content, map it into memory, check that +  // the mapped memory has the same bytes as originally written to the +  // file. +  // +  makefile(f); +  if ((fd = open(f, O_RDONLY)) == -1) +    err("open"); + +  printf("test mmap f\n"); +  // +  // this call to mmap() asks the kernel to map the content +  // of open file fd into the address space. the first +  // 0 argument indicates that the kernel should choose the +  // virtual address. the second argument indicates how many +  // bytes to map. the third argument indicates that the +  // mapped memory should be read-only. the fourth argument +  // indicates that, if the process modifies the mapped memory, +  // that the modifications should not be written back to +  // the file nor shared with other processes mapping the +  // same file (of course in this case updates are prohibited +  // due to PROT_READ). the fifth argument is the file descriptor +  // of the file to be mapped. the last argument is the starting +  // offset in the file. +  // +  char *p = mmap(0, PGSIZE*2, PROT_READ, MAP_PRIVATE, fd, 0); +  if (p == MAP_FAILED) +    err("mmap (1)"); +  _v1(p); +  if (munmap(p, PGSIZE*2) == -1) +    err("munmap (1)"); + +  printf("test mmap f: OK\n"); +     +  printf("test mmap private\n"); +  // should be able to map file opened read-only with private writable +  // mapping +  p = mmap(0, PGSIZE*2, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +  if (p == MAP_FAILED) +    err("mmap (2)"); +  if (close(fd) == -1) +    err("close"); +  _v1(p); +  for (i = 0; i < PGSIZE*2; i++) +    p[i] = 'Z'; +  if (munmap(p, PGSIZE*2) == -1) +    err("munmap (2)"); + +  printf("test mmap private: OK\n"); +     +  printf("test mmap read-only\n"); +     +  // check that mmap doesn't allow read/write mapping of a +  // file opened read-only. +  if ((fd = open(f, O_RDONLY)) == -1) +    err("open"); +  p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +  if (p != MAP_FAILED) +    err("mmap call should have failed"); +  if (close(fd) == -1) +    err("close"); + +  printf("test mmap read-only: OK\n"); +     +  printf("test mmap read/write\n"); +   +  // check that mmap does allow read/write mapping of a +  // file opened read/write. +  if ((fd = open(f, O_RDWR)) == -1) +    err("open"); +  p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +  if (p == MAP_FAILED) +    err("mmap (3)"); +  if (close(fd) == -1) +    err("close"); + +  // check that the mapping still works after close(fd). +  _v1(p); + +  // write the mapped memory. +  for (i = 0; i < PGSIZE*2; i++) +    p[i] = 'Z'; + +  // unmap just the first two of three pages of mapped memory. +  if (munmap(p, PGSIZE*2) == -1) +    err("munmap (3)"); +   +  printf("test mmap read/write: OK\n"); +   +  printf("test mmap dirty\n"); +   +  // check that the writes to the mapped memory were +  // written to the file. +  if ((fd = open(f, O_RDWR)) == -1) +    err("open"); +  for (i = 0; i < PGSIZE + (PGSIZE/2); i++){ +    char b; +    if (read(fd, &b, 1) != 1) +      err("read (1)"); +    if (b != 'Z') +      err("file does not contain modifications"); +  } +  if (close(fd) == -1) +    err("close"); + +  printf("test mmap dirty: OK\n"); + +  printf("test not-mapped unmap\n"); +   +  // unmap the rest of the mapped memory. +  if (munmap(p+PGSIZE*2, PGSIZE) == -1) +    err("munmap (4)"); + +  printf("test not-mapped unmap: OK\n"); +     +  printf("test mmap two files\n"); +   +  // +  // mmap two files at the same time. +  // +  int fd1; +  if((fd1 = open("mmap1", O_RDWR|O_CREATE)) < 0) +    err("open mmap1"); +  if(write(fd1, "12345", 5) != 5) +    err("write mmap1"); +  char *p1 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd1, 0); +  if(p1 == MAP_FAILED) +    err("mmap mmap1"); +  close(fd1); +  unlink("mmap1"); + +  int fd2; +  if((fd2 = open("mmap2", O_RDWR|O_CREATE)) < 0) +    err("open mmap2"); +  if(write(fd2, "67890", 5) != 5) +    err("write mmap2"); +  char *p2 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd2, 0); +  if(p2 == MAP_FAILED) +    err("mmap mmap2"); +  close(fd2); +  unlink("mmap2"); + +  if(memcmp(p1, "12345", 5) != 0) +    err("mmap1 mismatch"); +  if(memcmp(p2, "67890", 5) != 0) +    err("mmap2 mismatch"); + +  munmap(p1, PGSIZE); +  if(memcmp(p2, "67890", 5) != 0) +    err("mmap2 mismatch (2)"); +  munmap(p2, PGSIZE); +   +  printf("test mmap two files: OK\n"); +   +  printf("mmap_test: ALL OK\n"); +} + +// +// mmap a file, then fork. +// check that the child sees the mapped file. +// +void +fork_test(void) +{ +  int fd; +  int pid; +  const char * const f = "mmap.dur"; +   +  printf("fork_test starting\n"); +  testname = "fork_test"; +   +  // mmap the file twice. +  makefile(f); +  if ((fd = open(f, O_RDONLY)) == -1) +    err("open"); +  unlink(f); +  char *p1 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0); +  if (p1 == MAP_FAILED) +    err("mmap (4)"); +  char *p2 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0); +  if (p2 == MAP_FAILED) +    err("mmap (5)"); + +  // read just 2nd page. +  if(*(p1+PGSIZE) != 'A') +    err("fork mismatch (1)"); + +  if((pid = fork()) < 0) +    err("fork"); +  if (pid == 0) { +    _v1(p1); +    munmap(p1, PGSIZE); // just the first page +    exit(0); // tell the parent that the mapping looks OK. +  } + +  int status = -1; +  wait(&status); + +  if(status != 0){ +    printf("fork_test failed\n"); +    exit(1); +  } + +  // check that the parent's mappings are still there. +  _v1(p1); +  _v1(p2); + +  printf("fork_test OK\n"); +} + | 
