<OS Lab Notes

Lab1 unix utilities

primes

Problem: run commands in pipeline

Few gaps I didn’t think straight for the first time:

  • Write process tree: pass array as input[1]

    1
    2
    // pass ints to pipe
    write(fd, &int, sizeof int);
  • Pipe usage: the meaning of “create one process that reads from its left neighbor over a pipe and writes to its right neighbor over another pipe” is as follows. Thinking about a pipeline like a | b | c, the process is read from pipe(a_to_b) and write(b_to_c). Don’t forget to pipe the int array before using the pipe.

  • Understood this we could break this lab into two parts, the main part feeds numbers to a function which will produce primes from the numbers. Feeding is in the parent process and function execution is in the child process. In this way, the function can share the parent’s data memory and they can run simultaneously.

  • Fd resources: fds are limited.
    Read blocks until it is impossible for new data to arrive (book).
    Princle: close file descriptors that a process doesn’t need.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if (fork() == 0) {
    close(0);
    dup(numbers[0]);
    close(numbers[1]);
    getPrimes(numbers);
    } else {
    close(numbers[0]);
    for (int i = 2; i <= RANGE; ++i) {
    write(numbers[1], &i, sizeof(i));
    }
    close(numbers[1]);
    wait(0);
    }
  • Leaves of the process tree: hang because read blocks somehow.

find

c basics: ++, pointer

  • value of ++p is p after the increment, value of p++ is p before the increment,
  • *ptr++, *(ptr++), first dereferences the pointer, then increments the pointer
    *++ptr, first increments the pointer, then dereferences the pointer
    ++*ptr, first dereferences the pointer, then increments dereferenced value
  • i++ vs ++i
    “++i” is known as the pre-increment operator, which increments the value of ‘i’ immediately and returns the incremented value. On the other hand, “i++” is known as the post-increment operator, which increments the value of ‘i’ but returns the original value that ‘i’ held before being incremented (from codeforce answers).

xargs

c basics: string array

  • r/w in low level, read char to lines
  • int getline(char line[], int lim); int readlines(char *lineptr[], int maxlines);
    Btw, the “many $” sentence is an explanation not a bug.

Lab2 syscalls

Create a syscall in xv6: uapp.c -> user.h -> user/usys.pl usys.S -> ecall| -> syscall -> process

trace

Problem: what is trace?

Trace is a user call helping to track one particular syscall in the execution process.
Problem: what’s the relation between sys_call and sys_proc?

sysinfo

It’s easy to overlook the spelling error. One bracket makes you question about everything:)

1
2
if (copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info) < 0); // off-by-one-bracket error
if (copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info)) < 0); // correct one

Lab3 page tables

print pt

You can’t write it without knowing the page table implementation in xv6. At first, it needs a simple and straightforward solution and then optimize it. I was thinking about using iteration or recursion, which took a while.

kernel page table

  1. problem: When to start paging? -> page table set up: panic
  2. Hypothesis:
    • Traps due to missing mappings
    • scheduler
  3. Experiment:
    • modify allocproc: seems correct
    • modify scheduler: move around w_satp, errors occur -> scheduler goes wrong
  4. Problem 1: how scheduler goes wrong? -> Key point: context switching (thanks to @GuoZhi)
    • pit: Problem 2: why truncate2 OK but truncate3 not? -> We shouldn’t be worried if we can get grade part ok. And it’s time to move to real problem.
    • aside: Problem 3: lost some freepages in kernmem
  5. Observations:
    • Allocproc sets up one process’s kernel stack

copyin

Task: add user mappings to user process’s kernel page table

  1. Problem: when user mappings are changed in exec ? what should be done in exec ?
  2. Hypothesis:
  3. Experiment:
    • pit: no need to change copyin_new yet. The task is to make it work.
  4. Predictions:
  5. Observations:

Lab4

Lab5

Lab6

Lab7 thread

thread_switch

  1. thread_switch needs to save/restore only the callee-save registers. Caller-saved registers are saved on
    the stack (if needed) by the calling C code while caller-save registers lost value after a function call.
  2. Pointers are an addresses.

uthread

barrier

Lab8 lock

Lab9 fs

Lab10 mmap

Lab11

Tool

C

  1. volatile means variables can be changed from outside the program which compiler is not aware of.
  2. function pointer: void (*func)())

Qemu 5.1[2], Mac m1, Riscv-toolchain 10.1

6.s081 20fall labs


  1. stuck for a long time due to not very familiar with C in 21/03/20 ↩︎

  2. build from source. Configure prefix to /opt/qemu. More can be found here. ↩︎