prio/Paper/Paper.thy
changeset 296 2c8dcf010567
parent 294 bc5bf9e9ada2
child 297 0a4be67ea7f8
equal deleted inserted replaced
295:8e4a5fff2eda 296:2c8dcf010567
   246 
   246 
   247   \noindent
   247   \noindent
   248   The point of precedences is to schedule threads not according to priorities (because what should
   248   The point of precedences is to schedule threads not according to priorities (because what should
   249   we do in case two threads have the same priority), but according to precedences. 
   249   we do in case two threads have the same priority), but according to precedences. 
   250   Precedences allow us to always discriminate between two threads with equal priority by 
   250   Precedences allow us to always discriminate between two threads with equal priority by 
   251   tacking into account the time when the priority was last set. We order precedences so 
   251   taking into account the time when the priority was last set. We order precedences so 
   252   that threads with the same priority get a higher precedence if their priority has been 
   252   that threads with the same priority get a higher precedence if their priority has been 
   253   set earlier, since for such threads it is more urgent to finish their work. In an implementation
   253   set earlier, since for such threads it is more urgent to finish their work. In an implementation
   254   this choice would translate to a quite natural FIFO-scheduling of processes with 
   254   this choice would translate to a quite natural FIFO-scheduling of processes with 
   255   the same priority.
   255   the same priority.
   256 
   256 
   272   \end{isabelle}
   272   \end{isabelle}
   273 
   273 
   274   \noindent
   274   \noindent
   275   In this definition we assume @{text "set"} converts a list into a set.
   275   In this definition we assume @{text "set"} converts a list into a set.
   276   At the beginning, that is in the state where no process is created yet, 
   276   At the beginning, that is in the state where no process is created yet, 
   277   the waiting queue function will be just the function that returns the
   277   the waiting queue function will be the function that just returns the
   278   empty list for every resource.
   278   empty list for every resource.
   279 
   279 
   280   \begin{isabelle}\ \ \ \ \ %%%
   280   \begin{isabelle}\ \ \ \ \ %%%
   281   @{abbrev all_unlocked}
   281   @{abbrev all_unlocked}
   282   \end{isabelle}
   282   \end{isabelle}
   315   \draw (3.3,0.3) node {\small$th_1$};
   315   \draw (3.3,0.3) node {\small$th_1$};
   316   \end{tikzpicture}
   316   \end{tikzpicture}
   317   \end{center}
   317   \end{center}
   318 
   318 
   319   \noindent
   319   \noindent
   320   The use or relations for representing RAGs allows us to conveninetly define
   320   The use of relations for representing RAGs allows us to conveniently define
   321   the notion of the \emph{dependants} of a thread. This is defined as
   321   the notion of the \emph{dependants} of a thread. This is defined as
   322 
   322 
   323   \begin{isabelle}\ \ \ \ \ %%%
   323   \begin{isabelle}\ \ \ \ \ %%%
   324   @{thm cs_dependents_def}
   324   @{thm cs_dependents_def}
   325   \end{isabelle}
   325   \end{isabelle}
   326 
   326 
   327   \noindent
   327   \noindent
   328   This definition needs to account for all threads that wait for a tread to
   328   This definition needs to account for all threads that wait for a thread to
   329   release a resource. This means we need to include threads that transitively
   329   release a resource. This means we need to include threads that transitively
   330   wait for a resource being realeased (in the picture above this means also @{text "th\<^isub>3"}, 
   330   wait for a resource being released (in the picture above this means also @{text "th\<^isub>3"}, 
   331   which cannot make any progress unless @{text "th\<^isub>2"} makes progress which
   331   which cannot make any progress unless @{text "th\<^isub>2"} makes progress which
   332   in turn needs to wait for @{text "th\<^isub>1"}). If there is a cirle in a RAG, then clearly
   332   in turn needs to wait for @{text "th\<^isub>1"}). If there is a circle in a RAG, then clearly
   333   we have a deadlock. Therefore when a thread requests a resource,
   333   we have a deadlock. Therefore when a thread requests a resource,
   334   we must ensure that the resulting RAG is not not circular. 
   334   we must ensure that the resulting RAG is not not circular. 
   335 
   335 
   336   Next we introduce the notion of the \emph{current precedence} for a thread @{text th} in a 
   336   Next we introduce the notion of the \emph{current precedence} for a thread @{text th} in a 
   337   state @{text s}, which is defined as
   337   state @{text s}, which is defined as
   344   While the precedence @{term prec} of a thread is determined by the programmer 
   344   While the precedence @{term prec} of a thread is determined by the programmer 
   345   (for example when the thread is
   345   (for example when the thread is
   346   created), the point of the current precedence is to let scheduler increase this
   346   created), the point of the current precedence is to let scheduler increase this
   347   priority, if needed according to PIP. Therefore the current precedence of @{text th} is
   347   priority, if needed according to PIP. Therefore the current precedence of @{text th} is
   348   given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all 
   348   given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all 
   349   processes that are dependants of @{text th}. Since the notion @{term "dependents"} is
   349   processes that are dependants of @{text th}. Since the notion @{term "dependants"} is
   350   defined as the transitive closure of all dependent threads, we deal correctly with the 
   350   defined as the transitive closure of all dependent threads, we deal correctly with the 
   351   problem in the algorithm by Sha et al.~\cite{Sha90} where a priority of a thread is
   351   problem in the algorithm by Sha et al.~\cite{Sha90} where a priority of a thread is
   352   lowered prematurely.
   352   lowered prematurely.
   353   
   353   
   354   The next function, called @{term schs}, defines the behaviour of the scheduler. It is defined
   354   The next function, called @{term schs}, defines the behaviour of the scheduler. It is defined
   355   by recursion on the state (a list of events); @{term "schs"} takes a state as argument
   355   by recursion on the state (a list of events); @{term "schs"} takes a state as argument
   356   and returns a \emph{schedule state}, which we define as a record consisting of two
   356   and returns a \emph{schedule state}, which we define as a record consisting of two
   357   functions
   357   functions:
   358 
   358 
   359   \begin{isabelle}\ \ \ \ \ %%%
   359   \begin{isabelle}\ \ \ \ \ %%%
   360   @{text "\<lparr>wq_fun, cprec_fun\<rparr>"}
   360   @{text "\<lparr>wq_fun, cprec_fun\<rparr>"}
   361   \end{isabelle}
   361   \end{isabelle}
   362 
   362 
   363   \noindent
   363   \noindent
   364   We have the usual getter and setter methods for such records.
   364   The first is a waiting queue function (that is takes a @{text "cs"} and returns the
       
   365   corresponding list of threads that wait for it), the second is a function that takes
       
   366   a thread and returns its current precedence (see ???). We have the usual getter and 
       
   367   setter methods for such records.
   365 
   368 
   366   In the initial state, the scheduler starts with all resources unlocked and the
   369   In the initial state, the scheduler starts with all resources unlocked and the
   367   precedence of every thread is initialised with @{term "Prc 0 0"}. 
   370   precedence of every thread is initialised with @{term "Prc 0 0"}. Therefore
       
   371   we have
   368 
   372 
   369   \begin{isabelle}\ \ \ \ \ %%%
   373   \begin{isabelle}\ \ \ \ \ %%%
   370   \begin{tabular}{@ {}l}
   374   \begin{tabular}{@ {}l}
   371   @{thm (lhs) schs.simps(1)} @{text "\<equiv>"}\\ 
   375   @{thm (lhs) schs.simps(1)} @{text "\<equiv>"}\\ 
   372   \hspace{5mm}@{term "(|wq_fun = all_unlocked, cprec_fun = (\<lambda>_::thread. Prc 0 0)|)"}
   376   \hspace{5mm}@{term "(|wq_fun = all_unlocked, cprec_fun = (\<lambda>_::thread. Prc 0 0)|)"}
   373   \end{tabular}
   377   \end{tabular}
   374   \end{isabelle}
   378   \end{isabelle}
   375 
   379 
   376   \noindent
   380   \noindent
   377   The cases for @{term Create}, @{term Exit} and @{term Set} are straightforward:
   381   The cases for @{term Create}, @{term Exit} and @{term Set} are also straightforward:
   378   we calculuate the waiting queue function of the (previous) state @{text s}; 
   382   we calculate the waiting queue function of the (previous) state @{text s}; 
   379   this waiting queue function @{text wq} is unchanged in the next schedule state; for calculuating 
   383   this waiting queue function @{text wq} is unchanged in the next schedule state; 
   380   the next @{term "cprec_fun"} we use @{text wq} and the function @{term cpreced}. 
   384   for calculating the next @{term "cprec_fun"}, we use @{text wq} and the function 
   381   This gives the following clauses:
   385   @{term cpreced}. This gives the following three clauses:
   382 
   386 
   383   \begin{isabelle}\ \ \ \ \ %%%
   387   \begin{isabelle}\ \ \ \ \ %%%
   384   \begin{tabular}{@ {}l}
   388   \begin{tabular}{@ {}l}
   385   @{thm (lhs) schs.simps(2)} @{text "\<equiv>"}\\ 
   389   @{thm (lhs) schs.simps(2)} @{text "\<equiv>"}\\ 
   386   \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\
   390   \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\
   393   \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"}
   397   \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"}
   394   \end{tabular}
   398   \end{tabular}
   395   \end{isabelle}
   399   \end{isabelle}
   396 
   400 
   397   \noindent 
   401   \noindent 
   398   More interesting are the cases when a resource, say @{text cs}, is locked or relaesed. In this case
   402   More interesting are the cases when a resource, say @{text cs}, is locked or released. In this case
   399   we need to calculate a new waiting queue function. In case of @{term P} we update
   403   we need to calculate a new waiting queue function. In case of @{term P}, we update
   400   the function so that the new thread list for @{text cs} is old thread list with the waiting 
   404   the function so that the new thread list for @{text cs} is old thread list plus the thread @{text th} 
   401   thread appended to the end (remember the head of this list is in the possession of the
   405   appended to the end (remember the head of this list is in the possession of the
   402   resource).
   406   resource).
   403 
   407 
   404   \begin{isabelle}\ \ \ \ \ %%%
   408   \begin{isabelle}\ \ \ \ \ %%%
   405   \begin{tabular}{@ {}l}
   409   \begin{tabular}{@ {}l}
   406   @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ 
   410   @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ 
   409   \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (P th cs # s)|)"}
   413   \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (P th cs # s)|)"}
   410   \end{tabular}
   414   \end{tabular}
   411   \end{isabelle}
   415   \end{isabelle}
   412 
   416 
   413   \noindent
   417   \noindent
   414   The case for @{term V} is similarly, except that we update the waiting queue function
   418   The case for @{term V} is similar, except that we need to update the waiting queue function
   415   using the auxiliary definition
   419   so that the thread that possessed the lock is eliminated. For this we use
   416 
   420   the auxiliary function @{term release}. A simple version of @{term release} would
   417   \begin{isabelle}\ \ \ \ \ %%%
   421   just delete this thread and return the rest like so
   418   @{abbrev release}
   422 
   419   \end{isabelle}
   423   \begin{isabelle}\ \ \ \ \ %%%
   420 
   424   \begin{tabular}{@ {}lcl}
   421   \noindent
   425   @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\
   422   This gives for @{term schs} the clause:
   426   @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "qs"}\\
       
   427   \end{tabular}
       
   428   \end{isabelle}
       
   429 
       
   430   \noindent
       
   431   However in practice often the thread with the highest precedence will get the
       
   432   lock next. We have implemented this choice, but later found out that the choice 
       
   433   about which thread is chosen next is actually irrelevant for the correctness of PIP.
       
   434   Therefore we prove the stronger result where @{term release} is defined as
       
   435 
       
   436   \begin{isabelle}\ \ \ \ \ %%%
       
   437   \begin{tabular}{@ {}lcl}
       
   438   @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\
       
   439   @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "SOME qs'. distinct qs' \<and> set qs' = set qs"}\\
       
   440   \end{tabular}
       
   441   \end{isabelle}
       
   442 
       
   443   \noindent
       
   444   @{text "SOME"} stands for Hilbert's epsilon and implements an arbitrary
       
   445   choice for the next waiting list, it just has to be a distinct list and
       
   446   contain the same elements as @{text "qs"}. This gives for @{term V} and @{term schs} the clause:
   423  
   447  
   424   \begin{isabelle}\ \ \ \ \ %%%
   448   \begin{isabelle}\ \ \ \ \ %%%
   425   \begin{tabular}{@ {}l}
   449   \begin{tabular}{@ {}l}
   426   @{thm (lhs) schs.simps(6)} @{text "\<equiv>"}\\
   450   @{thm (lhs) schs.simps(6)} @{text "\<equiv>"}\\
   427   \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\
   451   \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\