* same with xv6
[mascara-docs.git] / i386 / MIT / src.xv6 / sleep1.p
blobaf697728e1663d84163e9535180ab20994b8296a
1 /*
2 This file defines a Promela model for xv6's
3 acquire, release, sleep, and wakeup, along with
4 a model of a simple producer/consumer queue.
6 To run:
7 spinp sleep1.p
9 (You may need to install Spin, available at http://spinroot.com/.)
11 After a successful run spin prints something like:
13 unreached in proctype consumer
14 (0 of 37 states)
15 unreached in proctype producer
16 (0 of 23 states)
18 After an unsuccessful run, the spinp script prints
19 an execution trace that causes a deadlock.
21 The safe body of producer reads:
23 acquire(lk);
24 x = value; value = x + 1; x = 0;
25 wakeup(0);
26 release(lk);
27 i = i + 1;
29 If this is changed to:
31 x = value; value = x + 1; x = 0;
32 acquire(lk);
33 wakeup(0);
34 release(lk);
35 i = i + 1;
37 then a deadlock can happen, because the non-atomic
38 increment of value conflicts with the non-atomic
39 decrement in consumer, causing value to have a bad value.
40 Try this.
42 If it is changed to:
44 acquire(lk);
45 x = value; value = x + 1; x = 0;
46 release(lk);
47 wakeup(0);
48 i = i + 1;
50 then nothing bad happens: it is okay to wakeup after release
51 instead of before, although it seems morally wrong.
54 #define ITER 4
55 #define N 2
57 bit lk;
58 byte value;
59 bit sleeping[N];
61 inline acquire(x)
63 atomic { x == 0; x = 1 }
66 inline release(x)
68 assert x==1;
69 x = 0
72 inline sleep(cond, lk)
74 assert !sleeping[_pid];
76 :: cond ->
77 skip
78 :: else ->
79 atomic { release(lk); sleeping[_pid] = 1 };
80 sleeping[_pid] == 0;
81 acquire(lk)
85 inline wakeup()
87 w = 0;
89 :: w < N ->
90 sleeping[w] = 0;
91 w = w + 1
92 :: else ->
93 break
97 active[N] proctype consumer()
99 byte i, x;
101 i = 0;
103 :: i < ITER ->
104 acquire(lk);
105 sleep(value > 0, lk);
106 x = value; value = x - 1; x = 0;
107 release(lk);
108 i = i + 1;
109 :: else ->
110 break
112 i = 0;
113 skip
116 active[N] proctype producer()
118 byte i, x, w;
120 i = 0;
122 :: i < ITER ->
123 acquire(lk);
124 x = value; value = x + 1; x = 0;
125 release(lk);
126 wakeup();
127 i = i + 1;
128 :: else ->
129 break
131 i = 0;
132 skip