300 \end{tabular} |
300 \end{tabular} |
301 \end{isabelle} |
301 \end{isabelle} |
302 |
302 |
303 \noindent |
303 \noindent |
304 In this definition we assume @{text "set"} converts a list into a set. |
304 In this definition we assume @{text "set"} converts a list into a set. |
|
305 Note that in the first definition the condition about @{text "th \<in> set (wq cs)"} does not follow |
|
306 from @{text "th = hd (set (wq cs))"}, since the head of an empty list is undefined in Isabelle/HOL. |
305 At the beginning, that is in the state where no thread is created yet, |
307 At the beginning, that is in the state where no thread is created yet, |
306 the waiting queue function will be the function that returns the |
308 the waiting queue function will be the function that returns the |
307 empty list for every resource. |
309 empty list for every resource. |
308 |
310 |
309 \begin{isabelle}\ \ \ \ \ %%% |
311 \begin{isabelle}\ \ \ \ \ %%% |
378 waiting edge. The reason is that when a thread asks for resource that is locked |
380 waiting edge. The reason is that when a thread asks for resource that is locked |
379 already, then the process is blocked and cannot ask for another resource. |
381 already, then the process is blocked and cannot ask for another resource. |
380 Clearly, also every resource can only have at most one outgoing holding edge---indicating |
382 Clearly, also every resource can only have at most one outgoing holding edge---indicating |
381 that the resource is locked. In this way we can always start at a thread waiting for a |
383 that the resource is locked. In this way we can always start at a thread waiting for a |
382 resource and ``chase'' outgoing arrows leading to a single root of a tree. |
384 resource and ``chase'' outgoing arrows leading to a single root of a tree. |
|
385 |
383 |
386 |
384 |
387 |
385 The use of relations for representing RAGs allows us to conveniently define |
388 The use of relations for representing RAGs allows us to conveniently define |
386 the notion of the \emph{dependants} of a thread using the transitive closure |
389 the notion of the \emph{dependants} of a thread using the transitive closure |
387 operation for relations. This gives |
390 operation for relations. This gives |
525 |
528 |
526 \begin{isabelle}\ \ \ \ \ %%% |
529 \begin{isabelle}\ \ \ \ \ %%% |
527 \begin{tabular}{@ {}l} |
530 \begin{tabular}{@ {}l} |
528 @{thm (lhs) schs.simps(6)} @{text "\<equiv>"}\\ |
531 @{thm (lhs) schs.simps(6)} @{text "\<equiv>"}\\ |
529 \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\ |
532 \hspace{5mm}@{text "let"} @{text "wq = wq_fun (schs s)"} @{text "in"}\\ |
530 \hspace{5mm}@{text "let"} @{text "new_wq = release (wq cs)"} @{text "in"}\\ |
533 \hspace{5mm}@{text "let"} @{text "new_wq = wq(cs := release (wq cs))"} @{text "in"}\\ |
531 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (V th cs # s)|)"} |
534 \hspace{8mm}@{term "(|wq_fun = new_wq, cprec_fun = cpreced new_wq (V th cs # s)|)"} |
532 \end{tabular} |
535 \end{tabular} |
533 \end{isabelle} |
536 \end{isabelle} |
534 |
537 |
535 Having the scheduler function @{term schs} at our disposal, we can ``lift'', or |
538 Having the scheduler function @{term schs} at our disposal, we can ``lift'', or |
1287 Our implicit assumption that every event is an atomic operation is ensured by the architecture of |
1290 Our implicit assumption that every event is an atomic operation is ensured by the architecture of |
1288 PINTOS (which allows disabling of interrupts when some operations are performed). The case where |
1291 PINTOS (which allows disabling of interrupts when some operations are performed). The case where |
1289 an unlocked resource is given next to the waiting thread with the |
1292 an unlocked resource is given next to the waiting thread with the |
1290 highest precedence is realised in our implementation by priority queues. We implemented |
1293 highest precedence is realised in our implementation by priority queues. We implemented |
1291 them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations |
1294 them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations |
1292 for accessing and updating. Apart from having to implement relatively complex data\-structures in C |
1295 for accessing and updating. In the code we shall describe below, we use the function |
|
1296 @{ML_text "queue_insert"}, for inserting a new element into a priority queue, and |
|
1297 @{ML_text "queue_update"}, for updating the position of an element that is already |
|
1298 in a queue. Both functions take an extra argument that specifies the |
|
1299 comparison function used for organising the priority queue. |
|
1300 |
|
1301 Apart from having to implement relatively complex data\-structures in C |
1293 using pointers, our experience with the implementation has been very positive: our specification |
1302 using pointers, our experience with the implementation has been very positive: our specification |
1294 and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. |
1303 and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. |
1295 Let us illustrate this with the C-code for the function @{ML_text "lock_acquire"}, |
1304 Let us illustrate this with the C-code for the function @{ML_text "lock_acquire"}, |
1296 shown in Figure~\ref{code}. This function implements the operation of requesting and, if free, |
1305 shown in Figure~\ref{code}. This function implements the operation of requesting and, if free, |
1297 locking of a resource by the current running thread. The convention in the PINTOS |
1306 locking of a resource by the current running thread. The convention in the PINTOS |
1298 code is to use the terminology \emph{locks} rather than resources. |
1307 code is to use the terminology \emph{locks} rather than resources. |
1299 A lock is represented as a pointer to the structure {\tt lock} (Line 1). |
1308 A lock is represented as a pointer to the structure {\tt lock} (Line 1). |
1300 |
|
1301 Lines 2 to 4 are taken from the original |
1309 Lines 2 to 4 are taken from the original |
1302 code of @{ML_text "lock_acquire"} in PINTOS. They contain diagnostic code: first, |
1310 code of @{ML_text "lock_acquire"} in PINTOS. They contain diagnostic code: first, |
1303 there is a check that |
1311 there is a check that |
1304 the lock is a ``valid'' lock |
1312 the lock is a ``valid'' lock |
1305 by testing whether it is not {\tt NULL}; second, a check that the code is not called |
1313 by testing whether it is not {\tt NULL}; second, a check that the code is not called |
1306 as part of an interrupt---acquiring a lock should only be initiated by a |
1314 as part of an interrupt---acquiring a lock should only be initiated by a |
1307 request from a (user) thread, not from an interrupt; third, it is ensured that the |
1315 request from a (user) thread, not from an interrupt; third, it is ensured that the |
1308 current thread does not ask twice for a lock. These assertions are supposed |
1316 current thread does not ask twice for a lock. These assertions are supposed |
1309 to be satisfied because of the assumptions in PINTOS about how this code is called. |
1317 to be satisfied because of the assumptions in PINTOS about how this code is called. |
1310 If not, then the assertions indicate a bug in PINTOS and the result will be |
1318 If not, then the assertions indicate a bug in PINTOS and the result will be |
1311 a \emph{kernel panic}. |
1319 a ``kernel panic''. |
1312 |
1320 |
1313 |
1321 |
1314 |
1322 |
1315 \begin{figure}[t] |
1323 \begin{figure}[t] |
1316 \begin{lstlisting} |
1324 \begin{lstlisting} |
1364 current thread, and the other from the currend thread pointing to the lock. |
1372 current thread, and the other from the currend thread pointing to the lock. |
1365 According to our specification in Section~\ref{model} and the properties we were able |
1373 According to our specification in Section~\ref{model} and the properties we were able |
1366 to prove for @{text P}, we need to ``chase'' all the dependants |
1374 to prove for @{text P}, we need to ``chase'' all the dependants |
1367 in the RAG (Resource Allocation Graph) and update their |
1375 in the RAG (Resource Allocation Graph) and update their |
1368 current precedence; however we only have to do this as long as there is change in the |
1376 current precedence; however we only have to do this as long as there is change in the |
1369 current precedence from one thread at hand to another. |
1377 current precedence. |
1370 |
1378 |
1371 The ``chase'' is implemented in the while-loop in Lines 13 to 24. |
1379 The ``chase'' is implemented in the while-loop in Lines 13 to 24. |
1372 To initialise the loop, we |
1380 To initialise the loop, we |
1373 assign in Lines 11 and 12 the variable @{ML_text pt} to the owner |
1381 assign in Lines 11 and 12 the variable @{ML_text pt} to the owner |
1374 of the lock. |
1382 of the lock. |
1393 |
1401 |
1394 |
1402 |
1395 Similar operations need to be implementated for the @{ML_text lock_release} function, which |
1403 Similar operations need to be implementated for the @{ML_text lock_release} function, which |
1396 we however do not show. The reader should note though that we did \emph{not} verify our C-code. |
1404 we however do not show. The reader should note though that we did \emph{not} verify our C-code. |
1397 This is in contrast, for example, to the work on seL4, which actually verified in Isabelle/HOL |
1405 This is in contrast, for example, to the work on seL4, which actually verified in Isabelle/HOL |
1398 that their C-code satisfies its specification \cite{sel4}. |
1406 that their C-code satisfies its specification, thought this specification does not contain |
1399 Our verification however provided us with the justification for designing |
1407 anything about PIP \cite{sel4}. |
|
1408 Our verification of PIP however provided us with the justification for designing |
1400 the C-code. It gave us confidence that leaving the ``chase'' early, whenever |
1409 the C-code. It gave us confidence that leaving the ``chase'' early, whenever |
1401 there is no change in the calculated current precedence, does not break the |
1410 there is no change in the calculated current precedence, does not break the |
1402 correctness of the algorithm. |
1411 correctness of the algorithm. |
1403 *} |
1412 *} |
1404 |
1413 |
1442 the proof of Sha et al.: they require that critical sections nest properly, |
1451 the proof of Sha et al.: they require that critical sections nest properly, |
1443 whereas our scheduler allows critical sections to overlap. |
1452 whereas our scheduler allows critical sections to overlap. |
1444 |
1453 |
1445 PIP is a scheduling algorithm for single-processor systems. We are |
1454 PIP is a scheduling algorithm for single-processor systems. We are |
1446 now living in a multi-processor world. Priority Inversion certainly |
1455 now living in a multi-processor world. Priority Inversion certainly |
1447 occurs also there, see for example \cite{Brandenburg11, Davis11} |
1456 occurs also there, see for example \cite{Brandenburg11, Davis11}. |
1448 However, there is very little ``foundational'' |
1457 However, there is very little ``foundational'' |
1449 work about PIP-algorithms on multi-processor systems. We are not |
1458 work about PIP-algorithms on multi-processor systems. We are not |
1450 aware of any correctness proofs, not even informal ones. There is an |
1459 aware of any correctness proofs, not even informal ones. There is an |
1451 implementation of a PIP-algorithm for multi-processors as part of the |
1460 implementation of a PIP-algorithm for multi-processors as part of the |
1452 ``real-time'' effort in Linux, including an informal description of the implemented scheduling |
1461 ``real-time'' effort in Linux, including an informal description of the implemented scheduling |