51 preempted. Priorities allow scheduling of threads that need to |
51 preempted. Priorities allow scheduling of threads that need to |
52 finish their work within deadlines. Unfortunately, both features |
52 finish their work within deadlines. Unfortunately, both features |
53 can interact in subtle ways leading to a problem, called |
53 can interact in subtle ways leading to a problem, called |
54 \emph{Priority Inversion}. Suppose three threads having priorities |
54 \emph{Priority Inversion}. Suppose three threads having priorities |
55 $H$(igh), $M$(edium) and $L$(ow). We would expect that the thread |
55 $H$(igh), $M$(edium) and $L$(ow). We would expect that the thread |
56 $H$ blocks any other thread with lower priority and itself cannot |
56 $H$ blocks any other thread with lower priority and the thread itself cannot |
57 be blocked by any thread with lower priority. Alas, in a naive |
57 be blocked indefinitely by any thread with lower priority. Alas, in a naive |
58 implementation of resource locking and priorities this property can |
58 implementation of resource locking and priorities this property can |
59 be violated. Even worse, $H$ can be delayed indefinitely by |
59 be violated. Even worse, $H$ can be delayed indefinitely by |
60 threads with lower priorities. For this let $L$ be in the |
60 threads with lower priorities. For this let $L$ be in the |
61 possession of a lock for a resource that $H$ also needs. $H$ must |
61 possession of a lock for a resource that $H$ also needs. $H$ must |
62 therefore wait for $L$ to exit the critical section and release this |
62 therefore wait for $L$ to exit the critical section and release this |
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 (to our |
169 mechanically checked proof for the correctness of PIP (to our |
170 knowledge the first one). |
170 knowledge the first one). |
171 %; the earlier informal proof by Sha et |
|
172 %al.~\cite{Sha90} is flawed). |
|
173 In contrast to model checking, our |
171 In contrast to model checking, our |
174 formalisation provides insight into why PIP is correct and allows us |
172 formalisation provides insight into why PIP is correct and allows us |
175 to prove stronger properties that, as we will show, can inform an |
173 to prove stronger properties that, as we will show, can inform an |
176 efficient implementation. For example, we found by ``playing'' with the formalisation |
174 efficient implementation. For example, we found by ``playing'' with the formalisation |
177 that the choice of the next thread to take over a lock when a |
175 that the choice of the next thread to take over a lock when a |
178 resource is released is irrelevant for PIP being correct---a fact |
176 resource is released is irrelevant for PIP being correct---a fact |
179 that has not been mentioned in the literature. |
177 that has not been mentioned in the literature. This is important |
|
178 for an efficient implementation, because we can give the lock to the |
|
179 thread with the highest priority so that it terminates more quickly. |
180 *} |
180 *} |
181 |
181 |
182 section {* Formal Model of the Priority Inheritance Protocol *} |
182 section {* Formal Model of the Priority Inheritance Protocol *} |
183 |
183 |
184 text {* |
184 text {* |
185 The Priority Inheritance Protocol, short PIP, is a scheduling |
185 The Priority Inheritance Protocol, short PIP, is a scheduling |
186 algorithm for a single-processor system.\footnote{We shall come back |
186 algorithm for a single-processor system.\footnote{We shall come back |
187 later to the case of PIP on multi-processor systems.} Our model of |
187 later to the case of PIP on multi-processor systems.} |
188 PIP is based on Paulson's inductive approach to protocol |
188 Following good experience in earlier work \cite{Wang09}, |
189 verification \cite{Paulson98}, where the \emph{state} of a system is |
189 our model of PIP is based on Paulson's inductive approach to protocol |
190 given by a list of events that happened so far. \emph{Events} of PIP fall |
190 verification \cite{Paulson98}. In this approach a \emph{state} of a system is |
|
191 given by a list of events that happened so far (with new events prepended to the list). |
|
192 \emph{Events} of PIP fall |
191 into five categories defined as the datatype: |
193 into five categories defined as the datatype: |
192 |
194 |
193 \begin{isabelle}\ \ \ \ \ %%% |
195 \begin{isabelle}\ \ \ \ \ %%% |
194 \mbox{\begin{tabular}{r@ {\hspace{2mm}}c@ {\hspace{2mm}}l@ {\hspace{7mm}}l} |
196 \mbox{\begin{tabular}{r@ {\hspace{2mm}}c@ {\hspace{2mm}}l@ {\hspace{7mm}}l} |
195 \isacommand{datatype} event |
197 \isacommand{datatype} event |
367 but also @{text "th\<^isub>3"}, |
369 but also @{text "th\<^isub>3"}, |
368 which cannot make any progress unless @{text "th\<^isub>2"} makes progress, which |
370 which cannot make any progress unless @{text "th\<^isub>2"} makes progress, which |
369 in turn needs to wait for @{text "th\<^isub>0"} to finish). If there is a circle of dependencies |
371 in turn needs to wait for @{text "th\<^isub>0"} to finish). If there is a circle of dependencies |
370 in a RAG, then clearly |
372 in a RAG, then clearly |
371 we have a deadlock. Therefore when a thread requests a resource, |
373 we have a deadlock. Therefore when a thread requests a resource, |
372 we must ensure that the resulting RAG is not circular. |
374 we must ensure that the resulting RAG is not circular. In practice, the |
|
375 programmer has to ensure this. |
|
376 |
|
377 |
|
378 {\bf define detached} |
|
379 |
373 |
380 |
374 Next we introduce the notion of the \emph{current precedence} of a thread @{text th} in a |
381 Next we introduce the notion of the \emph{current precedence} of a thread @{text th} in a |
375 state @{text s}. It is defined as |
382 state @{text s}. It is defined as |
376 |
383 |
377 \begin{isabelle}\ \ \ \ \ %%% |
384 \begin{isabelle}\ \ \ \ \ %%% |
378 @{thm cpreced_def2}\hfill\numbered{cpreced} |
385 @{thm cpreced_def2}\hfill\numbered{cpreced} |
379 \end{isabelle} |
386 \end{isabelle} |
380 |
387 |
381 \noindent |
388 \noindent |
382 where the dependants of @{text th} are given by the waiting queue function. |
389 where the dependants of @{text th} are given by the waiting queue function. |
383 While the precedence @{term prec} of a thread is determined by the programmer |
390 While the precedence @{term prec} of a thread is determined statically |
384 (for example when the thread is |
391 (for example when the thread is |
385 created), the point of the current precedence is to let the scheduler increase this |
392 created), the point of the current precedence is to let the scheduler increase this |
386 precedence, if needed according to PIP. Therefore the current precedence of @{text th} is |
393 precedence, if needed according to PIP. Therefore the current precedence of @{text th} is |
387 given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all |
394 given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all |
388 threads that are dependants of @{text th}. Since the notion @{term "dependants"} is |
395 threads that are dependants of @{text th}. Since the notion @{term "dependants"} is |
565 \end{center} |
572 \end{center} |
566 |
573 |
567 \noindent |
574 \noindent |
568 If a thread wants to lock a resource, then the thread needs to be |
575 If a thread wants to lock a resource, then the thread needs to be |
569 running and also we have to make sure that the resource lock does |
576 running and also we have to make sure that the resource lock does |
570 not lead to a cycle in the RAG. In practice, ensuring the latter is |
577 not lead to a cycle in the RAG. In practice, ensuring the latter |
571 the responsibility of the programmer. In our formal |
578 is the responsibility of the programmer. In our formal |
572 model we brush aside these problematic cases in order to be able to make |
579 model we brush aside these problematic cases in order to be able to make |
573 some meaningful statements about PIP.\footnote{This situation is |
580 some meaningful statements about PIP.\footnote{This situation is |
574 similar to the infamous \emph{occurs check} in Prolog: In order to say |
581 similar to the infamous \emph{occurs check} in Prolog: In order to say |
575 anything meaningful about unification, one needs to perform an occurs |
582 anything meaningful about unification, one needs to perform an occurs |
576 check. But in practice the occurs check is omitted and the |
583 check. But in practice the occurs check is omitted and the |
577 responsibility for avoiding problems rests with the programmer.} |
584 responsibility for avoiding problems rests with the programmer.} |
|
585 |
578 |
586 |
579 \begin{center} |
587 \begin{center} |
580 @{thm[mode=Rule] thread_P[where thread=th]} |
588 @{thm[mode=Rule] thread_P[where thread=th]} |
581 \end{center} |
589 \end{center} |
582 |
590 |
636 only one lock, can cause indefinite Priority Inversion for one of the |
644 only one lock, can cause indefinite Priority Inversion for one of the |
637 high-priority threads, invalidating their two bounds. |
645 high-priority threads, invalidating their two bounds. |
638 |
646 |
639 Even when fixed, their proof idea does not seem to go through for |
647 Even when fixed, their proof idea does not seem to go through for |
640 us, because of the way we have set up our formal model of PIP. One |
648 us, because of the way we have set up our formal model of PIP. One |
641 reason is that we allow critical sections to intersect |
649 reason is that we allow critical sections, which start with a @{text P}-event |
|
650 and finish with a corresponding @{text V}-event, to arbitrarily overlap |
642 (something Sha et al.~explicitly exclude). Therefore we have |
651 (something Sha et al.~explicitly exclude). Therefore we have |
643 designed a different correctness criterion for PIP. The idea behind |
652 designed a different correctness criterion for PIP. The idea behind |
644 our criterion is as follows: for all states @{text s}, we know the |
653 our criterion is as follows: for all states @{text s}, we know the |
645 corresponding thread @{text th} with the highest precedence; we show |
654 corresponding thread @{text th} with the highest precedence; we show |
646 that in every future state (denoted by @{text "s' @ s"}) in which |
655 that in every future state (denoted by @{text "s' @ s"}) in which |
656 s"}, the thread @{text th} and the events happening in @{text |
665 s"}, the thread @{text th} and the events happening in @{text |
657 s'}. We list them next: |
666 s'}. We list them next: |
658 |
667 |
659 \begin{quote} |
668 \begin{quote} |
660 {\bf Assumptions on the states {\boldmath@{text s}} and |
669 {\bf Assumptions on the states {\boldmath@{text s}} and |
661 {\boldmath@{text "s' @ s"}:}} In order to make |
670 {\boldmath@{text "s' @ s"}:}} We need to require that @{text "s"} and |
662 any meaningful statement, we need to require that @{text "s"} and |
671 @{text "s' @ s"} are valid states: |
663 @{text "s' @ s"} are valid states, namely |
|
664 \begin{isabelle}\ \ \ \ \ %%% |
672 \begin{isabelle}\ \ \ \ \ %%% |
665 \begin{tabular}{l} |
673 \begin{tabular}{l} |
666 @{term "vt s"}\\ |
674 @{term "vt s"}\\ |
667 @{term "vt (s' @ s)"} |
675 @{term "vt (s' @ s)"} |
668 \end{tabular} |
676 \end{tabular} |
958 (*>*) |
966 (*>*) |
959 |
967 |
960 section {* Properties for an Implementation\label{implement} *} |
968 section {* Properties for an Implementation\label{implement} *} |
961 |
969 |
962 text {* |
970 text {* |
963 While a formal correctness proof for our model of PIP is certainly |
971 While our formalised proof gives us confidence about the correctness of our model of PIP, |
964 attractive (especially in light of the flawed proof by Sha et |
972 we found that the formalisation can even help us with efficiently implementing it. |
965 al.~\cite{Sha90}), we found that the formalisation can even help us |
|
966 with efficiently implementing PIP. |
|
967 |
973 |
968 For example Baker complained that calculating the current precedence |
974 For example Baker complained that calculating the current precedence |
969 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
975 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
970 In our model of PIP the current precedence of a thread in a state @{text s} |
976 In our model of PIP the current precedence of a thread in a state @{text s} |
971 depends on all its dependants---a ``global'' transitive notion, |
977 depends on all its dependants---a ``global'' transitive notion, |
1066 @{term "s \<equiv> Set th prio#s'"} are both valid. We can show that |
1072 @{term "s \<equiv> Set th prio#s'"} are both valid. We can show that |
1067 |
1073 |
1068 \begin{isabelle}\ \ \ \ \ %%% |
1074 \begin{isabelle}\ \ \ \ \ %%% |
1069 \begin{tabular}{@ {}l} |
1075 \begin{tabular}{@ {}l} |
1070 @{thm[mode=IfThen] eq_dep}, and\\ |
1076 @{thm[mode=IfThen] eq_dep}, and\\ |
1071 @{thm[mode=IfThen] eq_cp} |
1077 @{thm[mode=IfThen] eq_cp_pre} |
1072 \end{tabular} |
1078 \end{tabular} |
1073 \end{isabelle} |
1079 \end{isabelle} |
1074 |
1080 |
1075 \noindent |
1081 \noindent |
1076 The first property is again telling us we do not need to change the @{text RAG}. The second |
1082 The first property is again telling us we do not need to change the @{text RAG}. |
1077 however states that only threads that are \emph{not} dependants of @{text th} have their |
1083 The second shows that the @{term cp}-values of all threads other than @{text th} |
1078 current precedence unchanged. For the others we have to recalculate the current |
1084 are unchanged. The reason is that @{text th} is running; therefore it is not in |
1079 precedence. To do this we can start from @{term "th"} |
1085 the @{term dependants} relation of any thread. This in turn means that the |
1080 and follow the @{term "depend"}-edges to recompute using Lemma~\ref{childrenlem} |
1086 change of its priority cannot affect the threads. |
1081 the @{term "cp"} of every |
1087 |
1082 thread encountered on the way. Since the @{term "depend"} |
1088 %The second |
1083 is assumed to be loop free, this procedure will always stop. The following two lemmas show, however, |
1089 %however states that only threads that are \emph{not} dependants of @{text th} have their |
1084 that this procedure can actually stop often earlier without having to consider all |
1090 %current precedence unchanged. For the others we have to recalculate the current |
1085 dependants. |
1091 %precedence. To do this we can start from @{term "th"} |
1086 |
1092 %and follow the @{term "depend"}-edges to recompute using Lemma~\ref{childrenlem} |
1087 \begin{isabelle}\ \ \ \ \ %%% |
1093 %the @{term "cp"} of every |
1088 \begin{tabular}{@ {}l} |
1094 %thread encountered on the way. Since the @{term "depend"} |
1089 @{thm[mode=IfThen] eq_up_self}\\ |
1095 %is assumed to be loop free, this procedure will always stop. The following two lemmas show, however, |
1090 @{text "If"} @{thm (prem 1) eq_up}, @{thm (prem 2) eq_up} and @{thm (prem 3) eq_up}\\ |
1096 %that this procedure can actually stop often earlier without having to consider all |
1091 @{text "then"} @{thm (concl) eq_up}. |
1097 %dependants. |
1092 \end{tabular} |
1098 % |
1093 \end{isabelle} |
1099 %\begin{isabelle}\ \ \ \ \ %%% |
1094 |
1100 %\begin{tabular}{@ {}l} |
1095 \noindent |
1101 %@{thm[mode=IfThen] eq_up_self}\\ |
1096 The first lemma states that if the current precedence of @{text th} is unchanged, |
1102 %@{text "If"} @{thm (prem 1) eq_up}, @{thm (prem 2) eq_up} and @{thm (prem 3) eq_up}\\ |
1097 then the procedure can stop immediately (all dependent threads have their @{term cp}-value unchanged). |
1103 %@{text "then"} @{thm (concl) eq_up}. |
1098 The second states that if an intermediate @{term cp}-value does not change, then |
1104 %\end{tabular} |
1099 the procedure can also stop, because none of its dependent threads will |
1105 %\end{isabelle} |
1100 have their current precedence changed. |
1106 % |
|
1107 %\noindent |
|
1108 %The first lemma states that if the current precedence of @{text th} is unchanged, |
|
1109 %then the procedure can stop immediately (all dependent threads have their @{term cp}-value unchanged). |
|
1110 %The second states that if an intermediate @{term cp}-value does not change, then |
|
1111 %the procedure can also stop, because none of its dependent threads will |
|
1112 %have their current precedence changed. |
1101 \smallskip |
1113 \smallskip |
1102 *} |
1114 *} |
1103 (*<*) |
1115 (*<*) |
1104 end |
1116 end |
1105 context step_v_cps_nt |
1117 context step_v_cps_nt |
1151 (*>*) |
1163 (*>*) |
1152 text {* |
1164 text {* |
1153 \noindent |
1165 \noindent |
1154 \colorbox{mygrey}{@{term "P th cs"}:} We assume that @{text s'} and |
1166 \colorbox{mygrey}{@{term "P th cs"}:} We assume that @{text s'} and |
1155 @{term "s \<equiv> P th cs#s'"} are both valid. We again have to analyse two subcases, namely |
1167 @{term "s \<equiv> P th cs#s'"} are both valid. We again have to analyse two subcases, namely |
1156 the one where @{text cs} is locked, and where it is not. We treat the second case |
1168 the one where @{text cs} is not locked, and one where it is. We treat the former case |
1157 first by showing that |
1169 first by showing that |
1158 |
1170 |
1159 \begin{isabelle}\ \ \ \ \ %%% |
1171 \begin{isabelle}\ \ \ \ \ %%% |
1160 \begin{tabular}{@ {}l} |
1172 \begin{tabular}{@ {}l} |
1161 @{thm depend_s}\\ |
1173 @{thm depend_s}\\ |
1208 make the notions in the correctness proof by Sha et al.~\cite{Sha90} |
1220 make the notions in the correctness proof by Sha et al.~\cite{Sha90} |
1209 precise so that they can be processed by a theorem prover. The reason is |
1221 precise so that they can be processed by a theorem prover. The reason is |
1210 that a mechanically checked proof avoids the flaws that crept into their |
1222 that a mechanically checked proof avoids the flaws that crept into their |
1211 informal reasoning. We achieved this goal: The correctness of PIP now |
1223 informal reasoning. We achieved this goal: The correctness of PIP now |
1212 only hinges on the assumptions behind our formal model. The reasoning, which is |
1224 only hinges on the assumptions behind our formal model. The reasoning, which is |
1213 sometimes quite intricate and tedious, has been checked beyond any |
1225 sometimes quite intricate and tedious, has been checked by Isabelle/HOL. |
1214 reasonable doubt by Isabelle/HOL. We can also confirm that Paulson's |
1226 We can also confirm that Paulson's |
1215 inductive method for protocol verification~\cite{Paulson98} is quite |
1227 inductive method for protocol verification~\cite{Paulson98} is quite |
1216 suitable for our formal model and proof. The traditional application |
1228 suitable for our formal model and proof. The traditional application |
1217 area of this method is security protocols. The only other |
1229 area of this method is security protocols. |
1218 application of Paulson's method we know of outside this area is |
|
1219 \cite{Wang09}. |
|
1220 |
1230 |
1221 The second goal of our formalisation is to provide a specification for actually |
1231 The second goal of our formalisation is to provide a specification for actually |
1222 implementing PIP. Textbooks, for example \cite[Section 5.6.5]{Vahalia96}, |
1232 implementing PIP. Textbooks, for example \cite[Section 5.6.5]{Vahalia96}, |
1223 explain how to use various implementations of PIP and abstractly |
1233 explain how to use various implementations of PIP and abstractly |
1224 discuss their properties, but surprisingly lack most details important for a |
1234 discuss their properties, but surprisingly lack most details important for a |
1234 the next thread which takes over a lock is irrelevant for the correctness |
1244 the next thread which takes over a lock is irrelevant for the correctness |
1235 of PIP. Earlier model checking approaches which verified particular implementations |
1245 of PIP. Earlier model checking approaches which verified particular implementations |
1236 of PIP \cite{Faria08,Jahier09,Wellings07} cannot |
1246 of PIP \cite{Faria08,Jahier09,Wellings07} cannot |
1237 provide this kind of ``deep understanding'' about the principles behind |
1247 provide this kind of ``deep understanding'' about the principles behind |
1238 PIP and its correctness. |
1248 PIP and its correctness. |
|
1249 |
|
1250 {\bf rewrite the following slightly} |
1239 |
1251 |
1240 PIP is a scheduling algorithm for single-processor systems. We are |
1252 PIP is a scheduling algorithm for single-processor systems. We are |
1241 now living in a multi-processor world. So the question naturally |
1253 now living in a multi-processor world. So the question naturally |
1242 arises whether PIP has any relevance in such a world beyond |
1254 arises whether PIP has any relevance in such a world beyond |
1243 teaching. Priority Inversion certainly occurs also in |
1255 teaching. Priority Inversion certainly occurs also in |
1258 slave processes. However, a formal investigation of this idea is beyond |
1270 slave processes. However, a formal investigation of this idea is beyond |
1259 the scope of this paper. We are not aware of any proofs in this |
1271 the scope of this paper. We are not aware of any proofs in this |
1260 area, not even informal or flawed ones. |
1272 area, not even informal or flawed ones. |
1261 |
1273 |
1262 The most closely related work to ours is the formal verification in |
1274 The most closely related work to ours is the formal verification in |
1263 PVS of the Priority Ceiling Protocol done by Dutertre |
1275 PVS of the Priority Ceiling Protocol done by Dutertre |
1264 \cite{dutertre99b}---another solution to the Priority Inversion |
1276 \cite{dutertre99b}---another solution to the Priority Inversion |
1265 problem, which however needs |
1277 problem, which however needs static analysis of programs in order to |
1266 static analysis of programs in order to avoid it. |
1278 avoid it. {\bf mention model-checking approaches} |
1267 His formalisation consists of 407 lemmas and 2500 lines of (PVS) code. Our formalisation |
1279 |
|
1280 Our formalisation |
1268 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
1281 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
1269 code with a few apply-scripts interspersed. The formal model of PIP |
1282 code with a few apply-scripts interspersed. The formal model of PIP |
1270 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
1283 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
1271 definitions and proofs span over 770 lines of code. The properties relevant |
1284 definitions and proofs span over 770 lines of code. The properties relevant |
1272 for an implementation require 2000 lines. The code of our formalisation |
1285 for an implementation require 2000 lines. The code of our formalisation |
1273 can be downloaded from |
1286 can be downloaded from |
1274 \url{http://www.inf.kcl.ac.uk/staff/urbanc/pip.html}. |
1287 \url{http://www.inf.kcl.ac.uk/staff/urbanc/pip.html}. |
1275 |
1288 |
|
1289 {\bf say: |
|
1290 So this paper is a good witness for one |
|
1291 of the major reasons to be interested in machine checked reasoning: |
|
1292 gaining deeper understanding of the subject matter. |
|
1293 } |
|
1294 |
|
1295 |
1276 \bibliographystyle{plain} |
1296 \bibliographystyle{plain} |
1277 \bibliography{root} |
1297 \bibliography{root} |
1278 *} |
1298 *} |
1279 |
1299 |
1280 |
1300 |