OSTEP Chapter 26

ECE 3600, Fall 2022


Table of Contents


1. Concurrency and Address Spaces


2. Thread Scheduling

t0.c (updated)
     1	#include <stdio.h>
     2	#include <stdlib.h>
     3	#include <pthread.h>
     4
     5	#include "common.h"
     6	#include "common_threads.h"
     7
     8	void *mythread(void *arg) {
     9	    printf("%s\n", (char *) arg);
    10	    return NULL;
    11	}
    12
    13	int main(int argc, char *argv[]) {
    14	    if (argc != 1) {
    15		fprintf(stderr, "usage: main\n");
    16		exit(1);
    17	    }
    18
    19	    pthread_t p1, p2;
    20	    printf("main: begin\n");
    21	    printf( "main: creating T1\n");
    22	    Pthread_create(&p1, NULL, mythread, "A");
    23	    printf( "main: creating T2\n");
    24	    Pthread_create(&p2, NULL, mythread, "B");
    25	    // join waits for the threads to finish
    26	    printf( "main: waiting for T1\n");
    27	    Pthread_join(p1, NULL);
    28	    printf( "main: waiting for T2\n");
    29	    Pthread_join(p2, NULL);
    30	    printf("main: end\n");
    31	    return 0;
    32	}
Figure 26.2: Simple Thread Creation Code (t0.c) (updated)
     
$ ./t0
main: begin
main: creating T1
main: creating T2
main: waiting for T1
A
B
main: waiting for T2
main: end

$ ./t0
main: begin
main: creating T1
main: creating T2
A
main: waiting for T1
main: waiting for T2
B
main: end

$ ./t0
main: begin
main: creating T1
main: creating T2
A
main: waiting for T1
B
main: waiting for T2
main: end

3. Thread Traces

           

4. Updating Shared Data

t1.c (updated)
     1	#include <stdio.h>
     2	#include <stdlib.h>
     3	#include <pthread.h>
     4
     5	#include "common.h"
     6	#include "common_threads.h"
     7
     8	int max;
     9	volatile int counter = 0; // shared global variable
    10
    11	void *mythread(void *arg) {
    12	    char *letter = arg;
    13	    int i; // stack (private per thread)
    14	    printf("%s: begin [addr of i: %p]\n", letter, &i);
    15	    for (i = 0; i < max; i++) {
    16		counter = counter + 1; // shared: only one
    17	    }
    18	    printf("%s: done\n", letter);
    19	    return NULL;
    20	}
    21
    22	int main(int argc, char *argv[]) {
    23	    if (argc != 2) {
    24		fprintf(stderr, "usage: main-first <loopcount>\n");
    25		exit(1);
    26	    }
    27	    max = atoi(argv[1]);
    28
    29	    pthread_t p1, p2;
    30	    printf("main: begin [counter = %d] [%p]\n", counter,
    31		   &counter);
    32	    Pthread_create(&p1, NULL, mythread, "A");
    33	    Pthread_create(&p2, NULL, mythread, "B");
    34	    // join waits for the threads to finish
    35	    Pthread_join(p1, NULL);
    36	    Pthread_join(p2, NULL);
    37	    printf("main: done\n [counter: %d]\n [should: %d]\n",
    38		   counter, max*2);
    39	    return 0;
    40	}
Figure 26.6: Sharing Data: Uh Oh (t1.c) (updated)
     
$ ./t1 1000
main: begin [counter = 0] [0x5595c870602c]
A: begin [addr of i: 0x7f1d4b103edc]
A: done
B: begin [addr of i: 0x7f1d4a902edc]
B: done
main: done
 [counter: 2000]
 [should: 2000]
$ ./t1 10000
main: begin [counter = 0] [0x5614fcebb02c]
A: begin [addr of i: 0x7f2d6429eedc]
B: begin [addr of i: 0x7f2d63a9dedc]
A: done
B: done
main: done
 [counter: 16198]
 [should: 20000]
$ ./t1 10000
main: begin [counter = 0] [0x55e639cc602c]
A: begin [addr of i: 0x7fe89de71edc]
B: begin [addr of i: 0x7fe89d670edc]
A: done
B: done
main: done
 [counter: 13548]
 [should: 20000]
$ ./t1 10000
main: begin [counter = 0] [0x55bc1502402c]
A: begin [addr of i: 0x7f12e8365edc]
A: done
B: begin [addr of i: 0x7f12e7b64edc]
B: done
main: done
 [counter: 20000]
 [should: 20000]
$ ./t1 100000
main: begin [counter = 0] [0x563ec42ec02c]
A: begin [addr of i: 0x7ff3d02b7edc]
B: begin [addr of i: 0x7ff3cfab6edc]
A: done
B: done
main: done
 [counter: 102446]
 [should: 200000]

5. Data Race

$ objdump -d t1 > t1.disasm.txt   #   (note on %rip addressing)
...
 a4a:	8b 05 dc 15 20 00    	mov    0x2015dc(%rip),%eax        # 20202c <counter>
 a50:	83 c0 01             	add    $0x1,%eax
 a53:	89 05 d3 15 20 00    	mov    %eax,0x2015d3(%rip)        # 20202c <counter>
...
Textbook example:
 mov 0x8049a1c, %eax
 add $0x1, %eax
 mov %eax, 0x8049a1c

Need mutual exclusion or atomic operations


6. Exercises

See the book for exercises using x86.py:

$ cat loop.s
.main
.top
sub  $1,%dx
test $0,%dx
jgte .top
halt

$ python ./x86.py -p loop.s -t 1 -i 100 -R dx

   dx          Thread 0
    ?
    ?   1000 sub  $1,%dx
    ?   1001 test $0,%dx
    ?   1002 jgte .top
    ?   1003 halt

$ python ./x86.py -p loop.s -t 1 -i 100 -R dx -c

   dx          Thread 0
    0
   -1   1000 sub  $1,%dx
   -1   1001 test $0,%dx
   -1   1002 jgte .top
   -1   1003 halt

7. Q2

$ python ./x86.py -p loop.s -t 2 -i 100 -a dx=3,dx=3 -R dx -c

   dx          Thread 0                Thread 1
    3
    2   1000 sub  $1,%dx
    2   1001 test $0,%dx
    2   1002 jgte .top
    1   1000 sub  $1,%dx
    1   1001 test $0,%dx
    1   1002 jgte .top
    0   1000 sub  $1,%dx
    0   1001 test $0,%dx
    0   1002 jgte .top
   -1   1000 sub  $1,%dx
   -1   1001 test $0,%dx
   -1   1002 jgte .top
   -1   1003 halt
    3   ----- Halt;Switch -----  ----- Halt;Switch -----
    2                            1000 sub  $1,%dx
    2                            1001 test $0,%dx
    2                            1002 jgte .top
    1                            1000 sub  $1,%dx
    1                            1001 test $0,%dx
    1                            1002 jgte .top
    0                            1000 sub  $1,%dx
    0                            1001 test $0,%dx
    0                            1002 jgte .top
   -1                            1000 sub  $1,%dx
   -1                            1001 test $0,%dx
   -1                            1002 jgte .top
   -1                            1003 halt

8. Q3

$ python ./x86.py -p loop.s -t 2 -a dx=3,dx=3 -R dx -c -i 5

   dx          Thread 0                Thread 1
    3
    2   1000 sub  $1,%dx
    2   1001 test $0,%dx
    2   1002 jgte .top
    1   1000 sub  $1,%dx
    1   1001 test $0,%dx
    3   ------ Interrupt ------  ------ Interrupt ------
    2                            1000 sub  $1,%dx
    2                            1001 test $0,%dx
    2                            1002 jgte .top
    1                            1000 sub  $1,%dx
    1                            1001 test $0,%dx
    1   ------ Interrupt ------  ------ Interrupt ------
    1   1002 jgte .top
    0   1000 sub  $1,%dx
    0   1001 test $0,%dx
    0   1002 jgte .top
   -1   1000 sub  $1,%dx
    1   ------ Interrupt ------  ------ Interrupt ------
    1                            1002 jgte .top
    0                            1000 sub  $1,%dx
    0                            1001 test $0,%dx
    0                            1002 jgte .top
   -1                            1000 sub  $1,%dx
   -1   ------ Interrupt ------  ------ Interrupt ------
   -1   1001 test $0,%dx
   -1   1002 jgte .top
   -1   1003 halt
   -1   ----- Halt;Switch -----  ----- Halt;Switch -----
   -1                            1001 test $0,%dx
   -1                            1002 jgte .top
   -1   ------ Interrupt ------  ------ Interrupt ------
   -1                            1003 halt

9. Q4

$ cat looping-race-nolock.s
# assumes %bx has loop count in it

.main
.top
# critical section
mov 2000, %ax  # get 'value' at address 2000
add $1, %ax    # increment it
mov %ax, 2000  # store it back

# see if we're still looping
sub  $1, %bx
test $0, %bx
jgt .top

halt

$ python ./x86.py -p looping-race-nolock.s -t 1 -a bx=1 -M 2000 -c

 2000          Thread 0
    0
    0   1000 mov 2000, %ax
    0   1001 add $1, %ax
    1   1002 mov %ax, 2000
    1   1003 sub  $1, %bx
    1   1004 test $0, %bx
    1   1005 jgt .top
    1   1006 halt

$ python ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -R bx -c

 2000      bx          Thread 0                Thread 1
    0       1
    0       1   1000 mov 2000, %ax
    0       1   1001 add $1, %ax
    1       1   1002 mov %ax, 2000
    1       0   1003 sub  $1, %bx
    1       0   1004 test $0, %bx
    1       0   1005 jgt .top
    1       0   1006 halt
    1       1   ----- Halt;Switch -----  ----- Halt;Switch -----
    1       1                            1000 mov 2000, %ax
    1       1                            1001 add $1, %ax
    2       1                            1002 mov %ax, 2000
    2       0                            1003 sub  $1, %bx
    2       0                            1004 test $0, %bx
    2       0                            1005 jgt .top
    2       0                            1006 halt

10. Q7

$ python ./x86.py -p looping-race-nolock.s -a bx=1 -t 2 -M 2000 -R bx -c -i 1

 2000      bx          Thread 0                Thread 1
    0       1
    0       1   1000 mov 2000, %ax
    0       1   ------ Interrupt ------  ------ Interrupt ------
    0       1                            1000 mov 2000, %ax
    0       1   ------ Interrupt ------  ------ Interrupt ------
    0       1   1001 add $1, %ax
    0       1   ------ Interrupt ------  ------ Interrupt ------
    0       1                            1001 add $1, %ax
    0       1   ------ Interrupt ------  ------ Interrupt ------
    1       1   1002 mov %ax, 2000
    1       1   ------ Interrupt ------  ------ Interrupt ------
    1       1                            1002 mov %ax, 2000
    1       1   ------ Interrupt ------  ------ Interrupt ------
    1       0   1003 sub  $1, %bx
    1       1   ------ Interrupt ------  ------ Interrupt ------
    1       0                            1003 sub  $1, %bx
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0   1004 test $0, %bx
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0                            1004 test $0, %bx
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0   1005 jgt .top
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0                            1005 jgt .top
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0   1006 halt
    1       0   ----- Halt;Switch -----  ----- Halt;Switch -----
    1       0   ------ Interrupt ------  ------ Interrupt ------
    1       0                            1006 halt