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 |
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"}\\ |