301 |
301 |
302 \noindent |
302 \noindent |
303 where the first stands for a \emph{waiting edge} and the second for a |
303 where the first stands for a \emph{waiting edge} and the second for a |
304 \emph{holding edge} (@{term Cs} and @{term Th} are constructors of a |
304 \emph{holding edge} (@{term Cs} and @{term Th} are constructors of a |
305 datatype for vertices). Given a waiting queue function, a RAG is defined |
305 datatype for vertices). Given a waiting queue function, a RAG is defined |
306 as |
306 as the union of the sets of waiting and holding edges, namely |
307 |
307 |
308 \begin{isabelle}\ \ \ \ \ %%% |
308 \begin{isabelle}\ \ \ \ \ %%% |
309 @{thm cs_depend_def} |
309 @{thm cs_depend_def} |
310 \end{isabelle} |
310 \end{isabelle} |
311 |
311 |
312 \noindent |
312 \noindent |
313 Given three threads and three resources, an instance of a RAG is as follows: |
313 Given three threads and three resources, an instance of a RAG can be pictured |
|
314 as follows: |
314 |
315 |
315 \begin{center} |
316 \begin{center} |
316 \newcommand{\fnt}{\fontsize{7}{8}\selectfont} |
317 \newcommand{\fnt}{\fontsize{7}{8}\selectfont} |
317 \begin{tikzpicture}[scale=1] |
318 \begin{tikzpicture}[scale=1] |
318 %%\draw[step=2mm] (-3,2) grid (1,-1); |
319 %%\draw[step=2mm] (-3,2) grid (1,-1); |
334 \end{tikzpicture} |
335 \end{tikzpicture} |
335 \end{center} |
336 \end{center} |
336 |
337 |
337 \noindent |
338 \noindent |
338 The use of relations for representing RAGs allows us to conveniently define |
339 The use of relations for representing RAGs allows us to conveniently define |
339 the notion of the \emph{dependants} of a thread. This is defined as |
340 the notion of the \emph{dependants} of a thread using the transitive closure |
|
341 operation for relations. This gives |
340 |
342 |
341 \begin{isabelle}\ \ \ \ \ %%% |
343 \begin{isabelle}\ \ \ \ \ %%% |
342 @{thm cs_dependents_def} |
344 @{thm cs_dependents_def} |
343 \end{isabelle} |
345 \end{isabelle} |
344 |
346 |
345 \noindent |
347 \noindent |
346 This definition needs to account for all threads that wait for a thread to |
348 This definition needs to account for all threads that wait for a thread to |
347 release a resource. This means we need to include threads that transitively |
349 release a resource. This means we need to include threads that transitively |
348 wait for a resource being released (in the picture above this means the dependants |
350 wait for a resource being released (in the picture above this means the dependants |
349 of @{text "th\<^isub>0"} are @{text "th\<^isub>1"} and @{text "th\<^isub>2"}, but also @{text "th\<^isub>3"}, |
351 of @{text "th\<^isub>0"} are @{text "th\<^isub>1"} and @{text "th\<^isub>2"}, which wait for resource @{text "cs\<^isub>1"}, |
|
352 but also @{text "th\<^isub>3"}, |
350 which cannot make any progress unless @{text "th\<^isub>2"} makes progress, which |
353 which cannot make any progress unless @{text "th\<^isub>2"} makes progress, which |
351 in turn needs to wait for @{text "th\<^isub>1"} to finish). If there is a circle in a RAG, then clearly |
354 in turn needs to wait for @{text "th\<^isub>0"} to finish). If there is a circle in a RAG, then clearly |
352 we have a deadlock. Therefore when a thread requests a resource, |
355 we have a deadlock. Therefore when a thread requests a resource, |
353 we must ensure that the resulting RAG is not circular. |
356 we must ensure that the resulting RAG is not circular. |
354 |
357 |
355 Next we introduce the notion of the \emph{current precedence} of a thread @{text th} in a |
358 Next we introduce the notion of the \emph{current precedence} of a thread @{text th} in a |
356 state @{text s}. It is defined as |
359 state @{text s}. It is defined as |
358 \begin{isabelle}\ \ \ \ \ %%% |
361 \begin{isabelle}\ \ \ \ \ %%% |
359 @{thm cpreced_def2}\hfill\numbered{cpreced} |
362 @{thm cpreced_def2}\hfill\numbered{cpreced} |
360 \end{isabelle} |
363 \end{isabelle} |
361 |
364 |
362 \noindent |
365 \noindent |
|
366 where the dependants of @{text th} are given by the waiting queue function. |
363 While the precedence @{term prec} of a thread is determined by the programmer |
367 While the precedence @{term prec} of a thread is determined by the programmer |
364 (for example when the thread is |
368 (for example when the thread is |
365 created), the point of the current precedence is to let scheduler increase this |
369 created), the point of the current precedence is to let the scheduler increase this |
366 priority, if needed according to PIP. Therefore the current precedence of @{text th} is |
370 precedence, if needed according to PIP. Therefore the current precedence of @{text th} is |
367 given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all |
371 given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all |
368 processes that are dependants of @{text th}. Since the notion @{term "dependants"} is |
372 threads that are dependants of @{text th}. Since the notion @{term "dependants"} is |
369 defined as the transitive closure of all dependent threads, we deal correctly with the |
373 defined as the transitive closure of all dependent threads, we deal correctly with the |
370 problem in the algorithm by Sha et al.~\cite{Sha90} where a priority of a thread is |
374 problem in the informal algorithm by Sha et al.~\cite{Sha90} where a priority of a thread is |
371 lowered prematurely. |
375 lowered prematurely. |
372 |
376 |
373 The next function, called @{term schs}, defines the behaviour of the scheduler. It will be defined |
377 The next function, called @{term schs}, defines the behaviour of the scheduler. It will be defined |
374 by recursion on the state (a list of events); @{term "schs"} returns a \emph{schedule state}, which |
378 by recursion on the state (a list of events); this function returns a \emph{schedule state}, which |
375 we represent as a record consisting of two |
379 we represent as a record consisting of two |
376 functions: |
380 functions: |
377 |
381 |
378 \begin{isabelle}\ \ \ \ \ %%% |
382 \begin{isabelle}\ \ \ \ \ %%% |
379 @{text "\<lparr>wq_fun, cprec_fun\<rparr>"} |
383 @{text "\<lparr>wq_fun, cprec_fun\<rparr>"} |
380 \end{isabelle} |
384 \end{isabelle} |
381 |
385 |
382 \noindent |
386 \noindent |
383 The first function is a waiting queue function (that is it takes a resource @{text "cs"} and returns the |
387 The first function is a waiting queue function (that is, it takes a resource @{text "cs"} and returns the |
384 corresponding list of threads that wait for it), the second is a function that takes |
388 corresponding list of threads that wait for it), the second is a function that takes |
385 a thread and returns its current precedence (see \eqref{cpreced}). We assume the usual getter and |
389 a thread and returns its current precedence (see \eqref{cpreced}). We assume the usual getter and |
386 setter methods for such records. |
390 setter methods for such records. |
387 |
391 |
388 In the initial state, the scheduler starts with all resources unlocked (see \eqref{allunlocked}) and the |
392 In the initial state, the scheduler starts with all resources unlocked (the corresponding |
|
393 function is defined in \eqref{allunlocked}) and the |
389 current precedence of every thread is initialised with @{term "Prc 0 0"}; that means |
394 current precedence of every thread is initialised with @{term "Prc 0 0"}; that means |
390 \mbox{@{abbrev initial_cprec}}. Therefore |
395 \mbox{@{abbrev initial_cprec}}. Therefore |
391 we have |
396 we have for the initial state |
392 |
397 |
393 \begin{isabelle}\ \ \ \ \ %%% |
398 \begin{isabelle}\ \ \ \ \ %%% |
394 \begin{tabular}{@ {}l} |
399 \begin{tabular}{@ {}l} |
395 @{thm (lhs) schs.simps(1)} @{text "\<equiv>"}\\ |
400 @{thm (lhs) schs.simps(1)} @{text "\<equiv>"}\\ |
396 \hspace{5mm}@{term "(|wq_fun = all_unlocked, cprec_fun = (\<lambda>_::thread. Prc 0 0)|)"} |
401 \hspace{5mm}@{term "(|wq_fun = all_unlocked, cprec_fun = (\<lambda>_::thread. Prc 0 0)|)"} |
399 |
404 |
400 \noindent |
405 \noindent |
401 The cases for @{term Create}, @{term Exit} and @{term Set} are also straightforward: |
406 The cases for @{term Create}, @{term Exit} and @{term Set} are also straightforward: |
402 we calculate the waiting queue function of the (previous) state @{text s}; |
407 we calculate the waiting queue function of the (previous) state @{text s}; |
403 this waiting queue function @{text wq} is unchanged in the next schedule state---because |
408 this waiting queue function @{text wq} is unchanged in the next schedule state---because |
404 none of these events lock or release any resources; |
409 none of these events lock or release any resource; |
405 for calculating the next @{term "cprec_fun"}, we use @{text wq} and the function |
410 for calculating the next @{term "cprec_fun"}, we use @{text wq} and |
406 @{term cpreced}. This gives the following three clauses for @{term schs}: |
411 @{term cpreced}. This gives the following three clauses for @{term schs}: |
407 |
412 |
408 \begin{isabelle}\ \ \ \ \ %%% |
413 \begin{isabelle}\ \ \ \ \ %%% |
409 \begin{tabular}{@ {}l} |
414 \begin{tabular}{@ {}l} |
410 @{thm (lhs) schs.simps(2)} @{text "\<equiv>"}\\ |
415 @{thm (lhs) schs.simps(2)} @{text "\<equiv>"}\\ |
418 \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"} |
423 \hspace{8mm}@{term "(|wq_fun = wq\<iota>, cprec_fun = cpreced wq\<iota> (Set th prio # s)|)"} |
419 \end{tabular} |
424 \end{tabular} |
420 \end{isabelle} |
425 \end{isabelle} |
421 |
426 |
422 \noindent |
427 \noindent |
423 More interesting are the cases when a resource, say @{text cs}, is locked or released. In these cases |
428 More interesting are the cases where a resource, say @{text cs}, is locked or released. In these cases |
424 we need to calculate a new waiting queue function. For the event @{term "P th cs"}, we have to update |
429 we need to calculate a new waiting queue function. For the event @{term "P th cs"}, we have to update |
425 the function so that the new thread list for @{text cs} is old thread list plus the thread @{text th} |
430 the function so that the new thread list for @{text cs} is the old thread list plus the thread @{text th} |
426 appended to the end of that list (remember the head of this list is seen to be in the possession of this |
431 appended to the end of that list (remember the head of this list is seen to be in the possession of this |
427 resource). |
432 resource). This gives the clause |
428 |
433 |
429 \begin{isabelle}\ \ \ \ \ %%% |
434 \begin{isabelle}\ \ \ \ \ %%% |
430 \begin{tabular}{@ {}l} |
435 \begin{tabular}{@ {}l} |
431 @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ |
436 @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ |
432 \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\ |
437 \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\ |
438 \noindent |
443 \noindent |
439 The clause for event @{term "V th cs"} is similar, except that we need to update the waiting queue function |
444 The clause for event @{term "V th cs"} is similar, except that we need to update the waiting queue function |
440 so that the thread that possessed the lock is deleted from the corresponding thread list. For this |
445 so that the thread that possessed the lock is deleted from the corresponding thread list. For this |
441 list transformation, we use |
446 list transformation, we use |
442 the auxiliary function @{term release}. A simple version of @{term release} would |
447 the auxiliary function @{term release}. A simple version of @{term release} would |
443 just delete this thread and return the rest, namely |
448 just delete this thread and return the remaining threads, namely |
444 |
449 |
445 \begin{isabelle}\ \ \ \ \ %%% |
450 \begin{isabelle}\ \ \ \ \ %%% |
446 \begin{tabular}{@ {}lcl} |
451 \begin{tabular}{@ {}lcl} |
447 @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\ |
452 @{term "release []"} & @{text "\<equiv>"} & @{term "[]"}\\ |
448 @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "qs"}\\ |
453 @{term "release (DUMMY # qs)"} & @{text "\<equiv>"} & @{term "qs"}\\ |
500 @{thm runing_def}\\ |
505 @{thm runing_def}\\ |
501 \end{tabular} |
506 \end{tabular} |
502 \end{isabelle} |
507 \end{isabelle} |
503 |
508 |
504 \noindent |
509 \noindent |
505 In this definition @{term "f ` S"} stands for the set @{text S} under the image of the |
510 In this definition @{term "DUMMY ` DUMMY"} stands for the image of a set under a function. |
506 function @{text f}. |
511 Note that in the initial state, that is where the list of events is empty, the set |
507 Note that in the initial case, that is where the list of events is empty, the set |
|
508 @{term threads} is empty and therefore there is no thread ready nor a running. |
512 @{term threads} is empty and therefore there is no thread ready nor a running. |
509 If there is one or more threads ready, then there can only be \emph{one} thread |
513 If there is one or more threads ready, then there can only be \emph{one} thread |
510 running, namely the one whose current precedence is equal to the maximum of all ready |
514 running, namely the one whose current precedence is equal to the maximum of all ready |
511 threads. We use the set-comprehension to capture both possibilities. |
515 threads. We use the set-comprehension to capture both possibilities. |
512 We can now also define the set of resources that are locked by a thread in any |
516 We can now also conveniently define the set of resources that are locked by a thread in a |
513 given state. |
517 given state. |
514 |
518 |
515 \begin{isabelle}\ \ \ \ \ %%% |
519 \begin{isabelle}\ \ \ \ \ %%% |
516 @{thm holdents_def} |
520 @{thm holdents_def} |
517 \end{isabelle} |
521 \end{isabelle} |
518 |
522 |
519 \noindent |
523 Finally we can define what a \emph{valid state} is in our model of PIP. For |
520 These resources are given by the holding edges in the RAG. |
|
521 |
|
522 Finally we can define what a \emph{valid state} is in our PIP. For |
|
523 example we cannot expect to be able to exit a thread, if it was not |
524 example we cannot expect to be able to exit a thread, if it was not |
524 created yet. These validity constraints are characterised by the |
525 created yet. These validity constraints on states are characterised by the |
525 inductive predicate @{term "step"}. We give five inference rules |
526 inductive predicate @{term "step"} and @{term vt}. We first give five inference rules |
526 relating a state and an event that can happen next. |
527 for @{term step} relating a state and an event that can happen next. |
527 |
528 |
528 \begin{center} |
529 \begin{center} |
529 \begin{tabular}{c} |
530 \begin{tabular}{c} |
530 @{thm[mode=Rule] thread_create[where thread=th]}\hspace{1cm} |
531 @{thm[mode=Rule] thread_create[where thread=th]}\hspace{1cm} |
531 @{thm[mode=Rule] thread_exit[where thread=th]} |
532 @{thm[mode=Rule] thread_exit[where thread=th]} |
533 \end{center} |
534 \end{center} |
534 |
535 |
535 \noindent |
536 \noindent |
536 The first rule states that a thread can only be created, if it does not yet exists. |
537 The first rule states that a thread can only be created, if it does not yet exists. |
537 Similarly, the second rule states that a thread can only be terminated if it was |
538 Similarly, the second rule states that a thread can only be terminated if it was |
538 running and does not lock any resources anymore (to simplify ). The event @{text Set} can happen |
539 running and does not lock any resources anymore (this simplifies slightly our model; |
|
540 in practice we would expect the operating system releases all held lock of a |
|
541 thread that is about to exit). The event @{text Set} can happen |
539 if the corresponding thread is running. |
542 if the corresponding thread is running. |
540 |
543 |
541 \begin{center} |
544 \begin{center} |
542 @{thm[mode=Rule] thread_set[where thread=th]} |
545 @{thm[mode=Rule] thread_set[where thread=th]} |
543 \end{center} |
546 \end{center} |
544 |
547 |
545 \noindent |
548 \noindent |
546 If a thread wants to lock a resource, then the thread needs to be |
549 If a thread wants to lock a resource, then the thread needs to be |
547 running and also we have to make sure that the resource lock does |
550 running and also we have to make sure that the resource lock does |
548 not lead to a cycle in the RAG. In practice, ensuring the latter is |
551 not lead to a cycle in the RAG. In practice, ensuring the latter is |
549 of course the responsibility of the programmer. Here in our formal |
552 of course the responsibility of the programmer. In our formal |
550 model we just exclude such problematic cases in order to make |
553 model we just exclude such problematic cases in order to make |
551 some meaningful statements about PIP.\footnote{This situation is |
554 some meaningful statements about PIP.\footnote{This situation is |
552 similar to the infamous occurs check in Prolog: in order to say |
555 similar to the infamous occurs check in Prolog: in order to say |
553 anything meaningful about unification, we need to perform an occurs |
556 anything meaningful about unification, one needs to perform an occurs |
554 check; but in practice the occurs check is ommited and the |
557 check, but in practice the occurs check is ommited and the |
555 responsibility to avoid problems rests with the programmer.} |
558 responsibility for avoiding problems rests with the programmer.} |
|
559 |
|
560 \begin{center} |
|
561 @{thm[mode=Rule] thread_P[where thread=th]} |
|
562 \end{center} |
|
563 |
|
564 \noindent |
556 Similarly, if a thread wants to release a lock on a resource, then |
565 Similarly, if a thread wants to release a lock on a resource, then |
557 it must be running and in the possession of that lock. This is |
566 it must be running and in the possession of that lock. This is |
558 formally given by the last two inference rules of @{term step}. |
567 formally given by the last inference rule of @{term step}. |
559 |
568 |
560 \begin{center} |
569 \begin{center} |
561 \begin{tabular}{c} |
570 @{thm[mode=Rule] thread_V[where thread=th]} |
562 @{thm[mode=Rule] thread_P[where thread=th]}\medskip\\ |
|
563 @{thm[mode=Rule] thread_V[where thread=th]}\\ |
|
564 \end{tabular} |
|
565 \end{center} |
571 \end{center} |
566 |
572 |
567 \noindent |
573 \noindent |
568 A valid state of PIP can then be conveniently be defined as follows: |
574 A valid state of PIP can then be conveniently be defined as follows: |
569 |
575 |
570 \begin{center} |
576 \begin{center} |
571 \begin{tabular}{c} |
577 \begin{tabular}{c} |