1/* 2This file defines a Promela model for xv6's 3acquire, release, sleep, and wakeup, along with 4a model of a simple producer/consumer queue. 5 6To run: 7 spinp sleep1.p 8 9(You may need to install Spin, available at http://spinroot.com/.) 10 11After a successful run spin prints something like: 12 13 unreached in proctype consumer 14 (0 of 37 states) 15 unreached in proctype producer 16 (0 of 23 states) 17 18After an unsuccessful run, the spinp script prints 19an execution trace that causes a deadlock. 20 21The safe body of producer reads: 22 23 acquire(lk); 24 x = value; value = x + 1; x = 0; 25 wakeup(0); 26 release(lk); 27 i = i + 1; 28 29If this is changed to: 30 31 x = value; value = x + 1; x = 0; 32 acquire(lk); 33 wakeup(0); 34 release(lk); 35 i = i + 1; 36 37then a deadlock can happen, because the non-atomic 38increment of value conflicts with the non-atomic 39decrement in consumer, causing value to have a bad value. 40Try this. 41 42If it is changed to: 43 44 acquire(lk); 45 x = value; value = x + 1; x = 0; 46 release(lk); 47 wakeup(0); 48 i = i + 1; 49 50then nothing bad happens: it is okay to wakeup after release 51instead of before, although it seems morally wrong. 52*/ 53 54#define ITER 4 55#define N 2 56 57bit lk; 58byte value; 59bit sleeping[N]; 60 61inline acquire(x) 62{ 63 atomic { x == 0; x = 1 } 64} 65 66inline release(x) 67{ 68 assert x==1; 69 x = 0 70} 71 72inline sleep(cond, lk) 73{ 74 assert !sleeping[_pid]; 75 if 76 :: cond -> 77 skip 78 :: else -> 79 atomic { release(lk); sleeping[_pid] = 1 }; 80 sleeping[_pid] == 0; 81 acquire(lk) 82 fi 83} 84 85inline wakeup() 86{ 87 w = 0; 88 do 89 :: w < N -> 90 sleeping[w] = 0; 91 w = w + 1 92 :: else -> 93 break 94 od 95} 96 97active[N] proctype consumer() 98{ 99 byte i, x; 100 101 i = 0; 102 do 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 111 od; 112 i = 0; 113 skip 114} 115 116active[N] proctype producer() 117{ 118 byte i, x, w; 119 120 i = 0; 121 do 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 130 od; 131 i = 0; 132 skip 133} 134 135