Class 7: Double Faults

Posted: Thu 06 February 2014

Problem Set 2 is due Sunday, 9 February. You should sign-up for a team demo using this form.

Remember to check the course calendar for office hours updates. Several additional times have been scheduled to provide help on PS2 including 2-3pm and 7-8:30pm Thursday; 10-11am, 1:30-2:30pm, and 5-6:30pm Friday; and 4-5pm and 6-7pm Sunday. (Check the calendar for the locations and any changes.)

Recommended Reading

Chapters 12 through 23 of the OSTEP book provide a lot more information on virtual memory. You are not expected to know details covered there that we didn't also cover in class, but should find these chapters interesting and useful to read.


Page Fault Challenge

Michael Recachinas solved the Page Fault Challenge!

His code and results are here:

Page Tables

How well does the 386 architecture work for larger memories?

Why not just make the page size bigger to support more memory?

What are the advantages of flexible page sizes over fixed page sizes?

ARMv8 White Paper ARMv8 Architecture

Qualcomm and Samsung Pass AMD in MPU Ranking, IC Insights, 20 May 2013.


What is the difference between a segmentation fault and page fault?

What does it mean if a C++ program execution generates a segmentation fault?

What does it mean if a Rust program execution generates a segmentation fault?

How often should page faults happen in a Rust program?

What does this program do? [Code]

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

int main(int argc, char **argv) {
  char *s = (char *) malloc (1);
  int i = 0;
  while (1) {
    printf("%d: %lx / %d\n", i, s + i, i[s]);
    i += 1;

Processes, Threads, and Tasks

What is difference between a process and thread?

Is a Rust task more like a process or a thread?

How can Rust tasks provide process-like memory isolation but without the expense of a traditional process?

Spawning Tasks

The spawn function takes in an owned function (which cannot capture any mutable, shared objects) and runs that function in a new thread:

    fn spawn(f: proc())

Channels provide a way for spawned tasked to communicate back to their parent:

   let (port, chan) : (Port<int>, Chan<int>) = Chan::new();
   let val = node.head;
   do spawn {
   let newval = port.recv();

The port.recv() call with block until a sent value (from chan.send(f.val)) arrives.

Faster Collatz Steps

Here's the code for my klunky multi-tasking Collatz program: [Code] (I believe, but not with a lot of confidence, that it is correct, but it sometimes leads Rust to segv)

fn collatz_steps(n: int) -> int {
    if n == 1 {
    } else {
        1 + collatz_steps(if n % 2 == 0 { n / 2 } else { 3*n + 1 })

fn find_collatz(k: int) -> int {
    // Returns the minimum value, n, with Collatz stopping time >= k.
    let mut n = 1;
    let max_tasks = 7; // keep all my cores busy

    let mut found_result = false;
    let mut result = -1; // need to initialize

    while !found_result {
        let mut ports = ~[];

        for i in range(0, max_tasks) {
            let val = n + i;
            let (port, chan) : (Port<int>, Chan<int>) = Chan::new();

            spawn(proc() { 
               let steps = collatz_steps(val);
               println!("Result for {}: {}", val, steps);

        for i in range(0, max_tasks) {
            let port = ports.pop();
            let steps = port.recv();
            if steps > k {
                found_result = true;
                result = n + i;
        n += max_tasks;

    assert!(result != -1);

fn main() {
    println!("Result: {}", find_collatz(500));

Challenge: Write a substantially better find_collatz program that makes good use of all available cores, and always produces the correct result. (In class, I said it had to run 6 times faster than the single-threaded version on an 8-core machine, but if it is close to getting a good speedup and using an effective strategy to keep all the cores busy doing useful work nearly all the time that is good enough.)

comments powered by Disqus