This is the archived Fall 2013 version of the course.
For the most recent version, see http://rust-class.org/class-22-putting-a-fork-in-fork.html.

Class 22: Putting a Fork in Fork

Action Items

Project Design and Progress reviews will start next week. The submission form for updates and scheduling is due by 11:59pm Sunday.

Segmentation Violations

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void (*signal(int signum, void (*sighandler)(int)))(int);

static int i;

void catch_segv(int sig) {
  printf("Caught segv: %d\n", sig);
  printf("i = %d\n", i);
}

int main(int argc, char **argv) {
  char *s = (char *) malloc (1);
  i = 0;

  signal(SIGSEGV, catch_segv);

  while (1) {
    s[i] = 'a';
    i++;
  }
}

When does this code produce a Segmentation Violation?

#include <stdio.h>
#include <stdlib.h>

void big_stack() {
  char BIG_DATA[8515*1024];
  int i = 3; // need this to avoid optimizations...
}

int main(int argc, char **argv) {
  big_stack();
}

Try uname -a to determine if this code will SEGV or not on your machine.

Representing Tasks

include/linux/sched.h

struct task_struct {
        volatile long state;        /* -1 unrunnable, 0 runnable, >0 stopped */
        void *stack;
        atomic_t usage;
        unsigned int flags;        /* per process flags, defined below */
        unsigned int ptrace;

        ... // 400 lines total

        int prio, static_prio, normal_prio;
        unsigned int rt_priority;
        const struct sched_class *sched_class;

    ... 

        struct mm_struct *mm, *active_mm;

    /* task state */
        int exit_state;
        int exit_code, exit_signal;
        int pdeath_signal;  /*  The signal sent when the parent dies  */
        unsigned int jobctl;        /* JOBCTL_*, siglock protected */

        /* Used for emulating ABI behavior of previous Linux versions */
        unsigned int personality;
    ...
        pid_t pid;
        pid_t tgid;

#ifdef CONFIG_CC_STACKPROTECTOR
        /* Canary value for the -fstack-protector gcc feature */
        unsigned long stack_canary;
#endif
        /*
         * pointers to (original) parent process, youngest child, younger sibling,
         * older sibling, respectively.  (p->father can be replaced with
         * p->real_parent->pid)
         */
        struct task_struct __rcu *real_parent; /* real parent process */
        struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
        /*
         * children/sibling forms the list of my natural children
         */
        struct list_head children;        /* list of my children */
        struct list_head sibling;        /* linkage in my parent's children list */
        struct task_struct *group_leader;        /* threadgroup leader */

    ...
};

Why does the kernel need to know about GCC's -fstack-protector feature?

Linux Magic!

...

#define MINIX_SUPER_MAGIC        0x137F                /* minix v1 fs, 14 char names */
#define MINIX_SUPER_MAGIC2        0x138F                /* minix v1 fs, 30 char names */
#define MINIX2_SUPER_MAGIC        0x2468                /* minix v2 fs, 14 char names */
#define MINIX2_SUPER_MAGIC2        0x2478                /* minix v2 fs, 30 char names */
#define MINIX3_SUPER_MAGIC        0x4d5a                /* minix v3 fs, 60 char names */
...
#define STACK_END_MAGIC                0x57AC6E9D
...

How should the kernel flush the TLB?

Code

static inline void __native_flush_tlb(void)
{
        native_write_cr3(native_read_cr3());
}

Is Mark's answer correct? What unstated assumptions does it rely on?

For a more truthful account of how Mark did in his Operating Systems course, see Matt Welsh's How I almost killed Facebook.