os_kernel_lab/related_info/lab7/lab7-spoc-exercise.md
2015-04-29 12:38:37 +08:00

228 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# lab7 理解race condition
## x86模拟运行环境
x86.py是一个模拟执行基于汇编代码的多线程执行过程的模拟器。这里的汇编语法是基于很简单的x86汇编语法。
且没有包括OS的调度、context切换和中断处理过程。每条指令大小为一个byte。每个变量占4个byte
在硬件上模拟了4个通用寄存器
```
%ax, %bx, %cx, %dx
```
一个程序计数器`pc`,一个堆栈寄存器`sp`,和一小部分指令:
```
mov immediate, register # immediate value --> register
mov memory, register # memory --> register
mov register, register # register --> register
mov register, memory # register --> memory
mov immediate, memory # immediate value --> memory
add immediate, register # register = register + immediate
add register1, register2 # register2 = register2 + register1
sub immediate, register # register = register - immediate
sub register1, register2 # register2 = register2 - register1
test immediate, register # compare immediate and register (set condition codes)
test register, immediate # compare register and immediate (set condition codes)
test register, register # compare register and register (set condition codes)
jne # jump if test'd values are not equal
je # jump if test'd values are equal
jlt # jump if test'd second is less than first
jlte # jump if test'd second is less than or equal first
jgt # jump if test'd second is greater than first
jgte # jump if test'd second is greater than or equal first
xchg register, memory # atomic exchange:
# put value of register into memory
# return old contents of memory into reg
# do both things atomically
nop # no op
halt # stop
push memory or register # push value in memory or from reg onto stack
# stack is defined by sp register
pop [register] # pop value off stack (into optional register)
call label # call function at label
yield # switch to the next thread in the runqueue
```
注意:
- 'immediate' 格式是 $number
- 'memory' 格式是 'number' 或 '(reg)' 或 'number(reg)' 或 'number(reg,reg)'
- (%cx) -> 在括号中的register cx 的值 形成 address
- 2000 -> 2000 形成 address
- 1000(%dx) -> 1000 + dx的值 形成 address
- 10(%ax,%bx) -> 10 + ax的值 + bx的值 形成 address
- 'register' 格式是 %ax, %bx, %cx, %dx
下面是一个代码片段:
```
.main
mov 2000, %ax # 取地址2000处的内存单元的内容并赋值给ax
add $1, %ax # ax=ax+1
mov %ax, 2000 # 把ax的内容存储到地址2000处的内存单元中
halt
```
其含义如下
```
2000 -> 2000 形成地址 address
(%cx) -> cx的内容 形成地址 address
1000(%dx) -> 1000+dx 形成地址 address
10(%ax,%bx) -> (10+ax+bx) 形成地址 address
halt -> 执行结束
```
循环执行的小例子片段
```
.main
.top
sub $1,%dx
test $0,%dx
jgte .top
halt
```
x86.py模拟器运行参数
```
-h, --help show this help message and exit
-s SEED, --seed=SEED the random seed
-t NUMTHREADS, --threads=NUMTHREADS
number of threads
-p PROGFILE, --program=PROGFILE
source program (in .s)
-i INTFREQ, --interrupt=INTFREQ
interrupt frequency
-r, --randints if interrupts are random
-a ARGV, --argv=ARGV comma-separated per-thread args (e.g., ax=1,ax=2 sets
thread 0 ax reg to 1 and thread 1 ax reg to 2);
specify multiple regs per thread via colon-separated
list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and
just cx for thread 1)
-L LOADADDR, --loadaddr=LOADADDR
address where to load code
-m MEMSIZE, --memsize=MEMSIZE
size of address space (KB)
-M MEMTRACE, --memtrace=MEMTRACE
comma-separated list of addrs to trace (e.g.,
20000,20001)
-R REGTRACE, --regtrace=REGTRACE
comma-separated list of regs to trace (e.g.,
ax,bx,cx,dx)
-C, --cctrace should we trace condition codes
-S, --printstats print some extra stats
-v, --verbose print some extra info
-c, --compute compute answers for me
```
执行举例
```
$ ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx
2000 ax bx Thread 0
? ? ?
? ? ? 1000 mov 2000, %ax
? ? ? 1001 add $1, %ax
? ? ? 1002 mov %ax, 2000
? ? ? 1003 halt
```
如果加上参数 `-c`可得到具体执行结果
```
$ ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx -c
2000 ax bx Thread 0
0 0 0
0 0 0 1000 mov 2000, %ax
0 1 0 1001 add $1, %ax
1 1 0 1002 mov %ax, 2000
1 1 0 1003 halt
```
另外一个执行的例子
```
$ ./x86.py -p loop.s -t 1 -a dx=3 -R dx -C -c
dx >= > <= < != == Thread 0
3 0 0 0 0 0 0
2 0 0 0 0 0 0 1000 sub $1,%dx
2 1 1 0 0 1 0 1001 test $0,%dx
2 1 1 0 0 1 0 1002 jgte .top
1 1 1 0 0 1 0 1000 sub $1,%dx
1 1 1 0 0 1 0 1001 test $0,%dx
1 1 1 0 0 1 0 1002 jgte .top
0 1 1 0 0 1 0 1000 sub $1,%dx
0 1 0 1 0 0 1 1001 test $0,%dx
0 1 0 1 0 0 1 1002 jgte .top
0 1 0 1 0 0 1 1003 halt
```
多线程存在race condition 的例子 looping-race-nolock.s
```
.main
.top
# critical section
mov 2000, %ax # get the value at the address
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
```
执行结果:
```
$ ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -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
```
多线程存在 race condition 的例子 looping-race-nolock.s 在引入中断后会产生race condition.
```
$ ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -i 2
2000 Thread 0 Thread 1
?
? 1000 mov 2000, %ax
? 1001 add $1, %ax
? ------ Interrupt ------ ------ Interrupt ------
? 1000 mov 2000, %ax
? 1001 add $1, %ax
? ------ Interrupt ------ ------ Interrupt ------
? 1002 mov %ax, 2000
? 1003 sub $1, %bx
? ------ Interrupt ------ ------ Interrupt ------
? 1002 mov %ax, 2000
? 1003 sub $1, %bx
? ------ Interrupt ------ ------ Interrupt ------
? 1004 test $0, %bx
? 1005 jgt .top
? ------ Interrupt ------ ------ Interrupt ------
? 1004 test $0, %bx
? 1005 jgt .top
? ------ Interrupt ------ ------ Interrupt ------
? 1006 halt
? ----- Halt;Switch ----- ----- Halt;Switch -----
? 1006 halt
```