Model verifying that wakeup really
can be called after release without causing deadlock.
This commit is contained in:
		
							parent
							
								
									943fd378a1
								
							
						
					
					
						commit
						949352af66
					
				
					 2 changed files with 150 additions and 0 deletions
				
			
		
							
								
								
									
										134
									
								
								sleep1.p
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								sleep1.p
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,134 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					This file defines a Promela model for xv6's
 | 
				
			||||||
 | 
					acquire, release, sleep, and wakeup, along with
 | 
				
			||||||
 | 
					a model of a simple producer/consumer queue.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run:
 | 
				
			||||||
 | 
						spinp sleep1.p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(You may need to install Spin, available at http://spinroot.com/.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After a successful run spin prints something like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unreached in proctype consumer
 | 
				
			||||||
 | 
							(0 of 37 states)
 | 
				
			||||||
 | 
						unreached in proctype producer
 | 
				
			||||||
 | 
							(0 of 23 states)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After an unsuccessful run, the spinp script prints
 | 
				
			||||||
 | 
					an execution trace that causes a deadlock.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The safe body of producer reads:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							acquire(lk);
 | 
				
			||||||
 | 
							x = value; value = x + 1; x = 0;
 | 
				
			||||||
 | 
							wakeup(0);
 | 
				
			||||||
 | 
							release(lk);
 | 
				
			||||||
 | 
							i = i + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If this is changed to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							x = value; value = x + 1; x = 0;
 | 
				
			||||||
 | 
							acquire(lk);
 | 
				
			||||||
 | 
							wakeup(0);
 | 
				
			||||||
 | 
							release(lk);
 | 
				
			||||||
 | 
							i = i + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					then a deadlock can happen, because the non-atomic
 | 
				
			||||||
 | 
					increment of value conflicts with the non-atomic 
 | 
				
			||||||
 | 
					decrement in consumer, causing value to have a bad value.
 | 
				
			||||||
 | 
					Try this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If it is changed to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							acquire(lk);
 | 
				
			||||||
 | 
							x = value; value = x + 1; x = 0;
 | 
				
			||||||
 | 
							release(lk);
 | 
				
			||||||
 | 
							wakeup(0);
 | 
				
			||||||
 | 
							i = i + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					then nothing bad happens: it is okay to wakeup after release
 | 
				
			||||||
 | 
					instead of before, although it seems morally wrong.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ITER 4
 | 
				
			||||||
 | 
					#define N 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bit lk;
 | 
				
			||||||
 | 
					byte value;
 | 
				
			||||||
 | 
					bit sleeping[N];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline acquire(x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						atomic { x == 0; x = 1 }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline release(x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert x==1;
 | 
				
			||||||
 | 
						x = 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline sleep(cond, lk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert !sleeping[_pid];
 | 
				
			||||||
 | 
						if
 | 
				
			||||||
 | 
						:: cond ->
 | 
				
			||||||
 | 
							skip
 | 
				
			||||||
 | 
						:: else ->
 | 
				
			||||||
 | 
							atomic { release(lk); sleeping[_pid] = 1 };
 | 
				
			||||||
 | 
							sleeping[_pid] == 0;
 | 
				
			||||||
 | 
							acquire(lk)
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline wakeup()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						w = 0;
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						:: w < N ->
 | 
				
			||||||
 | 
							sleeping[w] = 0;
 | 
				
			||||||
 | 
							w = w + 1
 | 
				
			||||||
 | 
						:: else ->
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						od
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					active[N] proctype consumer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						byte i, x;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						i = 0;
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						:: i < ITER ->
 | 
				
			||||||
 | 
							acquire(lk);
 | 
				
			||||||
 | 
							sleep(value > 0, lk);
 | 
				
			||||||
 | 
							x = value; value = x - 1; x = 0;
 | 
				
			||||||
 | 
							release(lk);
 | 
				
			||||||
 | 
							i = i + 1;
 | 
				
			||||||
 | 
						:: else ->
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						od;
 | 
				
			||||||
 | 
						i = 0;
 | 
				
			||||||
 | 
						skip
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					active[N] proctype producer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						byte i, x, w;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						i = 0;
 | 
				
			||||||
 | 
						do
 | 
				
			||||||
 | 
						:: i < ITER ->
 | 
				
			||||||
 | 
							acquire(lk);
 | 
				
			||||||
 | 
							x = value; value = x + 1; x = 0;
 | 
				
			||||||
 | 
							release(lk);
 | 
				
			||||||
 | 
							wakeup();
 | 
				
			||||||
 | 
							i = i + 1;
 | 
				
			||||||
 | 
						:: else ->
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						od;
 | 
				
			||||||
 | 
						i = 0;
 | 
				
			||||||
 | 
						skip	
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										16
									
								
								spinp
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								spinp
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ $# != 1 ] || [ ! -f "$1" ]; then
 | 
				
			||||||
 | 
						echo 'usage: spinp file.p' 1>&2
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rm -f $1.trail
 | 
				
			||||||
 | 
					spin -a $1 || exit 1
 | 
				
			||||||
 | 
					cc -DSAFETY -DREACH -DMEMLIM=500 -o pan pan.c
 | 
				
			||||||
 | 
					pan -i
 | 
				
			||||||
 | 
					rm pan.* pan
 | 
				
			||||||
 | 
					if [ -f $1.trail ]; then
 | 
				
			||||||
 | 
						spin -t -p $1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue