Journal/Paper.thy
changeset 12 85116bc854c0
parent 11 8e02fb168350
child 13 735e36c64a71
equal deleted inserted replaced
11:8e02fb168350 12:85116bc854c0
   165   \noindent
   165   \noindent
   166   {\bf Contributions:} There have been earlier formal investigations
   166   {\bf Contributions:} There have been earlier formal investigations
   167   into PIP \cite{Faria08,Jahier09,Wellings07}, but they employ model
   167   into PIP \cite{Faria08,Jahier09,Wellings07}, but they employ model
   168   checking techniques. This paper presents a formalised and
   168   checking techniques. This paper presents a formalised and
   169   mechanically checked proof for the correctness of PIP. For this we 
   169   mechanically checked proof for the correctness of PIP. For this we 
   170   needed to design a new correctness criterion. In contrast to model checking, our
   170   needed to design a new correctness criterion for PIP. In contrast to model checking, our
   171   formalisation provides insight into why PIP is correct and allows us
   171   formalisation provides insight into why PIP is correct and allows us
   172   to prove stronger properties that, as we will show, can help with an
   172   to prove stronger properties that, as we will show, can help with an
   173   efficient implementation of PIP in the educational PINTOS operating
   173   efficient implementation of PIP in the educational PINTOS operating
   174   system \cite{PINTOS}.  For example, we found by ``playing'' with the
   174   system \cite{PINTOS}.  For example, we found by ``playing'' with the
   175   formalisation that the choice of the next thread to take over a lock
   175   formalisation that the choice of the next thread to take over a lock
   329   \begin{isabelle}\ \ \ \ \ %%%
   329   \begin{isabelle}\ \ \ \ \ %%%
   330   @{thm cs_depend_def}
   330   @{thm cs_depend_def}
   331   \end{isabelle}
   331   \end{isabelle}
   332 
   332 
   333   \noindent
   333   \noindent
   334   Given four threads and three resources, an instance of a RAG can be pictured 
   334   If there is no cycle, then every RAG can be pictured as a forrest of trees, for example as follows:
   335   as follows:
   335 
   336 
   336   \begin{figure}[h]
   337   \begin{center}
   337   \begin{center}
   338   \newcommand{\fnt}{\fontsize{7}{8}\selectfont}
   338   \newcommand{\fnt}{\fontsize{7}{8}\selectfont}
   339   \begin{tikzpicture}[scale=1]
   339   \begin{tikzpicture}[scale=1]
   340   %%\draw[step=2mm] (-3,2) grid (1,-1);
   340   %%\draw[step=2mm] (-3,2) grid (1,-1);
   341 
   341 
   345   \node (D) at (4,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>2"}};
   345   \node (D) at (4,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>2"}};
   346   \node (E) at (6,-0.7) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>2"}};
   346   \node (E) at (6,-0.7) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>2"}};
   347   \node (E1) at (6, 0.2) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>3"}};
   347   \node (E1) at (6, 0.2) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>3"}};
   348   \node (F) at (8,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>3"}};
   348   \node (F) at (8,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>3"}};
   349 
   349 
       
   350   \node (X) at (0,-2) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>4"}};
       
   351   \node (Y) at (2,-2) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>4"}};
       
   352   \node (Z) at (2,-2.9) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>5"}};
       
   353   \node (U1) at (4,-2) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>5"}};
       
   354   \node (U2) at (4,-2.9) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>6"}};
       
   355    \node (R) at (6,-2.9) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>6"}};
       
   356 
   350   \draw [<-,line width=0.6mm] (A) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (B);
   357   \draw [<-,line width=0.6mm] (A) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (B);
   351   \draw [->,line width=0.6mm] (C) to node [pos=0.4,sloped,above=-0.5mm] {\fnt{}waiting}  (B);
   358   \draw [->,line width=0.6mm] (C) to node [pos=0.4,sloped,above=-0.5mm] {\fnt{}waiting}  (B);
   352   \draw [->,line width=0.6mm] (D) to node [pos=0.4,sloped,below=-0.5mm] {\fnt{}waiting}  (B);
   359   \draw [->,line width=0.6mm] (D) to node [pos=0.4,sloped,below=-0.5mm] {\fnt{}waiting}  (B);
   353   \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,below=-0.5mm] {\fnt{}holding}  (E);
   360   \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,below=-0.5mm] {\fnt{}holding}  (E);
   354   \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (E1);
   361   \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (E1);
   355   \draw [->,line width=0.6mm] (F) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting}  (E);
   362   \draw [->,line width=0.6mm] (F) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting}  (E);
       
   363 
       
   364   \draw [->,line width=0.6mm] (U1) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting}  (Y);
       
   365   \draw [->,line width=0.6mm] (U2) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting}  (Z);
       
   366   \draw [<-,line width=0.6mm] (X) to node [pos=0.54,sloped,below=-0.5mm] {\fnt{}holding}  (Z);
       
   367   \draw [<-,line width=0.6mm] (X) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (Y);
       
   368   \draw [<-,line width=0.6mm] (U2) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding}  (R);
   356   \end{tikzpicture}
   369   \end{tikzpicture}
   357   \end{center}
   370   \end{center}
       
   371   \caption{An Instance of a Resource Allocation Graph (RAG).\label{RAGgraph}}
       
   372   \end{figure}
   358 
   373 
   359   \noindent
   374   \noindent
   360   We will design our scheduler  
   375   We will design our scheduler  
   361   so that every thread can be in the possession of several resources, that is 
   376   so that every thread can be in the possession of several resources, that is 
   362   it has potentially several incoming holding edges in the RAG, but has at most only one outgoing  
   377   it has potentially several incoming holding edges in the RAG, but has at most one outgoing  
   363   waiting edge. The reason is that when a thread asks for resource that is locked
   378   waiting edge. The reason is that when a thread asks for resource that is locked
   364   already, then the process is stopped and cannot ask for another resource.
   379   already, then the process is stopped and cannot ask for another resource.
   365   Clearly, also every resource can only have at most one outgoing holding edge---indicating
   380   Clearly, also every resource can only have at most one outgoing holding edge---indicating
   366   that the resource is locked.
   381   that the resource is locked.
   367 
   382 
   530   \end{isabelle}
   545   \end{isabelle}
   531 
   546 
   532   \noindent
   547   \noindent
   533   With these abbreviations in place we can introduce 
   548   With these abbreviations in place we can introduce 
   534   the notion of a thread being @{term ready} in a state (i.e.~threads
   549   the notion of a thread being @{term ready} in a state (i.e.~threads
   535   that do not wait for any resource) and the running thread.
   550   that do not wait for any resource, i.e.~the roots of the trees in the RAG, see 
       
   551   Figure~\ref{RAGgraph}) and the running thread.
   536 
   552 
   537   \begin{isabelle}\ \ \ \ \ %%%
   553   \begin{isabelle}\ \ \ \ \ %%%
   538   \begin{tabular}{@ {}l}
   554   \begin{tabular}{@ {}l}
   539   @{thm readys_def}\\
   555   @{thm readys_def}\\
   540   @{thm runing_def}
   556   @{thm runing_def}
   757   Inversion. For this we further have to assume that every thread
   773   Inversion. For this we further have to assume that every thread
   758   gives up its resources after a finite amount of time. We found that
   774   gives up its resources after a finite amount of time. We found that
   759   this assumption is awkward to formalise in our model. Therefore we
   775   this assumption is awkward to formalise in our model. Therefore we
   760   leave it out and let the programmer assume the responsibility to
   776   leave it out and let the programmer assume the responsibility to
   761   program threads in such a benign manner (in addition to causing no 
   777   program threads in such a benign manner (in addition to causing no 
   762   circularity in the @{text RAG}). In this detail, we do not
   778   circularity in the RAG). In this detail, we do not
   763   make any progress in comparison with the work by Sha et al.
   779   make any progress in comparison with the work by Sha et al.
   764   However, we are able to combine their two separate bounds into a
   780   However, we are able to combine their two separate bounds into a
   765   single theorem improving their bound.
   781   single theorem improving their bound.
   766 
   782 
   767   In what follows we will describe properties of PIP that allow us to prove 
   783   In what follows we will describe properties of PIP that allow us to prove 
  1240 (*>*)
  1256 (*>*)
  1241 text {*
  1257 text {*
  1242   \noindent
  1258   \noindent
  1243   As can be seen, a pleasing byproduct of our formalisation is that the properties in
  1259   As can be seen, a pleasing byproduct of our formalisation is that the properties in
  1244   this section closely inform an implementation of PIP, namely whether the
  1260   this section closely inform an implementation of PIP, namely whether the
  1245   @{text RAG} needs to be reconfigured or current precedences need to
  1261   RAG needs to be reconfigured or current precedences need to
  1246   be recalculated for an event. This information is provided by the lemmas we proved.
  1262   be recalculated for an event. This information is provided by the lemmas we proved.
  1247   We confirmed that our observations translate into practice by implementing
  1263   We confirmed that our observations translate into practice by implementing
  1248   our version of PIP on top of PINTOS, a small operating system written in C and used for teaching at 
  1264   our version of PIP on top of PINTOS, a small operating system written in C and used for teaching at 
  1249   Stanford University \cite{PINTOS}. To implement PIP, we only need to modify the kernel 
  1265   Stanford University \cite{PINTOS}. To implement PIP, we only need to modify the kernel 
  1250   functions corresponding to the events in our formal model. The events translate to the following 
  1266   functions corresponding to the events in our formal model. The events translate to the following 
  1271   highest precedence is realised in our implementation by priority queues. We implemented
  1287   highest precedence is realised in our implementation by priority queues. We implemented
  1272   them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations
  1288   them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations
  1273   for accessing and updating. Apart from having to implement relatively complex data\-structures in C
  1289   for accessing and updating. Apart from having to implement relatively complex data\-structures in C
  1274   using pointers, our experience with the implementation has been very positive: our specification 
  1290   using pointers, our experience with the implementation has been very positive: our specification 
  1275   and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. 
  1291   and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. 
  1276   Let us illustrate this with the C-implementation of the function {\tt lock\_aquire}, 
  1292   Let us illustrate this with the C-code of the function {\tt lock\_aquire}, 
  1277   shown in Figure~\ref{code}.  This function implements the operation that
  1293   shown in Figure~\ref{code}.  This function implements the operation that
  1278   the currently running thread asks for the lock of a specific resource. 
  1294   the currently running thread asks for the lock of a resource. 
  1279   In C such a lock is represented as a pointer to the structure {\tt lock} (Line 1). 
  1295   In C such a lock is represented as a pointer to the structure {\tt lock} (Line 1). 
  1280 
  1296 
  1281   Lines 2 to 4 of {\tt lock\_aquire} contain diagnostic code: first we check that 
  1297   Lines 2 to 4 of {\tt lock\_aquire} contain diagnostic code: first, we check that 
  1282   the lock is a ``valid'' lock 
  1298   the lock is a ``valid'' lock 
  1283   by testing it is not {\tt NULL}; second we check that the code is not called
  1299   by testing it is not {\tt NULL}; second, we check that the code is not called
  1284   as part of an interrupt---aquiring a lock should have been only initiated by a 
  1300   as part of an interrupt---aquiring a lock should only be initiated by a 
  1285   request from a (user) thread, not an interrupt; third we make sure the 
  1301   request from a (user) thread, not an interrupt; third, we make sure the 
  1286   current thread does not ask twice for a lock. These assertions are supposed
  1302   current thread does not ask twice for a lock. These assertions are supposed
  1287   to be satisfied because of the assumptions in PINTOS about how this code is called.
  1303   to be satisfied because of the assumptions in PINTOS about how this code is called.
  1288   If not, then the assertions indicate a bug in PINTOS.
  1304   If not, then the assertions indicate a bug in PINTOS.
  1289 
  1305 
  1290 
  1306 
  1297   ASSERT (!lock_held_by_current_thread (lock));
  1313   ASSERT (!lock_held_by_current_thread (lock));
  1298 
  1314 
  1299   enum intr_level old_level;
  1315   enum intr_level old_level;
  1300   old_level = intr_disable();
  1316   old_level = intr_disable();
  1301   if (lock->value == 0) {
  1317   if (lock->value == 0) {
  1302     heap_insert(thread_preced, &lock->wq, &thread_current()->helem); 
  1318     heap_insert(thread_cprec, &lock->wq, &thread_current()->helem); 
  1303     thread_current()->waiting = lock;
  1319     thread_current()->waiting = lock;
  1304     struct thread *pt;
  1320     struct thread *pt;
  1305     pt = lock->holder;
  1321     pt = lock->holder;
  1306     while (pt) {
  1322     while (pt) {
  1307       heap_update(lock_preced, &pt->held, &lock->helem);
  1323       heap_update(lock_cprec, &pt->held, &lock->helem);
  1308       if (!(update_cpreced(pt)))
  1324       if (!(update_cprec(pt)))
  1309         break;
  1325         break;
  1310       lock = pt->waiting;
  1326       lock = pt->waiting;
  1311       if (!lock) {
  1327       if (!lock) {
  1312         heap_update(higher_cpreced, &ready_heap, &pt->helem);
  1328         heap_update(higher_cprec, &ready_heap, &pt->helem);
  1313         break;
  1329         break;
  1314       };
  1330       };
  1315       heap_update(thread_preced, &lock->wq, &pt->helem);
  1331       heap_update(thread_cprec, &lock->wq, &pt->helem);
  1316       pt = lock->holder;
  1332       pt = lock->holder;
  1317     };
  1333     };
  1318     thread_block();
  1334     thread_block();
  1319   } else {
  1335   } else {
  1320     lock->value--;
  1336     lock->value--;
  1322     heap_insert(lock_prec, &thread_current()->held, &lock->helem); 
  1338     heap_insert(lock_prec, &thread_current()->held, &lock->helem); 
  1323   };
  1339   };
  1324   intr_set_level(old_level);
  1340   intr_set_level(old_level);
  1325 }
  1341 }
  1326   \end{lstlisting}
  1342   \end{lstlisting}
  1327   \caption{Our version of the {\tt lock\_release} function (implementing event @{text P}) in 
  1343   \caption{Our version of the {\tt lock\_release} function in 
  1328   PINTOS.\label{code}}
  1344   PINTOS.  It implements the operation corresponding to a @{text P}-event.\label{code}}
  1329   \end{figure}
  1345   \end{figure}
  1330 
  1346 
  1331  
  1347  
  1332   Line 6 and 7 of {\tt lock\_aquire} make the operation of aquiring a lock atomic by disabling all 
  1348   Line 6 and 7 of {\tt lock\_aquire} make the operation of aquiring a lock atomic by disabling all 
  1333   interrupts, but saving them for resumption at the end of the function (Line 31).
  1349   interrupts, but saving them for resumption at the end of the function (Line 31).
  1334   In Line 8, the interesting code of the scheduler starts: we 
  1350   In Line 8, the interesting code starts: we 
  1335   test whether the lock is already taken (its value is then 0 indicating ``already 
  1351   test whether the lock is already taken (its value is then 0 indicating ``already 
  1336   taken'', and 1 for being ``free''). In case the lock is taken, we need to
  1352   taken'', or 1 for being ``free''). In case the lock is taken, we enter the
  1337   insert the current thread into the waiting queue of this lock (Line 9,
  1353   if-branch by first inserting the current thread into the waiting queue of this lock (Line 9,
  1338   the waiting queue is referenced as @{ML_text "&lock-wq"}). 
  1354   the waiting queue is referenced as @{ML_text "&lock-wq"}). 
  1339   Next we record that the current thread is waiting for the lock (Line 10).
  1355   Next we record that the current thread is waiting for the lock (Line 10).
  1340   According to our specification, we need to ``chase'' the holders of locks
  1356   According to our specification, we need to next ``chase'' the dependants 
  1341   in the RAG (Resource Allocation Graph). For this we assign in Lines 11 and 12 
  1357   in the RAG (Resource Allocation Graph), but we can stop whenever there
  1342   assign the variable @{ML_text pt} ot the owner of the lock, and enter
  1358   is no change in the @{text cprec}. Befre we start the loop, we 
  1343   the while-loop in Lines 13 to 24. This loop implements the ``chase''.  
  1359   assign in Lines 11 and 12 assign the variable @{ML_text pt} to the owner 
       
  1360   of the lock, and enter the while-loop in Lines 13 to 24. \ldots
  1344 
  1361 
  1345 *}
  1362 *}
  1346 
  1363 
  1347 section {* Conclusion *}
  1364 section {* Conclusion *}
  1348 
  1365