228 lines
8.0 KiB
Markdown
228 lines
8.0 KiB
Markdown
|
# 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
|
|||
|
```
|
|||
|
|
|||
|
|