136 to its original priority level.'' This leads them to believe that an |
136 to its original priority level.'' This leads them to believe that an |
137 implementation of PIP is ``rather straightforward''~\cite{Sha90}. |
137 implementation of PIP is ``rather straightforward''~\cite{Sha90}. |
138 Unfortunately, as Yodaiken points out, this behaviour is too |
138 Unfortunately, as Yodaiken points out, this behaviour is too |
139 simplistic. Consider the case where the low priority thread $L$ |
139 simplistic. Consider the case where the low priority thread $L$ |
140 locks \emph{two} resources, and two high-priority threads $H$ and |
140 locks \emph{two} resources, and two high-priority threads $H$ and |
141 $H'$ each wait for one of them. If $L$ then releases one resource |
141 $H'$ each wait for one of them. If $L$ releases one resource |
142 so that $H$, say, can proceed, then we still have Priority Inversion |
142 so that $H$, say, can proceed, then we still have Priority Inversion |
143 with $H'$ (which waits for the other resource). The correct |
143 with $H'$ (which waits for the other resource). The correct |
144 behaviour for $L$ is to revert to the highest remaining priority of |
144 behaviour for $L$ is to revert to the highest remaining priority of |
145 the threads that it blocks. The advantage of formalising the |
145 the threads that it blocks. The advantage of formalising the |
146 correctness of a high-level specification of PIP in a theorem prover |
146 correctness of a high-level specification of PIP in a theorem prover |
147 is that such issues clearly show up and cannot be overlooked as in |
147 is that such issues clearly show up and cannot be overlooked as in |
148 informal reasoning (since we have to analyse all possible behaviours |
148 informal reasoning (since we have to analyse all possible behaviours |
149 of threads, i.e.~\emph{traces}, that could possibly happen). |
149 of threads, i.e.~\emph{traces}, that could possibly happen).\medskip |
150 |
150 |
151 There have been earlier formal investigations into PIP, but ...\cite{Faria08} |
151 \noindent |
|
152 {\bf Contributions:} There have been earlier formal investigations |
|
153 into PIP, but ...\cite{Faria08} |
152 |
154 |
153 vt (valid trace) was introduced earlier, cite |
155 vt (valid trace) was introduced earlier, cite |
154 |
156 |
155 distributed PIP |
157 distributed PIP |
156 |
158 |
319 \node (D) at (4,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>2"}}; |
321 \node (D) at (4,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>2"}}; |
320 \node (E) at (6,-0.7) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>2"}}; |
322 \node (E) at (6,-0.7) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>2"}}; |
321 \node (E1) at (6, 0.2) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>3"}}; |
323 \node (E1) at (6, 0.2) [draw, circle, very thick, inner sep=0.4mm] {@{text "cs\<^isub>3"}}; |
322 \node (F) at (8,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>3"}}; |
324 \node (F) at (8,-0.7) [draw, rounded corners=1mm, rectangle, very thick] {@{text "th\<^isub>3"}}; |
323 |
325 |
324 \draw [->,line width=0.6mm] (A) to node [pos=0.45,sloped,above=-0.5mm] {\fnt{}holding} (B); |
326 \draw [<-,line width=0.6mm] (A) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding} (B); |
325 \draw [->,line width=0.6mm] (C) to node [pos=0.4,sloped,above=-0.5mm] {\fnt{}waiting} (B); |
327 \draw [->,line width=0.6mm] (C) to node [pos=0.4,sloped,above=-0.5mm] {\fnt{}waiting} (B); |
326 \draw [->,line width=0.6mm] (D) to node [pos=0.4,sloped,below=-0.5mm] {\fnt{}waiting} (B); |
328 \draw [->,line width=0.6mm] (D) to node [pos=0.4,sloped,below=-0.5mm] {\fnt{}waiting} (B); |
327 \draw [->,line width=0.6mm] (D) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}holding} (E); |
329 \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,below=-0.5mm] {\fnt{}holding} (E); |
328 \draw [->,line width=0.6mm] (D) to node [pos=0.45,sloped,above=-0.5mm] {\fnt{}holding} (E1); |
330 \draw [<-,line width=0.6mm] (D) to node [pos=0.54,sloped,above=-0.5mm] {\fnt{}holding} (E1); |
329 \draw [->,line width=0.6mm] (F) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting} (E); |
331 \draw [->,line width=0.6mm] (F) to node [pos=0.45,sloped,below=-0.5mm] {\fnt{}waiting} (E); |
330 \end{tikzpicture} |
332 \end{tikzpicture} |
331 \end{center} |
333 \end{center} |
332 |
334 |
333 \noindent |
335 \noindent |
414 \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"} |
416 \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"} |
415 \end{tabular} |
417 \end{tabular} |
416 \end{isabelle} |
418 \end{isabelle} |
417 |
419 |
418 \noindent |
420 \noindent |
419 More interesting are the cases when a resource, say @{text cs}, is locked or released. In this case |
421 More interesting are the cases when a resource, say @{text cs}, is locked or released. In these cases |
420 we need to calculate a new waiting queue function. For the event @{term P}, we have to update |
422 we need to calculate a new waiting queue function. For the event @{term "P th cs"}, we have to update |
421 the function so that the new thread list for @{text cs} is old thread list plus the thread @{text th} |
423 the function so that the new thread list for @{text cs} is old thread list plus the thread @{text th} |
422 appended to the end of that list (remember the head of this list is seen to be in the possession of the |
424 appended to the end of that list (remember the head of this list is seen to be in the possession of this |
423 resource). |
425 resource). |
424 |
426 |
425 \begin{isabelle}\ \ \ \ \ %%% |
427 \begin{isabelle}\ \ \ \ \ %%% |
426 \begin{tabular}{@ {}l} |
428 \begin{tabular}{@ {}l} |
427 @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ |
429 @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ |
430 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (P th cs # s)|)"} |
432 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (P th cs # s)|)"} |
431 \end{tabular} |
433 \end{tabular} |
432 \end{isabelle} |
434 \end{isabelle} |
433 |
435 |
434 \noindent |
436 \noindent |
435 The clause for event @{term V} is similar, except that we need to update the waiting queue function |
437 The clause for event @{term "V th cs"} is similar, except that we need to update the waiting queue function |
436 so that the thread that possessed the lock is deleted from the corresponding thread list. For this we use |
438 so that the thread that possessed the lock is deleted from the corresponding thread list. For this we use |
437 the auxiliary function @{term release}. A simple version of @{term release} would |
439 the auxiliary function @{term release}. A simple version of @{term release} would |
438 just delete this thread and return the rest, namely |
440 just delete this thread and return the rest, namely |
439 |
441 |
440 \begin{isabelle}\ \ \ \ \ %%% |
442 \begin{isabelle}\ \ \ \ \ %%% |
443 @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "qs"}\\ |
445 @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "qs"}\\ |
444 \end{tabular} |
446 \end{tabular} |
445 \end{isabelle} |
447 \end{isabelle} |
446 |
448 |
447 \noindent |
449 \noindent |
448 In practice, however, often the thread with the highest precedence will get the |
450 In practice, however, often the thread with the highest precedence in the list will get the |
449 lock next. We have implemented this choice, but later found out that the choice |
451 lock next. We have implemented this choice, but later found out that the choice |
450 about which thread is chosen next is actually irrelevant for the correctness of PIP. |
452 of which thread is chosen next is actually irrelevant for the correctness of PIP. |
451 Therefore we prove the stronger result where @{term release} is defined as |
453 Therefore we prove the stronger result where @{term release} is defined as |
452 |
454 |
453 \begin{isabelle}\ \ \ \ \ %%% |
455 \begin{isabelle}\ \ \ \ \ %%% |
454 \begin{tabular}{@ {}lcl} |
456 \begin{tabular}{@ {}lcl} |
455 @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\ |
457 @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\ |
469 \hspace{5mm}@{text "let"} @{text "new_wq = release (wq cs)"} @{text "in"}\\ |
471 \hspace{5mm}@{text "let"} @{text "new_wq = release (wq cs)"} @{text "in"}\\ |
470 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (V th cs # s)|)"} |
472 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (V th cs # s)|)"} |
471 \end{tabular} |
473 \end{tabular} |
472 \end{isabelle} |
474 \end{isabelle} |
473 |
475 |
474 Having the scheduler function @{term schs} at our disposal, we can ``lift'' the notions |
476 Having the scheduler function @{term schs} at our disposal, we can ``lift'', or |
475 @{term waiting}, @{term holding}, @{term depend} and @{term cp} such that they only depend |
477 overload, the notions |
476 on states. |
478 @{term waiting}, @{term holding}, @{term depend} and @{term cp} to operate on states only. |
477 |
479 |
478 \begin{isabelle}\ \ \ \ \ %%% |
480 \begin{isabelle}\ \ \ \ \ %%% |
479 \begin{tabular}{@ {}rcl} |
481 \begin{tabular}{@ {}rcl} |
480 @{thm (lhs) s_holding_abv} & @{text "\<equiv>"} & @{thm (rhs) s_holding_abv}\\ |
482 @{thm (lhs) s_holding_abv} & @{text "\<equiv>"} & @{thm (rhs) s_holding_abv}\\ |
481 @{thm (lhs) s_waiting_abv} & @{text "\<equiv>"} & @{thm (rhs) s_waiting_abv}\\ |
483 @{thm (lhs) s_waiting_abv} & @{text "\<equiv>"} & @{thm (rhs) s_waiting_abv}\\ |
483 @{thm (lhs) cp_def} & @{text "\<equiv>"} & @{thm (rhs) cp_def} |
485 @{thm (lhs) cp_def} & @{text "\<equiv>"} & @{thm (rhs) cp_def} |
484 \end{tabular} |
486 \end{tabular} |
485 \end{isabelle} |
487 \end{isabelle} |
486 |
488 |
487 \noindent |
489 \noindent |
488 With these abbreviations we can introduce for states |
490 With these abbreviations we can introduce |
489 the notion of threads being @{term readys} (i.e.~threads |
491 the notion of threads being @{term readys} in a state (i.e.~threads |
490 that do not wait for any resource) and the running thread. |
492 that do not wait for any resource) and the running thread. |
491 |
493 |
492 \begin{isabelle}\ \ \ \ \ %%% |
494 \begin{isabelle}\ \ \ \ \ %%% |
493 \begin{tabular}{@ {}l} |
495 \begin{tabular}{@ {}l} |
494 @{thm readys_def}\\ |
496 @{thm readys_def}\\ |
501 function @{text f}. |
503 function @{text f}. |
502 Note that in the initial case, that is where the list of events is empty, the set |
504 Note that in the initial case, that is where the list of events is empty, the set |
503 @{term threads} is empty and therefore there is no thread ready nor a running. |
505 @{term threads} is empty and therefore there is no thread ready nor a running. |
504 If there is one or more threads ready, then there can only be \emph{one} thread |
506 If there is one or more threads ready, then there can only be \emph{one} thread |
505 running, namely the one whose current precedence is equal to the maximum of all ready |
507 running, namely the one whose current precedence is equal to the maximum of all ready |
506 threads. We can also define the set of resources that are locked by a thread in any |
508 threads. We use the set-comprehension to capture both possibilites. |
|
509 We can now also define the set of resources that are locked by a thread in any |
507 given state. |
510 given state. |
508 |
511 |
509 \begin{isabelle}\ \ \ \ \ %%% |
512 \begin{isabelle}\ \ \ \ \ %%% |
510 @{thm holdents_def} |
513 @{thm holdents_def} |
511 \end{isabelle} |
514 \end{isabelle} |