52 thread with priority $M$, and so $H$ sits there potentially waiting |
52 thread with priority $M$, and so $H$ sits there potentially waiting |
53 indefinitely. Since $H$ is blocked by threads with lower |
53 indefinitely. Since $H$ is blocked by threads with lower |
54 priorities, the problem is called Priority Inversion. It was first |
54 priorities, the problem is called Priority Inversion. It was first |
55 described in \cite{Lampson80} in the context of the |
55 described in \cite{Lampson80} in the context of the |
56 Mesa programming language designed for concurrent programming. |
56 Mesa programming language designed for concurrent programming. |
57 |
57 |
58 If the problem of Priority Inversion is ignored, real-time systems |
58 If the problem of Priority Inversion is ignored, real-time systems |
59 can become unpredictable and resulting bugs can be hard to diagnose. |
59 can become unpredictable and resulting bugs can be hard to diagnose. |
60 The classic example where this happened is the software that |
60 The classic example where this happened is the software that |
61 controlled the Mars Pathfinder mission in 1997 \cite{Reeves98}. |
61 controlled the Mars Pathfinder mission in 1997 \cite{Reeves98}. |
62 Once the spacecraft landed, the software shut down at irregular |
62 Once the spacecraft landed, the software shut down at irregular |
79 wait indefinitely, because $L$ cannot be blocked by threads having |
79 wait indefinitely, because $L$ cannot be blocked by threads having |
80 priority $M$. While a few other solutions exist for the Priority |
80 priority $M$. While a few other solutions exist for the Priority |
81 Inversion problem, PIP is one that is widely deployed and |
81 Inversion problem, PIP is one that is widely deployed and |
82 implemented. This includes VxWorks (a proprietary real-time OS used |
82 implemented. This includes VxWorks (a proprietary real-time OS used |
83 in the Mars Pathfinder mission, in Boeing's 787 Dreamliner, Honda's |
83 in the Mars Pathfinder mission, in Boeing's 787 Dreamliner, Honda's |
84 ASIMO robot, etc.), but also the POSIX 1003.1c Standard realised for |
84 ASIMO robot, etc.) and ThreadX (another proprietary real-time OS |
|
85 used in HP inkjet printers \cite{ThreadX}), but also |
|
86 the POSIX 1003.1c Standard realised for |
85 example in libraries for FreeBSD, Solaris and Linux. |
87 example in libraries for FreeBSD, Solaris and Linux. |
86 |
88 |
87 Two advantages of PIP are that increasing the priority of a thread |
89 Two advantages of PIP are that it is deterministic and that increasing the priority of a thread |
88 can be performed dynamically by the scheduler and is deterministic. |
90 can be performed dynamically by the scheduler. |
89 This is in contrast to \emph{Priority Ceiling} |
91 This is in contrast to \emph{Priority Ceiling} |
90 \cite{Sha90}, another solution to the Priority Inversion problem, |
92 \cite{Sha90}, another solution to the Priority Inversion problem, |
91 which requires static analysis of the program in order to prevent |
93 which requires static analysis of the program in order to prevent |
92 Priority Inversion, and also to the Windows NT scheduler, which avoids |
94 Priority Inversion, and also in contrast to the Windows NT scheduler, which avoids |
93 this problem by randomly boosting the priority of ready (low priority) threads |
95 this problem by randomly boosting the priority of ready low-priority threads |
94 (e.g.~\cite{WINDOWSNT}). |
96 (see for instance~\cite{WINDOWSNT}). |
95 However, there has also been strong criticism against |
97 However, there has also been strong criticism against |
96 PIP. For instance, PIP cannot prevent deadlocks when lock |
98 PIP. For instance, PIP cannot prevent deadlocks when lock |
97 dependencies are circular, and also blocking times can be |
99 dependencies are circular, and also blocking times can be |
98 substantial (more than just the duration of a critical section). |
100 substantial (more than just the duration of a critical section). |
99 Though, most criticism against PIP centres around unreliable |
101 Though, most criticism against PIP centres around unreliable |
145 locks \emph{two} resources, and two high-priority threads $H$ and |
147 locks \emph{two} resources, and two high-priority threads $H$ and |
146 $H'$ each wait for one of them. If $L$ releases one resource |
148 $H'$ each wait for one of them. If $L$ releases one resource |
147 so that $H$, say, can proceed, then we still have Priority Inversion |
149 so that $H$, say, can proceed, then we still have Priority Inversion |
148 with $H'$ (which waits for the other resource). The correct |
150 with $H'$ (which waits for the other resource). The correct |
149 behaviour for $L$ is to switch to the highest remaining priority of |
151 behaviour for $L$ is to switch to the highest remaining priority of |
150 the threads that it blocks. The advantage of formalising the |
152 the threads that it blocks. While |
|
153 \cite{Sha90} is the only formal publication we have |
|
154 found that describes the incorrect behaviour, not all, but many |
|
155 informal\footnote{informal as in ``found on the Web''} |
|
156 descriptions of PIP overlook the possibility that another |
|
157 high-priority might wait for a low-priority process to finish. |
|
158 The advantage of formalising the |
151 correctness of a high-level specification of PIP in a theorem prover |
159 correctness of a high-level specification of PIP in a theorem prover |
152 is that such issues clearly show up and cannot be overlooked as in |
160 is that such issues clearly show up and cannot be overlooked as in |
153 informal reasoning (since we have to analyse all possible behaviours |
161 informal reasoning (since we have to analyse all possible behaviours |
154 of threads, i.e.~\emph{traces}, that could possibly happen).\footnote{While |
162 of threads, i.e.~\emph{traces}, that could possibly happen).\medskip\smallskip |
155 \cite{Sha90} is the only formal publication we have |
|
156 found that describes the incorrect behaviour, not all, but many |
|
157 informal descriptions of PIP overlook the case...}\medskip |
|
158 |
163 |
159 \noindent |
164 \noindent |
160 {\bf Contributions:} There have been earlier formal investigations |
165 {\bf Contributions:} There have been earlier formal investigations |
161 into PIP \cite{Faria08,Jahier09,Wellings07}, but they employ model |
166 into PIP \cite{Faria08,Jahier09,Wellings07}, but they employ model |
162 checking techniques. This paper presents a formalised and |
167 checking techniques. This paper presents a formalised and |
366 \end{center} |
369 \end{center} |
367 \caption{An instance of a Resource Allocation Graph (RAG).\label{RAGgraph}} |
370 \caption{An instance of a Resource Allocation Graph (RAG).\label{RAGgraph}} |
368 \end{figure} |
371 \end{figure} |
369 |
372 |
370 \noindent |
373 \noindent |
|
374 If there is no cycle, then every RAG can be pictured as a forrest of trees, as |
|
375 for example in Figure~\ref{RAGgraph}. |
|
376 |
371 We will design our scheduler |
377 We will design our scheduler |
372 so that every thread can be in the possession of several resources, that is |
378 so that every thread can be in the possession of several resources, that is |
373 it has potentially several incoming holding edges in the RAG, but has at most one outgoing |
379 it has potentially several incoming holding edges in the RAG, but has at most one outgoing |
374 waiting edge. The reason is that when a thread asks for resource that is locked |
380 waiting edge. The reason is that when a thread asks for resource that is locked |
375 already, then the process is blocked and cannot ask for another resource. |
381 already, then the process is blocked and cannot ask for another resource. |
1006 section {* Properties for an Implementation\label{implement} *} |
1012 section {* Properties for an Implementation\label{implement} *} |
1007 |
1013 |
1008 text {* |
1014 text {* |
1009 While our formalised proof gives us confidence about the correctness of our model of PIP, |
1015 While our formalised proof gives us confidence about the correctness of our model of PIP, |
1010 we found that the formalisation can even help us with efficiently implementing it. |
1016 we found that the formalisation can even help us with efficiently implementing it. |
1011 |
|
1012 For example Baker complained that calculating the current precedence |
1017 For example Baker complained that calculating the current precedence |
1013 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
1018 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
1014 In our model of PIP the current precedence of a thread in a state @{text s} |
1019 In our model of PIP the current precedence of a thread in a state @{text s} |
1015 depends on all its dependants---a ``global'' transitive notion, |
1020 depends on all its dependants---a ``global'' transitive notion, |
1016 which is indeed heavy weight (see Def.~shown in \eqref{cpreced}). |
1021 which is indeed heavy weight (see Def.~shown in \eqref{cpreced}). |
1248 |
1253 |
1249 \noindent |
1254 \noindent |
1250 This lemma states that if an intermediate @{term cp}-value does not change, then |
1255 This lemma states that if an intermediate @{term cp}-value does not change, then |
1251 the procedure can also stop, because none of its dependent threads will |
1256 the procedure can also stop, because none of its dependent threads will |
1252 have their current precedence changed. |
1257 have their current precedence changed. |
1253 *} |
1258 *}(*<*)end(*>*)text {* |
1254 (*<*) |
|
1255 end |
|
1256 (*>*) |
|
1257 text {* |
|
1258 \noindent |
|
1259 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 |
1260 this section closely inform an implementation of PIP, namely whether the |
1260 this section closely inform an implementation of PIP, namely whether the |
1261 RAG needs to be reconfigured or current precedences need to |
1261 RAG needs to be reconfigured or current precedences need to |
1262 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. |
1263 We confirmed that our observations translate into practice by implementing |
1263 We confirmed that our observations translate into practice by implementing |
1286 an unlocked resource is given next to the waiting thread with the |
1286 an unlocked resource is given next to the waiting thread with the |
1287 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 |
1288 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 |
1289 for accessing and updating. In the code we shall describe below, we use the function |
1289 for accessing and updating. In the code we shall describe below, we use the function |
1290 @{ML_text "queue_insert"}, for inserting a new element into a priority queue, and |
1290 @{ML_text "queue_insert"}, for inserting a new element into a priority queue, and |
1291 @{ML_text "queue_update"}, for updating the position of an element that is already |
1291 the function @{ML_text "queue_update"}, for updating the position of an element that is already |
1292 in a queue. Both functions take an extra argument that specifies the |
1292 in a queue. Both functions take an extra argument that specifies the |
1293 comparison function used for organising the priority queue. |
1293 comparison function used for organising the priority queue. |
1294 |
1294 |
1295 Apart from having to implement relatively complex data\-structures in C |
1295 Apart from having to implement relatively complex data\-structures in C |
1296 using pointers, our experience with the implementation has been very positive: our specification |
1296 using pointers, our experience with the implementation has been very positive: our specification |
1457 verification of this algorithm, involving more fine-grained events, |
1457 verification of this algorithm, involving more fine-grained events, |
1458 is a magnitude harder than the one we presented here, but still |
1458 is a magnitude harder than the one we presented here, but still |
1459 within reach of current theorem proving technology. We leave this |
1459 within reach of current theorem proving technology. We leave this |
1460 for future work. |
1460 for future work. |
1461 |
1461 |
|
1462 To us, it seems sound reasoning about scheduling algorithms is fiendishly difficult |
|
1463 if done informally by ``pencil-and-paper''. This is proved by the flawed proof |
|
1464 in the paper by Sha et al.~\cite{Sha90} and also by Regehr \cite{Regehr} who |
|
1465 pointed out an error in a paper about Preemption |
|
1466 Threshold Scheduling \cite{ThreadX}. The use of a theorem prover was |
|
1467 invaluable to us in order to feel confident about the correctness of our results. |
1462 The most closely related work to ours is the formal verification in |
1468 The most closely related work to ours is the formal verification in |
1463 PVS of the Priority Ceiling Protocol done by Dutertre |
1469 PVS of the Priority Ceiling Protocol done by Dutertre |
1464 \cite{dutertre99b}---another solution to the Priority Inversion |
1470 \cite{dutertre99b}---another solution to the Priority Inversion |
1465 problem, which however needs static analysis of programs in order to |
1471 problem, which however needs static analysis of programs in order to |
1466 avoid it. There have been earlier formal investigations |
1472 avoid it. There have been earlier formal investigations |
1476 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
1482 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
1477 code with a few apply-scripts interspersed. The formal model of PIP |
1483 code with a few apply-scripts interspersed. The formal model of PIP |
1478 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
1484 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
1479 definitions and proofs span over 770 lines of code. The properties relevant |
1485 definitions and proofs span over 770 lines of code. The properties relevant |
1480 for an implementation require 2000 lines. |
1486 for an implementation require 2000 lines. |
1481 %The code of our formalisation |
1487 The code of our formalisation |
1482 %can be downloaded from |
1488 can be downloaded from the Mercurial repository at |
1483 %\url{http://www.inf.kcl.ac.uk/staff/urbanc/pip.html}. |
1489 \url{http://www.inf.kcl.ac.uk/staff/urbanc/pip.html}. |
1484 |
1490 |
1485 %\medskip |
1491 %\medskip |
1486 |
1492 |
1487 %\noindent |
1493 %\noindent |
1488 %{\bf Acknowledgements:} |
1494 %{\bf Acknowledgements:} |