Michael Mächtel 8 роки тому
джерело
коміт
dda9ea1a73

+ 27
- 0
hw7/README.md Переглянути файл

@@ -0,0 +1,27 @@
1
+# hw7
2
+
3
+## Tasks
4
+
5
+To fulfill **hw7** you have to solve:
6
+
7
+- task1
8
+- task2
9
+- simu1
10
+
11
+## Files
12
+
13
+You find already or reuse some files for rust tasks. Please remember to use cargo to create a new project for each task and copy the given files into their dedicated directories.
14
+
15
+## Pull-Request
16
+
17
+Please merge any accepted reviews into your branch. If you are ready with the homework, all tests run, please create a pull request named **hw7**.
18
+
19
+## Credits of hw7
20
+
21
+| Task     | max. Credits | Comment |
22
+| -------- | ------------ | ------- |
23
+| task1    | 1,5          |         |
24
+| task2    | 1            |         |
25
+| simu1    | 1,5          |         |
26
+| Deadline | +1           |         |
27
+| =        | 5            |         |

+ 87
- 0
hw7/simu1/QUESTIONS.md Переглянути файл

@@ -0,0 +1,87 @@
1
+# QUESTIONS Synchronisation: Locks
2
+
3
+This program, x86.py, allows you to see how different thread interleavings
4
+either cause or avoid race conditions. See the README for details on how the
5
+program works and its basic inputs, then answer the questions below.
6
+
7
+## Questions
8
+
9
+### `flag.s`
10
+
11
+1. First let’s get ready to run `x86.py` with the flag `-p flag.s`. This code
12
+   “implements” locking with a single memory flag.
13
+
14
+    1.1 Explain what the assembly code is trying to do?
15
+
16
+    1.2 When you run with the defaults, does `flag.s` work as expected?
17
+
18
+    1.3 Does it produce the correct result? Use the -M and -R flags to trace variables and registers (and turn on -c to see their values). Variables start at address 100.
19
+
20
+    1.4 Can you predict what value will end up in flag as the code runs?
21
+
22
+1. Change the value of the register %bx with the -a flag (e.g., -a bx=2,bx=2 if
23
+   you are running just two threads). What does the code do? How does it change
24
+   your answer for the question above?
25
+
26
+1. Set bx to a high value for each thread, and then use the -i flag to generate
27
+   different interrupt frequencies; what values lead to a bad outcomes? Which
28
+   lead to good outcomes? Why?
29
+
30
+### `test-and-set.s`
31
+
32
+Now let’s look at the program `test-and-set.s`. First, try to understand the
33
+code, which uses the `xchg` instruction to build a simple locking primitive. How
34
+is the lock acquire written? How about lock release?
35
+
36
+1. Now run the code, changing the value of the interrupt interval (-i) again,
37
+   and making sure to loop for a number of times. Does the code always work as
38
+   expected? Does it sometimes lead to an inefficient use of the CPU? How could
39
+   you quantify that?
40
+
41
+1. Use the -P flag to generate specific tests of the locking code. For example,
42
+   run a schedule that grabs the lock in the first thread, but then tries to
43
+   acquire it in the second. Does the right thing happen? What else should you
44
+   test?
45
+
46
+### `peterson.s`
47
+
48
+Now let’s look at the code in `peterson.s`, which implements Peterson’s
49
+algorithm (mentioned in a sidebar in the text). Study the code and see if you
50
+can make sense of it.
51
+
52
+1. Now run the code with different values of -i. What kinds of different
53
+   behavior do you see?
54
+
55
+1. Can you control the scheduling (with the -P flag) to “prove” that the code
56
+   works? What are the different cases you should show hold? Think about mutual
57
+   exclusion and deadlock avoidance.
58
+
59
+### `ticket.s`
60
+
61
+Now study the code for the ticket lock in `ticket.s`. Does it match the code in
62
+the chapter?
63
+
64
+1. Now run the code, with the following flags: `-abx=1000,bx=1000` (this flag
65
+   sets each thread to loop through the critical 1000 times). Watch what happens
66
+   over time; do the threads spend much time spinning waiting for the lock?
67
+
68
+1. How does the code behave as you add more threads?
69
+
70
+### `yield.s`
71
+
72
+Now examine `yield.s`, in which we pretend that a yield instruction enables one
73
+thread to yield control of the CPU to another (realistically, this would be an
74
+OS primitive, but for the simplicity of simulation, we assume there is an
75
+instruction that does the task).
76
+
77
+1. Find a scenario where `test-and-set.s` wastes cycles spinning, but `yield.s`
78
+   does not. How many instructions are saved? In what scenarios do these savings
79
+   arise?
80
+
81
+### `test-and-test-and-set`
82
+
83
+Finally, examine `test-and-test-and-set.s`.
84
+
85
+1. What does this lock do?
86
+
87
+1. What kind of savings does it introduce as compared to `test-and-set.s`?

+ 368
- 0
hw7/simu1/README-locks.md Переглянути файл

@@ -0,0 +1,368 @@
1
+# README: Synchronisation: Locks
2
+
3
+Welcome to this simulator. The idea is to gain familiarity with threads by
4
+seeing how they interleave; the simulator, x86.py, will help you in gaining this
5
+understanding.
6
+
7
+The simulator mimicks the execution of short assembly sequences by multiple
8
+threads. Note that the OS code that would run (for example, to perform a context
9
+switch) is *not* shown; thus, all you see is the interleaving of the user code.
10
+
11
+The assembly code that is run is based on x86, but somewhat simplified. In this
12
+instruction set, there are four general-purpose registers (%ax, %bx, %cx, %dx),
13
+a program counter (PC), and a small set of instructions which will be enough for
14
+our purposes. We've also added a few extra GP registers (%ex, %fx) which don't
15
+quite match anything in x86 land (but that is OK).
16
+
17
+Here is an example code snippet that we will be able to run:
18
+
19
+```assembly
20
+.main
21
+mov 2000, %ax   # get the value at the address
22
+add $1, %ax     # increment it
23
+mov %ax, 2000   # store it back
24
+halt
25
+```
26
+
27
+The code is easy to understand. The first instruction, an x86 "mov", simply
28
+loads a value from the address specified by 2000 into the register %ax.
29
+Addresses, in this subset of x86, can take some of the following forms:
30
+
31
+  2000          -> the number (2000) is the address (%cx)         -> contents of
32
+  register (in parentheses) forms the address 1000(%dx)     -> the number +
33
+  contents of the register form the address 10(%ax,%bx)   -> the number + reg1 +
34
+  reg2 forms the address 10(%ax,%bx,4) -> the number + reg1 + (reg2*scaling)
35
+  forms the address
36
+
37
+To store a value, the same "mov" instruction is used, but this time with the
38
+arguments reversed, e.g.:
39
+
40
+  mov %ax, 2000
41
+
42
+The "add" instruction, from the sequence above, should be clear: it adds an
43
+immediate value (specified by $1) to the register specified in the second
44
+argument (i.e., %ax = %ax + 1).
45
+
46
+Thus, we now can understand the code sequence above: it loads the value at
47
+address 2000, adds 1 to it, and then stores the value back into address 2000.
48
+
49
+The fake-ish "halt" instruction just stops running this thread.
50
+
51
+Let's run the simulator and see how this all works! Assume the above code
52
+sequence is in the file "simple-race.s".
53
+
54
+```text
55
+prompt> ./x86.py -p simple-race.s -t 1
56
+
57
+       Thread 0
58
+1000 mov 2000, %ax
59
+1001 add $1, %ax
60
+1002 mov %ax, 2000
61
+1003 halt
62
+
63
+prompt>
64
+```
65
+
66
+The arguments used here specify the program (-p), the number of threads (-t 1),
67
+and the interrupt interval, which is how often a scheduler will be woken and run
68
+to switch to a different task. Because there is only one thread in this example,
69
+this interval does not matter.
70
+
71
+The output is easy to read: the simulator prints the program counter (here shown
72
+from 1000 to 1003) and the instruction that gets executed. Note that we assume
73
+(unrealistically) that all instructions just take up a single byte in memory; in
74
+x86, instructions are variable-sized and would take up from one to a small
75
+number of bytes.
76
+
77
+We can use more detailed tracing to get a better sense of how machine state
78
+changes during the execution:
79
+
80
+```text
81
+prompt> ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx
82
+
83
+ 2000      ax    bx          Thread 0
84
+    ?       ?     ?
85
+    ?       ?     ?   1000 mov 2000, %ax
86
+    ?       ?     ?   1001 add $1, %ax
87
+    ?       ?     ?   1002 mov %ax, 2000
88
+    ?       ?     ?   1003 halt
89
+```
90
+
91
+Oops! Forgot the -c flag (which actually computes the answers for you).
92
+
93
+```text
94
+prompt> ./x86.py -p simple-race.s -t 1 -M 2000 -R ax,bx -c
95
+
96
+ 2000      ax    bx          Thread 0
97
+    0       0     0
98
+    0       0     0   1000 mov 2000, %ax
99
+    0       1     0   1001 add $1, %ax
100
+    1       1     0   1002 mov %ax, 2000
101
+    1       1     0   1003 halt
102
+```
103
+
104
+By using the -M flag, we can trace memory locations (a comma-separated list lets
105
+you trace more than one, e.g., 2000,3000); by using the -R flag we can track the
106
+values inside specific registers.
107
+
108
+The values on the left show the memory/register contents AFTER the instruction
109
+on the right has executed. For example, after the "add" instruction, you can see
110
+that %ax has been incremented to the value 1; after the second "mov" instruction
111
+(at PC=1002), you can see that the memory contents at 2000 are now also
112
+incremented.
113
+
114
+There are a few more instructions you'll need to know, so let's get to them now.
115
+Here is a code snippet of a loop:
116
+
117
+```assembly
118
+.main
119
+.top
120
+sub  $1,%dx
121
+test $0,%dx
122
+jgte .top
123
+halt
124
+```
125
+
126
+A few things have been introduced here. First is the "test" instruction. This
127
+instruction takes two arguments and compares them; it then sets implicit
128
+"condition codes" (kind of like 1-bit registers) which subsequent instructions
129
+can act upon.
130
+
131
+In this case, the other new instruction is the "jump" instruction (in this case,
132
+"jgte" which stands for "jump if greater than or equal to"). This instruction
133
+jumps if the second value is greater than or equal to the first in the test.
134
+
135
+One last point: to really make this code work, dx must be initialized to 1 or
136
+greater.
137
+
138
+Thus, we run the program like this:
139
+
140
+```text
141
+prompt> ./x86.py -p loop.s -t 1 -a dx=3 -R dx -C -c
142
+
143
+   dx   >= >  <= <  != ==        Thread 0
144
+    3   0  0  0  0  0  0
145
+    2   0  0  0  0  0  0  1000 sub  $1,%dx
146
+    2   1  1  0  0  1  0  1001 test $0,%dx
147
+    2   1  1  0  0  1  0  1002 jgte .top
148
+    1   1  1  0  0  1  0  1000 sub  $1,%dx
149
+    1   1  1  0  0  1  0  1001 test $0,%dx
150
+    1   1  1  0  0  1  0  1002 jgte .top
151
+    0   1  1  0  0  1  0  1000 sub  $1,%dx
152
+    0   1  0  1  0  0  1  1001 test $0,%dx
153
+    0   1  0  1  0  0  1  1002 jgte .top
154
+    0   1  0  1  0  0  1  1003 halt
155
+```
156
+
157
+The "-R dx" flag traces the value of %dx; the "-C" flag traces the values of the
158
+condition codes that get set by a test instruction. Finally, the "-a dx=3" flag
159
+sets the %dx register to the value 3 to start with.
160
+
161
+As you can see from the trace, the "sub" instruction slowly lowers the value of
162
+%dx. The first few times "test" is called, only the ">=", ">", and "!="
163
+conditions get set. However, the last "test" in the trace finds %dx and 0 to be
164
+equal, and thus the subsequent jump does NOT take place, and the program finally
165
+halts.
166
+
167
+Now, finally, we get to a more interesting case, i.e., a race condition with
168
+multiple threads. Let's look at the code first:
169
+
170
+```assembly
171
+.main
172
+.top
173
+# critical section
174
+mov 2000, %ax       # get the value at the address
175
+add $1, %ax         # increment it
176
+mov %ax, 2000       # store it back
177
+
178
+# see if we're still looping
179
+sub  $1, %bx
180
+test $0, %bx
181
+jgt .top
182
+
183
+halt
184
+```
185
+
186
+The code has a critical section which loads the value of a variable (at address
187
+2000), then adds 1 to the value, then stores it back.
188
+
189
+The code after just decrements a loop counter (in %bx), tests if it is greater
190
+than or equal to zero, and if so, jumps back to the top to the critical section
191
+again.
192
+
193
+```text
194
+prompt> ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -c
195
+
196
+ 2000      bx          Thread 0                Thread 1
197
+    0       1
198
+    0       1   1000 mov 2000, %ax
199
+    0       1   1001 add $1, %ax
200
+    1       1   1002 mov %ax, 2000
201
+    1       0   1003 sub  $1, %bx
202
+    1       0   1004 test $0, %bx
203
+    1       0   1005 jgt .top
204
+    1       0   1006 halt
205
+    1       1   ----- Halt;Switch -----  ----- Halt;Switch -----
206
+    1       1                            1000 mov 2000, %ax
207
+    1       1                            1001 add $1, %ax
208
+    2       1                            1002 mov %ax, 2000
209
+    2       0                            1003 sub  $1, %bx
210
+    2       0                            1004 test $0, %bx
211
+    2       0                            1005 jgt .top
212
+    2       0                            1006 halt
213
+```
214
+
215
+Here you can see each thread ran once, and each updated the shared variable at
216
+address 2000 once, thus resulting in a count of two there.
217
+
218
+The "Halt;Switch" line is inserted whenever a thread halts and another thread
219
+must be run.
220
+
221
+One last example: run the same thing above, but with a smaller interrupt
222
+frequency. Here is what that will look like:
223
+
224
+```text
225
+[mac Race-Analyze] ./x86.py -p looping-race-nolock.s -t 2 -a bx=1 -M 2000 -i 2
226
+
227
+ 2000          Thread 0                Thread 1
228
+    ?
229
+    ?   1000 mov 2000, %ax
230
+    ?   1001 add $1, %ax
231
+    ?   ------ Interrupt ------  ------ Interrupt ------
232
+    ?                            1000 mov 2000, %ax
233
+    ?                            1001 add $1, %ax
234
+    ?   ------ Interrupt ------  ------ Interrupt ------
235
+    ?   1002 mov %ax, 2000
236
+    ?   1003 sub  $1, %bx
237
+    ?   ------ Interrupt ------  ------ Interrupt ------
238
+    ?                            1002 mov %ax, 2000
239
+    ?                            1003 sub  $1, %bx
240
+    ?   ------ Interrupt ------  ------ Interrupt ------
241
+    ?   1004 test $0, %bx
242
+    ?   1005 jgt .top
243
+    ?   ------ Interrupt ------  ------ Interrupt ------
244
+    ?                            1004 test $0, %bx
245
+    ?                            1005 jgt .top
246
+    ?   ------ Interrupt ------  ------ Interrupt ------
247
+    ?   1006 halt
248
+    ?   ----- Halt;Switch -----  ----- Halt;Switch -----
249
+    ?                            1006 halt
250
+```
251
+
252
+As you can see, each thread is interrupt every 2 instructions, as we specify via
253
+the "-i 2" flag. What is the value of memory[2000] throughout this run? What
254
+should it have been?
255
+
256
+Now let's give a little more information on what can be simulated with this
257
+program. The full set of registers: %ax, %bx, %cx, %dx, and the PC. In this
258
+version, there is no support for a "stack", nor are there call and return
259
+instructions.
260
+
261
+The full set of instructions simulated are:
262
+
263
+```assembly
264
+mov immediate, register     # moves immediate value to register
265
+mov memory, register        # loads from memory into register
266
+mov register, register      # moves value from one register to other
267
+mov register, memory        # stores register contents in memory
268
+mov immediate, memory       # stores immediate value in memory
269
+
270
+add immediate, register     # register  = register  + immediate
271
+add register1, register2    # register2 = register2 + register1
272
+sub immediate, register     # register  = register  - immediate
273
+sub register1, register2    # register2 = register2 - register1
274
+
275
+neg register                # negates contents of register
276
+
277
+test immediate, register    # compare immediate and register (set condition codes)
278
+test register, immediate    # same but register and immediate
279
+test register, register     # same but register and register
280
+
281
+jne                         # jump if test'd values are not equal
282
+je                          #                       ... equal
283
+jlt                         #     ... second is less than first
284
+jlte                        #               ... less than or equal
285
+jgt                         #            ... is greater than
286
+jgte                        #               ... greater than or equal
287
+
288
+push memory or register     # push value in memory or from reg onto stack
289
+                            # stack is defined by sp register
290
+pop [register]              # pop value off stack (into optional register)
291
+call label                  # call function at label
292
+
293
+xchg register, memory       # atomic exchange:
294
+                            #   put value of register into memory
295
+                            #   return old contents of memory into reg
296
+                            # do both things atomically
297
+
298
+yield                       # switch to the next thread in the runqueue
299
+
300
+nop                         # no op
301
+```
302
+
303
+Notes:
304
+
305
+- 'immediate' is something of the form $number
306
+- 'memory' is of the form 'number' or '(reg)' or 'number(reg)' or
307
+   'number(reg,reg)' or 'number(reg,reg,scale)' (as described above)
308
+- 'register' is one of %ax, %bx, %cx, %dx
309
+
310
+Finally, here are the full set of options to the simulator are available with
311
+the -h flag:
312
+
313
+```text
314
+Usage: x86.py [options]
315
+
316
+Options:
317
+  -s SEED, --seed=SEED  the random seed
318
+  -t NUMTHREADS, --threads=NUMTHREADS
319
+                        number of threads
320
+  -p PROGFILE, --program=PROGFILE
321
+                        source program (in .s)
322
+  -i INTFREQ, --interrupt=INTFREQ
323
+                        interrupt frequency
324
+  -P PROCSCHED, --procsched=PROCSCHED
325
+                        control exactly which thread runs when
326
+  -r, --randints        if interrupts are random
327
+  -a ARGV, --argv=ARGV  comma-separated per-thread args (e.g., ax=1,ax=2 sets
328
+                        thread 0 ax reg to 1 and thread 1 ax reg to 2);
329
+                        specify multiple regs per thread via colon-separated
330
+                        list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and
331
+                        just cx for thread 1)
332
+  -L LOADADDR, --loadaddr=LOADADDR
333
+                        address where to load code
334
+  -m MEMSIZE, --memsize=MEMSIZE
335
+                        size of address space (KB)
336
+  -M MEMTRACE, --memtrace=MEMTRACE
337
+                        comma-separated list of addrs to trace (e.g.,
338
+                        20000,20001)
339
+  -R REGTRACE, --regtrace=REGTRACE
340
+                        comma-separated list of regs to trace (e.g.,
341
+                        ax,bx,cx,dx)
342
+  -C, --cctrace         should we trace condition codes
343
+  -S, --printstats      print some extra stats
344
+  -v, --verbose         print some extra info
345
+  -H HEADERCOUNT, --headercount=HEADERCOUNT
346
+                        how often to print a row header
347
+  -c, --compute         compute answers for me
348
+```
349
+
350
+Most are obvious. Usage of -r turns on a random interrupter (from 1 to intfreq
351
+as specified by -i), which can make for more fun during homework problems.
352
+
353
+-P lets you specify exactly which threads run when; e.g., 11000 would run thread
354
+   1 for 2 instructions, then thread 0 for 3, then repeat
355
+
356
+-L specifies where in the address space to load the code.
357
+
358
+-m specified the size of the address space (in KB).
359
+
360
+-S prints some extra stats
361
+
362
+-c lets you see the values of the traced registers or memory values (otherwise
363
+   they show up as question marks)
364
+
365
+-H lets you specify how often to print a row header (useful for long traces)
366
+
367
+Now you have the basics in place; read the questions at the end of the chapter
368
+to study this race condition and related issues in more depth.

+ 27
- 0
hw7/simu1/flag.s Переглянути файл

@@ -0,0 +1,27 @@
1
+.var flag
2
+.var count
3
+
4
+.main
5
+.top
6
+
7
+.acquire
8
+mov  flag, %ax      # get flag
9
+test $0, %ax        # if we get 0 back: lock is free!
10
+jne  .acquire       # if not, try again
11
+mov  $1, flag       # store 1 into flag
12
+
13
+# critical section
14
+mov  count, %ax     # get the value at the address
15
+add  $1, %ax        # increment it
16
+mov  %ax, count     # store it back
17
+
18
+# release lock
19
+mov  $0, flag       # clear the flag now
20
+
21
+# see if we're still looping
22
+sub  $1, %bx
23
+test $0, %bx
24
+jgt .top	
25
+
26
+halt
27
+

+ 6
- 0
hw7/simu1/loop.s Переглянути файл

@@ -0,0 +1,6 @@
1
+.main
2
+.top
3
+sub  $1,%dx
4
+test $0,%dx     
5
+jgte .top         
6
+halt

+ 15
- 0
hw7/simu1/looping-race-nolock.s Переглянути файл

@@ -0,0 +1,15 @@
1
+# assumes %bx has loop count in it
2
+
3
+.main
4
+.top	
5
+# critical section
6
+mov 2000, %ax  # get the value at the address
7
+add $1, %ax    # increment it
8
+mov %ax, 2000  # store it back
9
+
10
+# see if we're still looping
11
+sub  $1, %bx
12
+test $0, %bx
13
+jgt .top	
14
+
15
+halt

+ 53
- 0
hw7/simu1/peterson.s Переглянути файл

@@ -0,0 +1,53 @@
1
+# array of 2 integers (each size 4 bytes)
2
+# load address of flag into fx register
3
+# access flag[] with 0(%fx,%index,4)
4
+# where %index is a register holding 0 or 1
5
+# index reg contains 0 -> flag[0], if 1->flag[1]
6
+.var flag   2     
7
+
8
+# global turn variable
9
+.var turn
10
+
11
+# global count
12
+.var count
13
+
14
+.main
15
+
16
+# put address of flag into fx
17
+lea flag, %fx
18
+
19
+# assume thread ID is in bx (0 or 1, scale by 4 to get proper flag address)
20
+mov %bx, %cx   # bx: self, now copies to cx
21
+neg %cx        # cx: - self
22
+add $1, %cx    # cx: 1 - self
23
+
24
+.acquire
25
+mov $1, 0(%fx,%bx,4)    # flag[self] = 1
26
+mov %cx, turn           # turn       = 1 - self
27
+
28
+.spin1
29
+mov 0(%fx,%cx,4), %ax   # flag[1-self]
30
+test $1, %ax            
31
+jne .fini               # if flag[1-self] != 1, skip past loop to .fini
32
+
33
+.spin2                  # just labeled for fun, not needed
34
+mov turn, %ax
35
+test %cx, %ax           # compare 'turn' and '1 - self'
36
+je .spin1               # if turn==1-self, go back and start spin again
37
+
38
+# fall out of spin
39
+.fini
40
+
41
+# do critical section now
42
+mov count, %ax
43
+add $1, %ax
44
+mov %ax, count
45
+
46
+.release
47
+mov $0, 0(%fx,%bx,4)    # flag[self] = 0
48
+
49
+
50
+# end case: make sure it's other's turn
51
+mov %cx, turn           # turn       = 1 - self
52
+halt
53
+

+ 6
- 0
hw7/simu1/simple-race.s Переглянути файл

@@ -0,0 +1,6 @@
1
+.main
2
+# this is a critical section
3
+mov 2000(%bx), %ax   # get the value at the address
4
+add $1, %ax          # increment it
5
+mov %ax, 2000(%bx)   # store it back
6
+halt

+ 26
- 0
hw7/simu1/test-and-set.s Переглянути файл

@@ -0,0 +1,26 @@
1
+.var mutex
2
+.var count
3
+
4
+.main
5
+.top	
6
+
7
+.acquire
8
+mov  $1, %ax        
9
+xchg %ax, mutex     # atomic swap of 1 and mutex
10
+test $0, %ax        # if we get 0 back: lock is free!
11
+jne  .acquire       # if not, try again
12
+
13
+# critical section
14
+mov  count, %ax     # get the value at the address
15
+add  $1, %ax        # increment it
16
+mov  %ax, count     # store it back
17
+
18
+# release lock
19
+mov  $0, mutex
20
+
21
+# see if we're still looping
22
+sub  $1, %bx
23
+test $0, %bx
24
+jgt .top	
25
+
26
+halt

+ 29
- 0
hw7/simu1/test-and-test-and-set.s Переглянути файл

@@ -0,0 +1,29 @@
1
+.var mutex
2
+.var count
3
+
4
+.main
5
+.top	
6
+
7
+.acquire
8
+mov  mutex, %ax
9
+test $0, %ax
10
+jne .acquire
11
+mov  $1, %ax        
12
+xchg %ax, mutex     # atomic swap of 1 and mutex
13
+test $0, %ax        # if we get 0 back: lock is free!
14
+jne .acquire        # if not, try again
15
+
16
+# critical section
17
+mov  count, %ax     # get the value at the address
18
+add  $1, %ax        # increment it
19
+mov  %ax, count     # store it back
20
+
21
+# release lock
22
+mov  $0, mutex
23
+
24
+# see if we're still looping
25
+sub  $1, %bx
26
+test $0, %bx
27
+jgt .top	
28
+
29
+halt

+ 30
- 0
hw7/simu1/ticket.s Переглянути файл

@@ -0,0 +1,30 @@
1
+.var ticket
2
+.var turn
3
+.var count
4
+
5
+.main
6
+.top	
7
+
8
+.acquire
9
+mov $1, %ax
10
+fetchadd %ax, ticket  # grab a ticket (keep it in dx)
11
+.tryagain
12
+mov turn, %cx         # check if it's your turn 
13
+test %cx, %ax
14
+jne .tryagain
15
+
16
+# critical section
17
+mov  count, %ax       # get the value at the address
18
+add  $1, %ax          # increment it
19
+mov  %ax, count       # store it back
20
+
21
+# release lock
22
+mov $1, %ax
23
+fetchadd %ax, turn
24
+
25
+# see if we're still looping
26
+sub  $1, %bx
27
+test $0, %bx
28
+jgt .top	
29
+
30
+halt

+ 1188
- 0
hw7/simu1/x86.py
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 29
- 0
hw7/simu1/yield.s Переглянути файл

@@ -0,0 +1,29 @@
1
+.var mutex
2
+.var count
3
+
4
+.main
5
+.top	
6
+
7
+.acquire
8
+mov  $1, %ax        
9
+xchg %ax, mutex     # atomic swap of 1 and mutex
10
+test $0, %ax        # if we get 0 back: lock is free!
11
+je .acquire_done    
12
+yield               # if not, yield and try again
13
+j .acquire
14
+.acquire_done
15
+
16
+# critical section
17
+mov  count, %ax     # get the value at the address
18
+add  $1, %ax        # increment it
19
+mov  %ax, count     # store it back
20
+
21
+# release lock
22
+mov  $0, mutex
23
+
24
+# see if we're still looping
25
+sub  $1, %bx
26
+test $0, %bx
27
+jgt .top	
28
+
29
+halt

Завантаження…
Відмінити
Зберегти