253 this choice would translate to a quite natural a FIFO-scheduling of processes with |
256 this choice would translate to a quite natural a FIFO-scheduling of processes with |
254 the same priority. |
257 the same priority. |
255 |
258 |
256 Next, we introduce the concept of \emph{waiting queues}. They are |
259 Next, we introduce the concept of \emph{waiting queues}. They are |
257 lists of threads associated with every resource. The first thread in |
260 lists of threads associated with every resource. The first thread in |
258 this list (the head, or short @{term hd}) is chosen to be in the one |
261 this list (the head, or short @{term hd}) is chosen to be the one |
259 that is in possession of the |
262 that is in possession of the |
260 ``lock'' of the corresponding resource. We model waiting queues as |
263 ``lock'' of the corresponding resource. We model waiting queues as |
261 functions, below abbreviated as @{text wq}, taking a resource as |
264 functions, below abbreviated as @{text wq}, taking a resource as |
262 argument and returning a list of threads. This allows us to define |
265 argument and returning a list of threads. This allows us to define |
263 when a thread \emph{holds}, respectively \emph{waits} for, a |
266 when a thread \emph{holds}, respectively \emph{waits} for, a |
310 This definition needs to account for all threads that wait for tread to |
330 This definition needs to account for all threads that wait for tread to |
311 release a resource. This means we need to include threads that transitively |
331 release a resource. This means we need to include threads that transitively |
312 wait for a resource being realeased (in the picture this means also @{text "th\<^isub>3"}, |
332 wait for a resource being realeased (in the picture this means also @{text "th\<^isub>3"}, |
313 which cannot make any progress unless @{text "th\<^isub>2"} makes progress which |
333 which cannot make any progress unless @{text "th\<^isub>2"} makes progress which |
314 in turn waits for @{text "th\<^isub>1"}). If there is a cirle in a RAG, then clearly |
334 in turn waits for @{text "th\<^isub>1"}). If there is a cirle in a RAG, then clearly |
315 we have a deadlock. Therefore when we state our correctness property for PIP |
335 we have a deadlock. Therefore when a thread requests a resource, |
316 we must ensure that RAGs are not circular. This allows us to define the notion |
336 we must ensure that the resulting RAG is not not circular. |
317 of the \emph{current precedence} of a thread @{text th} in a state @{text s}. |
337 |
318 |
338 Next we introduce the notion of \emph{current precedence} for a thread @{text th} in a |
319 \begin{isabelle}\ \ \ \ \ %%% |
339 state @{text s}, which is defined as |
320 @{thm cpreced_def2}\\ |
340 |
321 \end{isabelle} |
341 \begin{isabelle}\ \ \ \ \ %%% |
322 |
342 @{thm cpreced_def2} |
323 |
343 \end{isabelle} |
324 |
344 |
|
345 \noindent |
|
346 While the precedence of a thread is determined by the programmer (for example when the thread is |
|
347 created), the point of the current precedence is to let scheduler increase this |
|
348 priority, if needed according to PIP. Therefore the current precedence of @{text th} is |
|
349 given as the maximum of the precedence @{text th} has in state @{text s} \emph{and} all |
|
350 processes that are dependants of @{text th}. Since the notion @{term "dependents"} is |
|
351 defined as the transitive closure of all dependent threads, we deal correctly with the |
|
352 problem in the algorithm by Sha et al.~\cite{Sha90} where a priority of a thread is |
|
353 lowered prematurely. |
|
354 |
|
355 The next function, called @{term schs}, defines the behaviour of the scheduler. It is defined |
|
356 by recursion on the state (a list of events); @{term "schs"} takes a state as argument |
|
357 and returns a \emph{schedule state}, which we defined as a record consisting of ... |
|
358 |
|
359 In the initial state, the scheduler starts with all resources unlocked and the |
|
360 precedence of every thread is initialised with @{term "Prc 0 0"}. |
|
361 |
|
362 \begin{isabelle}\ \ \ \ \ %%% |
|
363 \begin{tabular}{@ {}l} |
|
364 @{thm (lhs) schs.simps(1)} @{text "\<equiv>"}\\ |
|
365 \hspace{5mm}@{term "(|waiting_queue = all_unlocked, cur_preced = (\<lambda>_::thread. Prc 0 0)|)"} |
|
366 \end{tabular} |
|
367 \end{isabelle} |
|
368 |
|
369 \noindent |
|
370 The cases for @{term Create}, @{term Exit} and @{term Set} are straightforward: |
|
371 we calculuate the waiting queue function of the (previous) state @{text s}; |
|
372 this waiting queue function @{text wq} is unchanged in the next schedule state; for calculuating |
|
373 the next @{term "cprec_fun"} we use @{text wq} and the function @{term cpreced}. |
|
374 This gives the following clauses: |
|
375 |
|
376 \begin{isabelle}\ \ \ \ \ %%% |
|
377 \begin{tabular}{@ {}l} |
|
378 @{thm (lhs) schs.simps(2)} @{text "\<equiv>"}\\ |
|
379 \hspace{5mm}@{text "let"} @{text "wq = waiting_queue (schs s)"} @{text "in"}\\ |
|
380 \hspace{8mm}@{term "(|waiting_queue = wq\<iota>, cur_preced = cpreced wq\<iota> (Create th prio # s)|)"}\\ |
|
381 @{thm (lhs) schs.simps(3)} @{text "\<equiv>"}\\ |
|
382 \hspace{5mm}@{text "let"} @{text "wq = waiting_queue (schs s)"} @{text "in"}\\ |
|
383 \hspace{8mm}@{term "(|waiting_queue = wq\<iota>, cur_preced = cpreced wq\<iota> (Exit th # s)|)"}\smallskip\\ |
|
384 @{thm (lhs) schs.simps(4)} @{text "\<equiv>"}\\ |
|
385 \hspace{5mm}@{text "let"} @{text "wq = waiting_queue (schs s)"} @{text "in"}\\ |
|
386 \hspace{8mm}@{term "(|waiting_queue = wq\<iota>, cur_preced = cpreced wq\<iota> (Set th prio # s)|)"} |
|
387 \end{tabular} |
|
388 \end{isabelle} |
|
389 |
|
390 \noindent |
|
391 More interesting are the cases when a resource, say @{text cs}, is locked or relaesed. In this case |
|
392 we need to calculate a new waiting queue function. In case of @{term P} we update |
|
393 the function so that the new thread list for @{text cs} is old thread list with the waiting |
|
394 thread appended to the end (remember the head of this list is in the possession of the |
|
395 resource). |
|
396 |
|
397 \begin{isabelle}\ \ \ \ \ %%% |
|
398 \begin{tabular}{@ {}l} |
|
399 @{thm (lhs) schs.simps(5)} @{text "\<equiv>"}\\ |
|
400 \hspace{5mm}@{text "let"} @{text "wq = waiting_queue (schs s)"} @{text "in"}\\ |
|
401 \hspace{5mm}@{text "let"} @{text "new_wq = wq(cs := (wq cs @ [th]))"} @{text "in"}\\ |
|
402 \hspace{8mm}@{term "(|waiting_queue = new_wq, cur_preced = cpreced new_wq (P th cs # s)|)"} |
|
403 \end{tabular} |
|
404 \end{isabelle} |
|
405 |
|
406 \noindent |
|
407 The case for @{term V} is similarly, except that we update the waiting queue function |
|
408 using the auxiliary definition |
|
409 |
|
410 \begin{isabelle}\ \ \ \ \ %%% |
|
411 @{abbrev release} |
|
412 \end{isabelle} |
|
413 |
|
414 \noindent |
|
415 This gives for @{term schs} the clause: |
|
416 |
|
417 \begin{isabelle}\ \ \ \ \ %%% |
|
418 \begin{tabular}{@ {}l} |
|
419 @{thm (lhs) schs.simps(6)} @{text "\<equiv>"}\\ |
|
420 \hspace{5mm}@{text "let"} @{text "wq = waiting_queue (schs s)"} @{text "in"}\\ |
|
421 \hspace{5mm}@{text "let"} @{text "new_wq = release (wq cs)"} @{text "in"}\\ |
|
422 \hspace{8mm}@{term "(|waiting_queue = new_wq, cur_preced = cpreced new_wq (V th cs # s)|)"} |
|
423 \end{tabular} |
|
424 \end{isabelle} |
|
425 |
|
426 |
|
427 TODO |
325 |
428 |
326 \begin{isabelle}\ \ \ \ \ %%% |
429 \begin{isabelle}\ \ \ \ \ %%% |
327 \begin{tabular}{@ {}l} |
430 \begin{tabular}{@ {}l} |
328 @{thm s_depend_def}\\ |
431 @{thm s_depend_def}\\ |
329 \end{tabular} |
432 \end{tabular} |