723 @{thm[mode=IfThen] runing_unique[of _ "th\<^isub>1" "th\<^isub>2"]} |
724 @{thm[mode=IfThen] runing_unique[of _ "th\<^isub>1" "th\<^isub>2"]} |
724 \end{tabular} |
725 \end{tabular} |
725 \end{isabelle} |
726 \end{isabelle} |
726 |
727 |
727 \noindent |
728 \noindent |
728 The first one states that every waiting thread can only wait for a single |
729 The first property states that every waiting thread can only wait for a single |
729 resource (because it gets suspended after requesting that resource and having |
730 resource (because it gets suspended after requesting that resource); the second |
730 to wait for it); the second that every resource can only be held by a single thread; |
731 that every resource can only be held by a single thread; |
731 the third property establishes that in every given valid state, there is |
732 the third property establishes that in every given valid state, there is |
732 at most one running thread. We can also show the following properties |
733 at most one running thread. We can also show the following properties |
733 about the RAG in @{text "s"}. |
734 about the @{term RAG} in @{text "s"}. |
734 |
735 |
735 \begin{isabelle}\ \ \ \ \ %%% |
736 \begin{isabelle}\ \ \ \ \ %%% |
736 \begin{tabular}{@ {}l} |
737 \begin{tabular}{@ {}l} |
737 @{text If}~@{thm (prem 1) acyclic_depend}~@{text "then"}:\\ |
738 @{text If}~@{thm (prem 1) acyclic_depend}~@{text "then"}:\\ |
738 \hspace{5mm}@{thm (concl) acyclic_depend}, |
739 \hspace{5mm}@{thm (concl) acyclic_depend}, |
739 @{thm (concl) finite_depend} and |
740 @{thm (concl) finite_depend} and |
740 @{thm (concl) wf_dep_converse},\\ |
741 @{thm (concl) wf_dep_converse},\\ |
741 \hspace{5mm}@{text "if"}~@{thm (prem 2) dm_depend_threads}~@{text "then"}~@{thm (concl) dm_depend_threads}\\ |
742 \hspace{5mm}@{text "if"}~@{thm (prem 2) dm_depend_threads}~@{text "then"}~@{thm (concl) dm_depend_threads} |
742 \hspace{5mm}@{text "if"}~@{thm (prem 2) range_in}~@{text "then"}~@{thm (concl) range_in} |
743 and\\ |
743 \end{tabular} |
744 \hspace{5mm}@{text "if"}~@{thm (prem 2) range_in}~@{text "then"}~@{thm (concl) range_in}. |
744 \end{isabelle} |
745 \end{tabular} |
745 |
746 \end{isabelle} |
746 TODO |
747 |
747 |
748 \noindent |
748 \noindent |
749 The acyclicity property follow from how we restricted the events in |
749 The following lemmas show how RAG is changed with the execution of events: |
750 @{text step}; similarly the finiteness and well-foundedness property. |
750 \begin{enumerate} |
751 The last two properties establish that every thread in a @{text "RAG"} |
751 \item Execution of @{term "Set"} does not change RAG (@{text "depend_set_unchanged"}): |
752 (either holding or waiting for a resource) is a live thread. |
752 @{thm[display] depend_set_unchanged} |
753 |
753 \item Execution of @{term "Create"} does not change RAG (@{text "depend_create_unchanged"}): |
754 To state the key lemma in our proof, it will be convenient to introduce the notion |
754 @{thm[display] depend_create_unchanged} |
755 of a \emph{detached} thread in a state, that is one which does not hold any |
755 \item Execution of @{term "Exit"} does not change RAG (@{text "depend_exit_unchanged"}): |
756 critical resource nor requests one. |
756 @{thm[display] depend_exit_unchanged} |
757 |
757 \item Execution of @{term "P"} (@{text "step_depend_p"}): |
758 \begin{lemma}\label{mainlem} |
758 @{thm[display] step_depend_p} |
759 Given the assumptions about states @{text "s"} and @{text "s' @ s"}, |
759 \item Execution of @{term "V"} (@{text "step_depend_v"}): |
760 the thread @{text th} and the events in @{text "s'"}, |
760 @{thm[display] step_depend_v} |
761 if @{term "th' \<in> treads (s' @ s)"}, @{text "th' \<noteq> th"} and @{text "detached (s' @ s) th'"}\\ |
761 \end{enumerate} |
762 then @{text "th' \<notin> running (s' @ s)"}. |
762 *} |
763 \end{lemma} |
763 |
764 |
764 text {* \noindent |
765 \noindent |
765 These properties are used to derive the following important results about RAG: |
766 The point of this lemma is that a thread different from @{text th} (which has the highest |
766 \begin{enumerate} |
767 precedence in @{text s}) not holding any resource cannot be running |
767 \item RAG is loop free (@{text "acyclic_depend"}): |
768 in the state @{text "s' @ s"}. |
768 @{thm [display] acyclic_depend} |
769 |
769 \item RAGs are finite (@{text "finite_depend"}): |
770 \begin{proof} |
770 @{thm [display] finite_depend} |
771 Since thread @{text "th'"} does not hold any resource, no thread can depend on it. |
771 \item Reverse paths in RAG are well founded (@{text "wf_dep_converse"}): |
772 Therefore its current precedence @{term "cp (s' @ s) th'"} equals its own precedence |
772 @{thm [display] wf_dep_converse} |
773 @{term "prec th' (s' @ s)"}. Since @{text "th"} has the highest precedence in the |
773 \item The dependence relation represented by RAG has a tree structure (@{text "unique_depend"}): |
774 state @{text "(s' @ s)"} and precedences are distinct among threads, we have |
774 @{thm [display] unique_depend[of _ _ "n\<^isub>1" "n\<^isub>2"]} |
775 @{term "prec th' (s' @s ) < prec th (s' @ s)"}. From this |
775 \item All threads in RAG are living threads |
776 we have @{term "cp (s' @ s) th' < prec th (s' @ s)"}. |
776 (@{text "dm_depend_threads"} and @{text "range_in"}): |
777 Since @{text "prec th (s' @ s)"} is already the highest |
777 @{thm [display] dm_depend_threads range_in} |
778 @{term "cp (s' @ s) th"} can not be higher than this and can not be lower either (by |
778 \end{enumerate} |
779 definition of @{term "cp"}). Consequently, we have @{term "prec th (s' @ s) = cp (s' @ s) th"}. |
779 *} |
780 Finally we have @{term "cp (s' @ s) th' < cp (s' @ s) th"}. |
780 |
781 By defintion of @{text "running"}, @{text "th'"} can not be running in state |
781 text {* \noindent |
782 @{text "s' @ s"}, as we had to show.\qed |
|
783 \end{proof} |
|
784 |
|
785 \noindent |
|
786 Since @{text "th'"} is not able to run at state @{text "s' @ s"}, it is not able to |
|
787 issue a {text "P"} or @{text "V"} event. Therefore if @{text "s' @ s"} is extended |
|
788 one step further, @{text "th'"} still cannot hold any resource. The situation will |
|
789 not change in further extensions as long as @{text "th"} holds the highest precedence. |
|
790 |
|
791 |
782 The following lemmas show how every node in RAG can be chased to ready threads: |
792 The following lemmas show how every node in RAG can be chased to ready threads: |
783 \begin{enumerate} |
793 \begin{enumerate} |
784 \item Every node in RAG can be chased to a ready thread (@{text "chain_building"}): |
794 \item Every node in RAG can be chased to a ready thread (@{text "chain_building"}): |
785 @{thm [display] chain_building[rule_format]} |
795 @{thm [display] chain_building[rule_format]} |
786 \item The ready thread chased to is unique (@{text "dchain_unique"}): |
796 \item The ready thread chased to is unique (@{text "dchain_unique"}): |
787 @{thm [display] dchain_unique[of _ _ "th\<^isub>1" "th\<^isub>2"]} |
797 @{thm [display] dchain_unique[of _ _ "th\<^isub>1" "th\<^isub>2"]} |
788 \end{enumerate} |
798 \end{enumerate} |
789 *} |
799 *} |
790 |
800 |
791 text {* \noindent |
|
792 Properties about @{term "next_th"}: |
|
793 \begin{enumerate} |
|
794 \item The thread taking over is different from the thread which is releasing |
|
795 (@{text "next_th_neq"}): |
|
796 @{thm [display] next_th_neq} |
|
797 \item The thread taking over is unique |
|
798 (@{text "next_th_unique"}): |
|
799 @{thm [display] next_th_unique[of _ _ _ "th\<^isub>1" "th\<^isub>2"]} |
|
800 \end{enumerate} |
|
801 *} |
|
802 |
801 |
803 text {* \noindent |
802 text {* \noindent |
804 Some deeper results about the system: |
803 Some deeper results about the system: |
805 \begin{enumerate} |
804 \begin{enumerate} |
806 \item The maximum of @{term "cp"} and @{term "preced"} are equal (@{text "max_cp_eq"}): |
805 \item The maximum of @{term "cp"} and @{term "preced"} are equal (@{text "max_cp_eq"}): |
867 if a thread releases all its resources at some moment in @{text "t"}, after that, |
856 if a thread releases all its resources at some moment in @{text "t"}, after that, |
868 it may never get a change to run. If every thread releases its resource in finite duration, |
857 it may never get a change to run. If every thread releases its resource in finite duration, |
869 then after a while, only thread @{text "th"} is left running. This shows how indefinite |
858 then after a while, only thread @{text "th"} is left running. This shows how indefinite |
870 priority inversion can be avoided. |
859 priority inversion can be avoided. |
871 |
860 |
872 So, the key of the proof is to establish the correctness of @{text "moment_blocked"}. |
|
873 We are going to show how this lemma is proved. At the heart of this proof, is |
|
874 lemma @{text "pv_blocked"}: |
|
875 @{thm [display] pv_blocked} |
|
876 This lemma says: for any @{text "s"}-extension {text "t"}, if thread @{text "th'"} |
|
877 does not hold any resource, it can not be running at @{text "t@s"}. |
|
878 |
|
879 |
|
880 \noindent Proof: |
|
881 \begin{enumerate} |
|
882 \item Since thread @{text "th'"} does not hold any resource, no thread may depend on it, |
|
883 so its current precedence @{text "cp (t@s) th'"} equals to its own precedence |
|
884 @{text "preced th' (t@s)"}. \label{arg_1} |
|
885 \item Since @{text "th"} has the highest precedence in the system and |
|
886 precedences are distinct among threads, we have |
|
887 @{text "preced th' (t@s) < preced th (t@s)"}. From this and item \ref{arg_1}, |
|
888 we have @{text "cp (t@s) th' < preced th (t@s)"}. |
|
889 \item Since @{text "preced th (t@s)"} is already the highest in the system, |
|
890 @{text "cp (t@s) th"} can not be higher than this and can not be lower neither (by |
|
891 the definition of @{text "cp"}), we have @{text "preced th (t@s) = cp (t@s) th"}. |
|
892 \item Finally we have @{text "cp (t@s) th' < cp (t@s) th"}. |
|
893 \item By defintion of @{text "running"}, @{text "th'"} can not be runing at |
|
894 @{text "t@s"}. |
|
895 \end{enumerate} |
|
896 Since @{text "th'"} is not able to run at state @{text "t@s"}, it is not able to |
|
897 make either {text "P"} or @{text "V"} action, so if @{text "t@s"} is extended |
|
898 one step further, @{text "th'"} still does not hold any resource. |
|
899 The situation will not unchanged in further extensions as long as |
|
900 @{text "th"} holds the highest precedence. Since this @{text "t"} is arbitarily chosen |
|
901 except being constrained by predicate @{text "extend_highest_gen"} and |
|
902 this predicate has the property that if it holds for @{text "t"}, it also holds |
|
903 for any moment @{text "i"} inside @{text "t"}, as shown by lemma @{text "red_moment"}: |
|
904 @{thm [display] "extend_highest_gen.red_moment"} |
|
905 so @{text "pv_blocked"} can be applied to any @{text "moment i t"}. |
|
906 From this, lemma @{text "moment_blocked"} follows. |
|
907 *} |
861 *} |
908 |
862 |
909 (*<*) |
|
910 end |
|
911 (*>*) |
|
912 |
|
913 |
|
914 section {* Properties for an Implementation\label{implement} *} |
|
915 |
|
916 text {* |
|
917 While a formal correctness proof for our model of PIP is certainly |
|
918 attractive (especially in light of the flawed proof by Sha et |
|
919 al.~\cite{Sha90}), we found that the formalisation can even help us |
|
920 with efficiently implementing PIP. |
|
921 |
|
922 For example Baker complained that calculating the current precedence |
|
923 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
|
924 In our model of PIP the current precedence of a thread in a state s |
|
925 depends on all its dependants---a ``global'' transitive notion, |
|
926 which is indeed heavy weight (see Def.~shown in \eqref{cpreced}). |
|
927 We can however improve upon this. For this let us define the notion |
|
928 of @{term children} of a thread @{text th} in a state @{text s} as |
|
929 |
|
930 \begin{isabelle}\ \ \ \ \ %%% |
|
931 \begin{tabular}{@ {}l} |
|
932 @{thm children_def2} |
|
933 \end{tabular} |
|
934 \end{isabelle} |
|
935 |
|
936 \noindent |
|
937 where a child is a thread that is one ``hop'' away from the tread |
|
938 @{text th} in the @{term RAG} (and waiting for @{text th} to release |
|
939 a resource). We can prove that |
|
940 |
|
941 \begin{lemma}\label{childrenlem} |
|
942 @{text "If"} @{thm (prem 1) cp_rec} @{text "then"} |
|
943 \begin{center} |
|
944 @{thm (concl) cp_rec}. |
|
945 \end{center} |
|
946 \end{lemma} |
|
947 |
|
948 \noindent |
|
949 That means the current precedence of a thread @{text th} can be |
|
950 computed locally by considering only the children of @{text th}. In |
|
951 effect, it only needs to be recomputed for @{text th} when one of |
|
952 its children changes its current precedence. Once the current |
|
953 precedence is computed in this more efficient manner, the selection |
|
954 of the thread with highest precedence from a set of ready threads is |
|
955 a standard scheduling operation implemented in most operating |
|
956 systems. |
|
957 |
|
958 Of course the main implementation work for PIP involves the |
|
959 scheduler and coding how it should react to events. Below we |
|
960 outline how our formalisation guides this implementation for each |
|
961 kind of event.\smallskip |
|
962 *} |
|
963 |
|
964 (*<*) |
|
965 context step_create_cps |
|
966 begin |
|
967 (*>*) |
|
968 text {* |
|
969 \noindent |
|
970 \colorbox{mygrey}{@{term "Create th prio"}:} We assume that the current state @{text s'} and |
|
971 the next state @{term "s \<equiv> Create th prio#s'"} are both valid (meaning the event |
|
972 is allowed to occur). In this situation we can show that |
|
973 |
|
974 \begin{isabelle}\ \ \ \ \ %%% |
|
975 \begin{tabular}{@ {}l} |
|
976 @{thm eq_dep},\\ |
|
977 @{thm eq_cp_th}, and\\ |
|
978 @{thm[mode=IfThen] eq_cp} |
|
979 \end{tabular} |
|
980 \end{isabelle} |
|
981 |
|
982 \noindent |
|
983 This means we do not have recalculate the @{text RAG} and also none of the |
|
984 current precedences of the other threads. The current precedence of the created |
|
985 thread @{text th} is just its precedence, namely the pair @{term "(prio, length (s::event list))"}. |
|
986 \smallskip |
|
987 *} |
|
988 (*<*) |
|
989 end |
|
990 context step_exit_cps |
|
991 begin |
|
992 (*>*) |
|
993 text {* |
|
994 \noindent |
|
995 \colorbox{mygrey}{@{term "Exit th"}:} We again assume that the current state @{text s'} and |
|
996 the next state @{term "s \<equiv> Exit th#s'"} are both valid. We can show that |
|
997 |
|
998 \begin{isabelle}\ \ \ \ \ %%% |
|
999 \begin{tabular}{@ {}l} |
|
1000 @{thm eq_dep}, and\\ |
|
1001 @{thm[mode=IfThen] eq_cp} |
|
1002 \end{tabular} |
|
1003 \end{isabelle} |
|
1004 |
|
1005 \noindent |
|
1006 This means again we do not have to recalculate the @{text RAG} and |
|
1007 also not the current precedences for the other threads. Since @{term th} is not |
|
1008 alive anymore in state @{term "s"}, there is no need to calculate its |
|
1009 current precedence. |
|
1010 \smallskip |
|
1011 *} |
|
1012 (*<*) |
|
1013 end |
|
1014 context step_set_cps |
|
1015 begin |
|
1016 (*>*) |
|
1017 text {* |
|
1018 \noindent |
|
1019 \colorbox{mygrey}{@{term "Set th prio"}:} We assume that @{text s'} and |
|
1020 @{term "s \<equiv> Set th prio#s'"} are both valid. We can show that |
|
1021 |
|
1022 \begin{isabelle}\ \ \ \ \ %%% |
|
1023 \begin{tabular}{@ {}l} |
|
1024 @{thm[mode=IfThen] eq_dep}, and\\ |
|
1025 @{thm[mode=IfThen] eq_cp} |
|
1026 \end{tabular} |
|
1027 \end{isabelle} |
|
1028 |
|
1029 \noindent |
|
1030 The first property is again telling us we do not need to change the @{text RAG}. The second |
|
1031 however states that only threads that are \emph{not} dependants of @{text th} have their |
|
1032 current precedence unchanged. For the others we have to recalculate the current |
|
1033 precedence. To do this we can start from @{term "th"} |
|
1034 and follow the @{term "depend"}-chains to recompute the @{term "cp"} of every |
|
1035 thread encountered on the way using Lemma~\ref{childrenlem}. Since the @{term "depend"} |
|
1036 is loop free, this procedure will always stop. The following two lemmas show, however, |
|
1037 that this procedure can actually stop often earlier without having to consider all |
|
1038 dependants. |
|
1039 |
|
1040 \begin{isabelle}\ \ \ \ \ %%% |
|
1041 \begin{tabular}{@ {}l} |
|
1042 @{thm[mode=IfThen] eq_up_self}\\ |
|
1043 @{text "If"} @{thm (prem 1) eq_up}, @{thm (prem 2) eq_up} and @{thm (prem 3) eq_up}\\ |
|
1044 @{text "then"} @{thm (concl) eq_up}. |
|
1045 \end{tabular} |
|
1046 \end{isabelle} |
|
1047 |
|
1048 \noindent |
|
1049 The first states that if the current precedence of @{text th} is unchanged, |
|
1050 then the procedure can stop immediately (all dependent threads have their @{term cp}-value unchanged). |
|
1051 The second states that if an intermediate @{term cp}-value does not change, then |
|
1052 the procedure can also stop, because none of its dependent threads will |
|
1053 have their current precedence changed. |
|
1054 \smallskip |
|
1055 *} |
|
1056 (*<*) |
|
1057 end |
|
1058 context step_v_cps_nt |
|
1059 begin |
|
1060 (*>*) |
|
1061 text {* |
|
1062 \noindent |
|
1063 \colorbox{mygrey}{@{term "V th cs"}:} We assume that @{text s'} and |
|
1064 @{term "s \<equiv> V th cs#s'"} are both valid. We have to consider two |
|
1065 subcases: one where there is a thread to ``take over'' the released |
|
1066 resource @{text cs}, and one where there is not. Let us consider them |
|
1067 in turn. Suppose in state @{text s}, the thread @{text th'} takes over |
|
1068 resource @{text cs} from thread @{text th}. We can show |
|
1069 |
|
1070 |
|
1071 \begin{isabelle}\ \ \ \ \ %%% |
|
1072 @{thm depend_s} |
|
1073 \end{isabelle} |
|
1074 |
|
1075 \noindent |
|
1076 which shows how the @{text RAG} needs to be changed. This also suggests |
|
1077 how the current precedences need to be recalculated. For threads that are |
|
1078 not @{text "th"} and @{text "th'"} nothing needs to be changed, since we |
|
1079 can show |
|
1080 |
|
1081 \begin{isabelle}\ \ \ \ \ %%% |
|
1082 @{thm[mode=IfThen] cp_kept} |
|
1083 \end{isabelle} |
|
1084 |
|
1085 \noindent |
|
1086 For @{text th} and @{text th'} we need to use Lemma~\ref{childrenlem} to |
|
1087 recalculate their current prcedence since their children have changed. *}(*<*)end context step_v_cps_nnt begin (*>*)text {* |
|
1088 \noindent |
|
1089 In the other case where there is no thread that takes over @{text cs}, we can show how |
|
1090 to recalculate the @{text RAG} and also show that no current precedence needs |
|
1091 to be recalculated. |
|
1092 |
|
1093 \begin{isabelle}\ \ \ \ \ %%% |
|
1094 \begin{tabular}{@ {}l} |
|
1095 @{thm depend_s}\\ |
|
1096 @{thm eq_cp} |
|
1097 \end{tabular} |
|
1098 \end{isabelle} |
|
1099 *} |
|
1100 (*<*) |
|
1101 end |
|
1102 context step_P_cps_e |
|
1103 begin |
|
1104 (*>*) |
|
1105 |
|
1106 text {* |
|
1107 \noindent |
|
1108 \colorbox{mygrey}{@{term "P th cs"}:} We assume that @{text s'} and |
|
1109 @{term "s \<equiv> P th cs#s'"} are both valid. We again have to analyse two subcases, namely |
|
1110 the one where @{text cs} is locked, and where it is not. We treat the second case |
|
1111 first by showing that |
|
1112 |
|
1113 \begin{isabelle}\ \ \ \ \ %%% |
|
1114 \begin{tabular}{@ {}l} |
|
1115 @{thm depend_s}\\ |
|
1116 @{thm eq_cp} |
|
1117 \end{tabular} |
|
1118 \end{isabelle} |
|
1119 |
|
1120 \noindent |
|
1121 This means we do not need to add a holding edge to the @{text RAG} and no |
|
1122 current precedence needs to be recalculated.*}(*<*)end context step_P_cps_ne begin(*>*) text {* |
|
1123 \noindent |
|
1124 In the second case we know that resouce @{text cs} is locked. We can show that |
|
1125 |
|
1126 \begin{isabelle}\ \ \ \ \ %%% |
|
1127 \begin{tabular}{@ {}l} |
|
1128 @{thm depend_s}\\ |
|
1129 @{thm[mode=IfThen] eq_cp} |
|
1130 \end{tabular} |
|
1131 \end{isabelle} |
|
1132 |
|
1133 \noindent |
|
1134 That means we have to add a waiting edge to the @{text RAG}. Furthermore |
|
1135 the current precedence for all threads that are not dependants of @{text th} |
|
1136 are unchanged. For the others we need to follow the edges |
|
1137 in the @{text RAG} and recompute the @{term "cp"}. However, like in the |
|
1138 @case of {text Set}, this operation can stop often earlier, namely when intermediate |
|
1139 values do not change. |
|
1140 *} |
|
1141 (*<*) |
|
1142 end |
|
1143 (*>*) |
|
1144 text {* |
|
1145 \noindent |
|
1146 A pleasing result of our formalisation is that the properties in |
|
1147 this section closely inform an implementation of PIP: Whether the |
|
1148 @{text RAG} needs to be reconfigured or current precedences need to |
|
1149 recalculated for an event is given by a lemma we proved. |
|
1150 *} |
|
1151 |
|
1152 section {* Conclusion *} |
|
1153 |
|
1154 text {* |
|
1155 The Priority Inheritance Protocol (PIP) is a classic textbook |
|
1156 algorithm used in real-time operating systems in order to avoid the problem of |
|
1157 Priority Inversion. Although classic and widely used, PIP does have |
|
1158 its faults: for example it does not prevent deadlocks in cases where threads |
|
1159 have circular lock dependencies. |
|
1160 |
|
1161 We had two goals in mind with our formalisation of PIP: One is to |
|
1162 make the notions in the correctness proof by Sha et al.~\cite{Sha90} |
|
1163 precise so that they can be processed by a theorem prover. The reason is |
|
1164 that a mechanically checked proof avoids the flaws that crept into their |
|
1165 informal reasoning. We achieved this goal: The correctness of PIP now |
|
1166 only hinges on the assumptions behind our formal model. The reasoning, which is |
|
1167 sometimes quite intricate and tedious, has been checked beyond any |
|
1168 reasonable doubt by Isabelle/HOL. We can also confirm that Paulson's |
|
1169 inductive method for protocol verification~\cite{Paulson98} is quite |
|
1170 suitable for our formal model and proof. The traditional application |
|
1171 area of this method is security protocols. The only other |
|
1172 application of Paulson's method we know of outside this area is |
|
1173 \cite{Wang09}. |
|
1174 |
|
1175 The second goal of our formalisation is to provide a specification for actually |
|
1176 implementing PIP. Textbooks, for example \cite[Section 5.6.5]{Vahalia96}, |
|
1177 explain how to use various implementations of PIP and abstractly |
|
1178 discuss their properties, but surprisingly lack most details for a |
|
1179 programmer who wants to implement PIP. That this is an issue in practice is illustrated by the |
|
1180 email from Baker we cited in the Introduction. We achieved also this |
|
1181 goal: The formalisation gives the first author enough data to enable |
|
1182 his undergraduate students to implement PIP (as part of their OS course) |
|
1183 on top of PINTOS, a small operating system for teaching |
|
1184 purposes. A byproduct of our formalisation effort is that nearly all |
|
1185 design choices for the PIP scheduler are backed up with a proved |
|
1186 lemma. We were also able to establish the property that the choice of |
|
1187 the next thread which takes over a lock is irrelevant for the correctness |
|
1188 of PIP. Earlier model checking approaches which verified implementations |
|
1189 of PIP \cite{Faria08,Jahier09,Wellings07} cannot |
|
1190 provide this kind of ``deep understanding'' about the principles behind |
|
1191 PIP and its correctness. |
|
1192 |
|
1193 PIP is a scheduling algorithm for single-processor systems. We are |
|
1194 now living in a multi-processor world. So the question naturally |
|
1195 arises whether PIP has any relevance in such a world beyond |
|
1196 teaching. Priority Inversion certainly occurs also in |
|
1197 multi-processor systems. However, the surprising answer, according |
|
1198 to \cite{Steinberg10}, is that except for one unsatisfactory |
|
1199 proposal nobody has a good idea for how PIP should be modified to |
|
1200 work correctly on multi-processor systems. The difficulties become |
|
1201 clear when considering that locking and releasing a resource always |
|
1202 requires a small amount of time. If processes work independently, |
|
1203 then a low priority process can ``steal'' in such an unguarded |
|
1204 moment a lock for a resource that was supposed allow a high-priority |
|
1205 process to run next. Thus the problem of Priority Inversion is not |
|
1206 really prevented. It seems difficult to design a PIP-algorithm with |
|
1207 a meaningful correctness property on a multi-processor systems where |
|
1208 processes work independently. We can imagine PIP to be of use in |
|
1209 situations where processes are \emph{not} independent, but |
|
1210 coordinated via a master process that distributes work over some |
|
1211 slave processes. However, a formal investigation of this is beyond |
|
1212 the scope of this paper. We are not aware of any proofs in this |
|
1213 area, not even informal ones. |
|
1214 |
|
1215 The most closely related work to ours is the formal verification in |
|
1216 PVS for Priority Ceiling done by Dutertre \cite{dutertre99b}. His formalisation |
|
1217 consists of 407 lemmas and 2500 lines of ``specification'' (we do not |
|
1218 know whether this includes also code for proofs). Our formalisation |
|
1219 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
|
1220 code with a few apply-scripts interspersed. The formal model of PIP |
|
1221 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
|
1222 definitions and proofs took 770 lines of code. The properties relevant |
|
1223 for an implementation took 2000 lines. Our code can be downloaded from |
|
1224 ... |
|
1225 |
|
1226 \bibliographystyle{plain} |
|
1227 \bibliography{root} |
|
1228 *} |
|
1229 |
|
1230 section {* Key properties \label{extension} *} |
863 section {* Key properties \label{extension} *} |
1231 |
864 |
1232 (*<*) |
|
1233 context extend_highest_gen |
|
1234 begin |
|
1235 (*>*) |
|
1236 |
|
1237 text {* |
|
1238 The essential of {\em Priority Inheritance} is to avoid indefinite priority inversion. For this |
|
1239 purpose, we need to investigate what happens after one thread takes the highest precedence. |
|
1240 A locale is used to describe such a situation, which assumes: |
|
1241 \begin{enumerate} |
|
1242 \item @{term "s"} is a valid state (@{text "vt_s"}): |
|
1243 @{thm vt_s}. |
|
1244 \item @{term "th"} is a living thread in @{term "s"} (@{text "threads_s"}): |
|
1245 @{thm threads_s}. |
|
1246 \item @{term "th"} has the highest precedence in @{term "s"} (@{text "highest"}): |
|
1247 @{thm highest}. |
|
1248 \item The precedence of @{term "th"} is @{term "Prc prio tm"} (@{text "preced_th"}): |
|
1249 @{thm preced_th}. |
|
1250 \end{enumerate} |
|
1251 *} |
|
1252 |
|
1253 text {* \noindent |
|
1254 Under these assumptions, some basic priority can be derived for @{term "th"}: |
|
1255 \begin{enumerate} |
|
1256 \item The current precedence of @{term "th"} equals its own precedence (@{text "eq_cp_s_th"}): |
|
1257 @{thm [display] eq_cp_s_th} |
|
1258 \item The current precedence of @{term "th"} is the highest precedence in |
|
1259 the system (@{text "highest_cp_preced"}): |
|
1260 @{thm [display] highest_cp_preced} |
|
1261 \item The precedence of @{term "th"} is the highest precedence |
|
1262 in the system (@{text "highest_preced_thread"}): |
|
1263 @{thm [display] highest_preced_thread} |
|
1264 \item The current precedence of @{term "th"} is the highest current precedence |
|
1265 in the system (@{text "highest'"}): |
|
1266 @{thm [display] highest'} |
|
1267 \end{enumerate} |
|
1268 *} |
|
1269 |
|
1270 text {* \noindent |
|
1271 To analysis what happens after state @{term "s"} a sub-locale is defined, which |
|
1272 assumes: |
|
1273 \begin{enumerate} |
|
1274 \item @{term "t"} is a valid extension of @{term "s"} (@{text "vt_t"}): @{thm vt_t}. |
|
1275 \item Any thread created in @{term "t"} has priority no higher than @{term "prio"}, therefore |
|
1276 its precedence can not be higher than @{term "th"}, therefore |
|
1277 @{term "th"} remain to be the one with the highest precedence |
|
1278 (@{text "create_low"}): |
|
1279 @{thm [display] create_low} |
|
1280 \item Any adjustment of priority in |
|
1281 @{term "t"} does not happen to @{term "th"} and |
|
1282 the priority set is no higher than @{term "prio"}, therefore |
|
1283 @{term "th"} remain to be the one with the highest precedence (@{text "set_diff_low"}): |
|
1284 @{thm [display] set_diff_low} |
|
1285 \item Since we are investigating what happens to @{term "th"}, it is assumed |
|
1286 @{term "th"} does not exit during @{term "t"} (@{text "exit_diff"}): |
|
1287 @{thm [display] exit_diff} |
|
1288 \end{enumerate} |
|
1289 *} |
|
1290 |
865 |
1291 text {* \noindent |
866 text {* \noindent |
1292 All these assumptions are put into a predicate @{term "extend_highest_gen"}. |
867 All these assumptions are put into a predicate @{term "extend_highest_gen"}. |
1293 It can be proved that @{term "extend_highest_gen"} holds |
868 It can be proved that @{term "extend_highest_gen"} holds |
1294 for any moment @{text "i"} in it @{term "t"} (@{text "red_moment"}): |
869 for any moment @{text "i"} in it @{term "t"} (@{text "red_moment"}): |
1341 then. |
916 then. |
1342 *} |
917 *} |
1343 |
918 |
1344 (*<*) |
919 (*<*) |
1345 end |
920 end |
1346 |
921 (*>*) |
|
922 |
|
923 section {* Properties for an Implementation\label{implement} *} |
|
924 |
|
925 text {* |
|
926 While a formal correctness proof for our model of PIP is certainly |
|
927 attractive (especially in light of the flawed proof by Sha et |
|
928 al.~\cite{Sha90}), we found that the formalisation can even help us |
|
929 with efficiently implementing PIP. |
|
930 |
|
931 For example Baker complained that calculating the current precedence |
|
932 in PIP is quite ``heavy weight'' in Linux (see the Introduction). |
|
933 In our model of PIP the current precedence of a thread in a state s |
|
934 depends on all its dependants---a ``global'' transitive notion, |
|
935 which is indeed heavy weight (see Def.~shown in \eqref{cpreced}). |
|
936 We can however improve upon this. For this let us define the notion |
|
937 of @{term children} of a thread @{text th} in a state @{text s} as |
|
938 |
|
939 \begin{isabelle}\ \ \ \ \ %%% |
|
940 \begin{tabular}{@ {}l} |
|
941 @{thm children_def2} |
|
942 \end{tabular} |
|
943 \end{isabelle} |
|
944 |
|
945 \noindent |
|
946 where a child is a thread that is one ``hop'' away from the tread |
|
947 @{text th} in the @{term RAG} (and waiting for @{text th} to release |
|
948 a resource). We can prove that |
|
949 |
|
950 \begin{lemma}\label{childrenlem} |
|
951 @{text "If"} @{thm (prem 1) cp_rec} @{text "then"} |
|
952 \begin{center} |
|
953 @{thm (concl) cp_rec}. |
|
954 \end{center} |
|
955 \end{lemma} |
|
956 |
|
957 \noindent |
|
958 That means the current precedence of a thread @{text th} can be |
|
959 computed locally by considering only the children of @{text th}. In |
|
960 effect, it only needs to be recomputed for @{text th} when one of |
|
961 its children changes its current precedence. Once the current |
|
962 precedence is computed in this more efficient manner, the selection |
|
963 of the thread with highest precedence from a set of ready threads is |
|
964 a standard scheduling operation implemented in most operating |
|
965 systems. |
|
966 |
|
967 Of course the main implementation work for PIP involves the |
|
968 scheduler and coding how it should react to events. Below we |
|
969 outline how our formalisation guides this implementation for each |
|
970 kind of event.\smallskip |
|
971 *} |
|
972 |
|
973 (*<*) |
|
974 context step_create_cps |
|
975 begin |
|
976 (*>*) |
|
977 text {* |
|
978 \noindent |
|
979 \colorbox{mygrey}{@{term "Create th prio"}:} We assume that the current state @{text s'} and |
|
980 the next state @{term "s \<equiv> Create th prio#s'"} are both valid (meaning the event |
|
981 is allowed to occur). In this situation we can show that |
|
982 |
|
983 \begin{isabelle}\ \ \ \ \ %%% |
|
984 \begin{tabular}{@ {}l} |
|
985 @{thm eq_dep},\\ |
|
986 @{thm eq_cp_th}, and\\ |
|
987 @{thm[mode=IfThen] eq_cp} |
|
988 \end{tabular} |
|
989 \end{isabelle} |
|
990 |
|
991 \noindent |
|
992 This means we do not have recalculate the @{text RAG} and also none of the |
|
993 current precedences of the other threads. The current precedence of the created |
|
994 thread @{text th} is just its precedence, namely the pair @{term "(prio, length (s::event list))"}. |
|
995 \smallskip |
|
996 *} |
|
997 (*<*) |
|
998 end |
|
999 context step_exit_cps |
|
1000 begin |
|
1001 (*>*) |
|
1002 text {* |
|
1003 \noindent |
|
1004 \colorbox{mygrey}{@{term "Exit th"}:} We again assume that the current state @{text s'} and |
|
1005 the next state @{term "s \<equiv> Exit th#s'"} are both valid. We can show that |
|
1006 |
|
1007 \begin{isabelle}\ \ \ \ \ %%% |
|
1008 \begin{tabular}{@ {}l} |
|
1009 @{thm eq_dep}, and\\ |
|
1010 @{thm[mode=IfThen] eq_cp} |
|
1011 \end{tabular} |
|
1012 \end{isabelle} |
|
1013 |
|
1014 \noindent |
|
1015 This means again we do not have to recalculate the @{text RAG} and |
|
1016 also not the current precedences for the other threads. Since @{term th} is not |
|
1017 alive anymore in state @{term "s"}, there is no need to calculate its |
|
1018 current precedence. |
|
1019 \smallskip |
|
1020 *} |
|
1021 (*<*) |
|
1022 end |
|
1023 context step_set_cps |
|
1024 begin |
|
1025 (*>*) |
|
1026 text {* |
|
1027 \noindent |
|
1028 \colorbox{mygrey}{@{term "Set th prio"}:} We assume that @{text s'} and |
|
1029 @{term "s \<equiv> Set th prio#s'"} are both valid. We can show that |
|
1030 |
|
1031 \begin{isabelle}\ \ \ \ \ %%% |
|
1032 \begin{tabular}{@ {}l} |
|
1033 @{thm[mode=IfThen] eq_dep}, and\\ |
|
1034 @{thm[mode=IfThen] eq_cp} |
|
1035 \end{tabular} |
|
1036 \end{isabelle} |
|
1037 |
|
1038 \noindent |
|
1039 The first property is again telling us we do not need to change the @{text RAG}. The second |
|
1040 however states that only threads that are \emph{not} dependants of @{text th} have their |
|
1041 current precedence unchanged. For the others we have to recalculate the current |
|
1042 precedence. To do this we can start from @{term "th"} |
|
1043 and follow the @{term "depend"}-chains to recompute the @{term "cp"} of every |
|
1044 thread encountered on the way using Lemma~\ref{childrenlem}. Since the @{term "depend"} |
|
1045 is loop free, this procedure will always stop. The following two lemmas show, however, |
|
1046 that this procedure can actually stop often earlier without having to consider all |
|
1047 dependants. |
|
1048 |
|
1049 \begin{isabelle}\ \ \ \ \ %%% |
|
1050 \begin{tabular}{@ {}l} |
|
1051 @{thm[mode=IfThen] eq_up_self}\\ |
|
1052 @{text "If"} @{thm (prem 1) eq_up}, @{thm (prem 2) eq_up} and @{thm (prem 3) eq_up}\\ |
|
1053 @{text "then"} @{thm (concl) eq_up}. |
|
1054 \end{tabular} |
|
1055 \end{isabelle} |
|
1056 |
|
1057 \noindent |
|
1058 The first states that if the current precedence of @{text th} is unchanged, |
|
1059 then the procedure can stop immediately (all dependent threads have their @{term cp}-value unchanged). |
|
1060 The second states that if an intermediate @{term cp}-value does not change, then |
|
1061 the procedure can also stop, because none of its dependent threads will |
|
1062 have their current precedence changed. |
|
1063 \smallskip |
|
1064 *} |
|
1065 (*<*) |
|
1066 end |
|
1067 context step_v_cps_nt |
|
1068 begin |
|
1069 (*>*) |
|
1070 text {* |
|
1071 \noindent |
|
1072 \colorbox{mygrey}{@{term "V th cs"}:} We assume that @{text s'} and |
|
1073 @{term "s \<equiv> V th cs#s'"} are both valid. We have to consider two |
|
1074 subcases: one where there is a thread to ``take over'' the released |
|
1075 resource @{text cs}, and one where there is not. Let us consider them |
|
1076 in turn. Suppose in state @{text s}, the thread @{text th'} takes over |
|
1077 resource @{text cs} from thread @{text th}. We can show |
|
1078 |
|
1079 |
|
1080 \begin{isabelle}\ \ \ \ \ %%% |
|
1081 @{thm depend_s} |
|
1082 \end{isabelle} |
|
1083 |
|
1084 \noindent |
|
1085 which shows how the @{text RAG} needs to be changed. This also suggests |
|
1086 how the current precedences need to be recalculated. For threads that are |
|
1087 not @{text "th"} and @{text "th'"} nothing needs to be changed, since we |
|
1088 can show |
|
1089 |
|
1090 \begin{isabelle}\ \ \ \ \ %%% |
|
1091 @{thm[mode=IfThen] cp_kept} |
|
1092 \end{isabelle} |
|
1093 |
|
1094 \noindent |
|
1095 For @{text th} and @{text th'} we need to use Lemma~\ref{childrenlem} to |
|
1096 recalculate their current prcedence since their children have changed. *}(*<*)end context step_v_cps_nnt begin (*>*)text {* |
|
1097 \noindent |
|
1098 In the other case where there is no thread that takes over @{text cs}, we can show how |
|
1099 to recalculate the @{text RAG} and also show that no current precedence needs |
|
1100 to be recalculated. |
|
1101 |
|
1102 \begin{isabelle}\ \ \ \ \ %%% |
|
1103 \begin{tabular}{@ {}l} |
|
1104 @{thm depend_s}\\ |
|
1105 @{thm eq_cp} |
|
1106 \end{tabular} |
|
1107 \end{isabelle} |
|
1108 *} |
|
1109 (*<*) |
|
1110 end |
|
1111 context step_P_cps_e |
|
1112 begin |
|
1113 (*>*) |
|
1114 |
|
1115 text {* |
|
1116 \noindent |
|
1117 \colorbox{mygrey}{@{term "P th cs"}:} We assume that @{text s'} and |
|
1118 @{term "s \<equiv> P th cs#s'"} are both valid. We again have to analyse two subcases, namely |
|
1119 the one where @{text cs} is locked, and where it is not. We treat the second case |
|
1120 first by showing that |
|
1121 |
|
1122 \begin{isabelle}\ \ \ \ \ %%% |
|
1123 \begin{tabular}{@ {}l} |
|
1124 @{thm depend_s}\\ |
|
1125 @{thm eq_cp} |
|
1126 \end{tabular} |
|
1127 \end{isabelle} |
|
1128 |
|
1129 \noindent |
|
1130 This means we do not need to add a holding edge to the @{text RAG} and no |
|
1131 current precedence needs to be recalculated.*}(*<*)end context step_P_cps_ne begin(*>*) text {* |
|
1132 \noindent |
|
1133 In the second case we know that resouce @{text cs} is locked. We can show that |
|
1134 |
|
1135 \begin{isabelle}\ \ \ \ \ %%% |
|
1136 \begin{tabular}{@ {}l} |
|
1137 @{thm depend_s}\\ |
|
1138 @{thm[mode=IfThen] eq_cp} |
|
1139 \end{tabular} |
|
1140 \end{isabelle} |
|
1141 |
|
1142 \noindent |
|
1143 That means we have to add a waiting edge to the @{text RAG}. Furthermore |
|
1144 the current precedence for all threads that are not dependants of @{text th} |
|
1145 are unchanged. For the others we need to follow the edges |
|
1146 in the @{text RAG} and recompute the @{term "cp"}. However, like in the |
|
1147 @case of {text Set}, this operation can stop often earlier, namely when intermediate |
|
1148 values do not change. |
|
1149 *} |
|
1150 (*<*) |
1347 end |
1151 end |
1348 (*>*) |
1152 (*>*) |
|
1153 text {* |
|
1154 \noindent |
|
1155 A pleasing result of our formalisation is that the properties in |
|
1156 this section closely inform an implementation of PIP: Whether the |
|
1157 @{text RAG} needs to be reconfigured or current precedences need to |
|
1158 recalculated for an event is given by a lemma we proved. |
|
1159 *} |
|
1160 |
|
1161 section {* Conclusion *} |
|
1162 |
|
1163 text {* |
|
1164 The Priority Inheritance Protocol (PIP) is a classic textbook |
|
1165 algorithm used in real-time operating systems in order to avoid the problem of |
|
1166 Priority Inversion. Although classic and widely used, PIP does have |
|
1167 its faults: for example it does not prevent deadlocks in cases where threads |
|
1168 have circular lock dependencies. |
|
1169 |
|
1170 We had two goals in mind with our formalisation of PIP: One is to |
|
1171 make the notions in the correctness proof by Sha et al.~\cite{Sha90} |
|
1172 precise so that they can be processed by a theorem prover. The reason is |
|
1173 that a mechanically checked proof avoids the flaws that crept into their |
|
1174 informal reasoning. We achieved this goal: The correctness of PIP now |
|
1175 only hinges on the assumptions behind our formal model. The reasoning, which is |
|
1176 sometimes quite intricate and tedious, has been checked beyond any |
|
1177 reasonable doubt by Isabelle/HOL. We can also confirm that Paulson's |
|
1178 inductive method for protocol verification~\cite{Paulson98} is quite |
|
1179 suitable for our formal model and proof. The traditional application |
|
1180 area of this method is security protocols. The only other |
|
1181 application of Paulson's method we know of outside this area is |
|
1182 \cite{Wang09}. |
|
1183 |
|
1184 The second goal of our formalisation is to provide a specification for actually |
|
1185 implementing PIP. Textbooks, for example \cite[Section 5.6.5]{Vahalia96}, |
|
1186 explain how to use various implementations of PIP and abstractly |
|
1187 discuss their properties, but surprisingly lack most details for a |
|
1188 programmer who wants to implement PIP. That this is an issue in practice is illustrated by the |
|
1189 email from Baker we cited in the Introduction. We achieved also this |
|
1190 goal: The formalisation gives the first author enough data to enable |
|
1191 his undergraduate students to implement PIP (as part of their OS course) |
|
1192 on top of PINTOS, a small operating system for teaching |
|
1193 purposes. A byproduct of our formalisation effort is that nearly all |
|
1194 design choices for the PIP scheduler are backed up with a proved |
|
1195 lemma. We were also able to establish the property that the choice of |
|
1196 the next thread which takes over a lock is irrelevant for the correctness |
|
1197 of PIP. Earlier model checking approaches which verified implementations |
|
1198 of PIP \cite{Faria08,Jahier09,Wellings07} cannot |
|
1199 provide this kind of ``deep understanding'' about the principles behind |
|
1200 PIP and its correctness. |
|
1201 |
|
1202 PIP is a scheduling algorithm for single-processor systems. We are |
|
1203 now living in a multi-processor world. So the question naturally |
|
1204 arises whether PIP has any relevance in such a world beyond |
|
1205 teaching. Priority Inversion certainly occurs also in |
|
1206 multi-processor systems. However, the surprising answer, according |
|
1207 to \cite{Steinberg10}, is that except for one unsatisfactory |
|
1208 proposal nobody has a good idea for how PIP should be modified to |
|
1209 work correctly on multi-processor systems. The difficulties become |
|
1210 clear when considering that locking and releasing a resource always |
|
1211 requires a small amount of time. If processes work independently, |
|
1212 then a low priority process can ``steal'' in such an unguarded |
|
1213 moment a lock for a resource that was supposed allow a high-priority |
|
1214 process to run next. Thus the problem of Priority Inversion is not |
|
1215 really prevented. It seems difficult to design a PIP-algorithm with |
|
1216 a meaningful correctness property on a multi-processor systems where |
|
1217 processes work independently. We can imagine PIP to be of use in |
|
1218 situations where processes are \emph{not} independent, but |
|
1219 coordinated via a master process that distributes work over some |
|
1220 slave processes. However, a formal investigation of this is beyond |
|
1221 the scope of this paper. We are not aware of any proofs in this |
|
1222 area, not even informal ones. |
|
1223 |
|
1224 The most closely related work to ours is the formal verification in |
|
1225 PVS for Priority Ceiling done by Dutertre \cite{dutertre99b}. His formalisation |
|
1226 consists of 407 lemmas and 2500 lines of ``specification'' (we do not |
|
1227 know whether this includes also code for proofs). Our formalisation |
|
1228 consists of around 210 lemmas and overall 6950 lines of readable Isabelle/Isar |
|
1229 code with a few apply-scripts interspersed. The formal model of PIP |
|
1230 is 385 lines long; the formal correctness proof 3800 lines. Some auxiliary |
|
1231 definitions and proofs took 770 lines of code. The properties relevant |
|
1232 for an implementation took 2000 lines. Our code can be downloaded from |
|
1233 ... |
|
1234 |
|
1235 \bibliographystyle{plain} |
|
1236 \bibliography{root} |
|
1237 *} |
|
1238 |
|
1239 |
|
1240 (*<*) |
|
1241 end |
|
1242 (*>*) |