Journal/Paper.thy
changeset 7 0514be2ad83e
parent 6 7f2493296c39
child 8 5ba3d79622da
equal deleted inserted replaced
6:7f2493296c39 7:0514be2ad83e
  1252   highest precedence is realised in our implementation by priority queues. We implemented
  1252   highest precedence is realised in our implementation by priority queues. We implemented
  1253   them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations
  1253   them as \emph{Braun trees} \cite{Paulson96}, which provide efficient @{text "O(log n)"}-operations
  1254   for accessing and updating. Apart from having to implement relatively complex data\-structures in C
  1254   for accessing and updating. Apart from having to implement relatively complex data\-structures in C
  1255   using pointers, our experience with the implementation has been very positive: our specification 
  1255   using pointers, our experience with the implementation has been very positive: our specification 
  1256   and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. 
  1256   and formalisation of PIP translates smoothly to an efficent implementation in PINTOS. 
       
  1257 
       
  1258   \begin{figure}
       
  1259   \begin{lstlisting}
       
  1260 void lock_acquire (struct lock *lock)
       
  1261 { ASSERT (lock != NULL);
       
  1262   ASSERT (!intr_context());
       
  1263   ASSERT (!lock_held_by_current_thread (lock));
       
  1264 
       
  1265   enum intr_level old_level;
       
  1266   old_level = intr_disable();
       
  1267   if (lock->value == 0) {
       
  1268     heap_insert(thread_preced, &lock->wq, &thread_current()->helem); 
       
  1269     thread_current()->waiting = lock;
       
  1270     struct thread *pt;
       
  1271     pt = lock->holder;
       
  1272     while (pt) {
       
  1273       heap_update(lock_preced, &pt->held, &lock->helem);
       
  1274       if (!(update_cpreced(pt)))
       
  1275         break;
       
  1276       lock = pt->waiting;
       
  1277       if (!lock) {
       
  1278         heap_update(higher_cpreced, &ready_heap, &pt->helem);
       
  1279         break;
       
  1280       };
       
  1281       heap_update(thread_preced, &lock->wq, &pt->helem);
       
  1282       pt = lock -> holder;
       
  1283     };
       
  1284     thread_block();
       
  1285   } else {
       
  1286     lock->value--;
       
  1287     lock->holder = thread_current();
       
  1288     heap_insert(lock_prec, &thread_current()->held, &lock->helem); 
       
  1289   };
       
  1290   intr_set_level(old_level);
       
  1291 }
       
  1292   \end{lstlisting}
       
  1293   \caption{Our version of the {\tt lock\_release} function (implementing event @{text P}) in 
       
  1294   PINTOS.\label{code}}
       
  1295   \end{figure}
       
  1296 
       
  1297   Let us illustrate that our specification translates relatively smoothly
       
  1298   into C-code. The function {\tt lock\_aquire}, shown in Figure~\ref{code}, 
       
  1299   implements the operation that
       
  1300   the currently running thread asks for the lock of a specific resource. 
       
  1301   In C such a lock is represented as a pointer to the structure {\tt lock}. Lines 2 to 
       
  1302   4 contain diagnostic code for PINTOS: first we check that the lock is a ``valid'' lock 
       
  1303   by testing it is not {\tt NULL}; second we check that the code is not called
       
  1304   as part of an interrupt---aquiring a lock should have been only initiated by a 
       
  1305   request from a (user) thread, not an interrupt; third we make sure the 
       
  1306   current thread does not ask twice for a lock. These assertions are supposed
       
  1307   to be always satisfied because of the assumptions in PINTOS of how this code is called.
       
  1308   If not, then there is a bug in PINTOS.
       
  1309 
       
  1310   Line 6 and 7 make the operation of aquiring a lock atomic by disabling all 
       
  1311   interrupts, but saving them for resumption at the ond of the function (Line 31).
       
  1312   In Line 8, the interesting code of this function starts: we 
       
  1313   test whether lock is already taken (its value is 0 for indicating ``already 
       
  1314   taken'' and 1 for being ``free''). In case the lock is taken, we need to
       
  1315   insert the current thread into the waiting queue of the lock (Line 9,
       
  1316   the waiting queue is referenced as @{ML_text "&lock-wq"}). The queues are
       
  1317   implemented as Braun Trees providing an heap interface, therefore
       
  1318   the function is called @{ML_text "heap_insert"}. Next we
       
  1319   record that the current thread is waiting for the lock (Line 10).
       
  1320 
  1257 *}
  1321 *}
  1258 
  1322 
  1259 section {* Conclusion *}
  1323 section {* Conclusion *}
  1260 
  1324 
  1261 text {* 
  1325 text {*