Lecture 6: Testing and concurrency

Assertions and observability

Random testing

Property testing

Some buddy allocation properties

Invariant-based testing

Some buddy allocation invariants

Debugging

Never forget

Analogy

Everything Everywhere All At Once

How does it feel to program concurrent code?

Sausage fingers

Starting point: The first law of synchronization

If two or more threads concurrently access a non-atomic object in memory, then all such accesses must be reads. Otherwise, the program invokes undefined behavior.

Gaining assurance

Synchronization and kernel tasks (struct proc)

Synchronization and new kernel tasks

Mutual exclusion

How long should you hold a lock?

Example: Allocating a PID

static pid_t find_unused_pid() {
    spinlock_guard guard(ptable_lock);
    for (pid_t p = 1; p < NPROC; ++p) {
        if (!ptable[p])
            return p;
    }
    return -1;
}

pid_t proc::syscall_fork(regstate* regs) {
    pid_t new_pid = find_unused_pid();
    if (new_pid < 0) {
        return -1;
    }

    ...

    spinlock_guard guard(ptable_lock);
    ptable[new_pid] = child;
    return new_pid;
}

Synchronization and CPUs (struct cpustate)

Kernel task suspension

Suspension and register state

Representing suspension