real-time extensions Marc Feeley 12 May 2000 12:47 UTC

Here is a summary of the real-time extensions that were added to
SRFI 18.

1) The concept of "base priority", "boosted priority", and "effective
   priority".  All of these priorities are represented with real
   numbers (the maximum and minimum are plus and minus infinity).
   This allows deadlines to be expressed by setting the base priority
   to the negation of the deadline time, i.e.

    (thread-base-priority-set!
      thread
      (- (+ (time->seconds (current-time)) 10)))

   The "priority boost" (which should be 0 when deadlines are used) is
   added to the base priority to get the boosted priority, when the
   thread blocks.  By carefully choosing the base priority and
   priority boost it is possible to set up an interactive thread so
   that it has good I/O response time without being a CPU hog when it
   performs long computations.

   The effective priority of a thread T is equal to the maximum of T's
   boosted priority and the effective priority of all the threads that
   are blocked on a mutex owned by T. This "priority inheritance"
   avoids priority inversion problems that would prevent a high
   priority thread blocked at the entry of a critical section to
   progress because a low priority thread inside the critical section
   is preempted for an arbitrary long time by a medium priority
   thread.

2) A precise definition of scheduling constraints based on priorities
   and blocking time, and a notion of time ordering of events based on
   a clock with a finite resolution.

The following are other changes which I also intend to add to SRFI 18:

3) Threads have a "specific" field which can be used to store thread
   specific data (i.e. the "thread local storage" of other thread
   systems).

4) Mutexes now have 4 states: locked (either owned or not owned) and
   unlocked (either abandoned or not abandoned).  A locked/not-owned
   mutex is not linked to a particular thread, which means no priority
   inheritance will occur if a thread blocks on that mutex.

5) "mutex-owner" has been renamed "mutex-state".

6) "mutex-lock!" can be passed a third argument to specify how the
   ownership of the mutex is changed.  If the argument is #f the mutex
   will become locked/not-owned, if the argument is a thread the mutex
   will become locked/owned and owned by that thread, and if the
   argument is not supplied the mutex will become locked/owned by the
   current thread.

7) "make-mutex" can no longer create a mutex that is initially owned
   by a thread.  This is so the only places a mutex is locked and
   unlocked is when "mutex-lock!" and "mutex-unlock!" are called,
   making it easier to reason about locks.

8) The functionality of "condition-variable-wait!" has been folded
   into "mutex-unlock!", for the reason given in 7) and also because
   there are two ways to lock a mutex and extra parameters would have
   to be passed to condition-variable-wait! to specify the type of
   locking to use once the wait is over.  Note that this means an
   explicit call to mutex-lock! is needed, for example:

        (define (semaphore-wait! sema)
          (mutex-lock! (vector-ref sema 1))
          (let ((n (vector-ref sema 0)))
            (if (> n 0)
                (begin
                  (vector-set! sema 0 (- n 1))
                  (mutex-unlock! (vector-ref sema 1)))
                (begin
                  (mutex-unlock! (vector-ref sema 1) (vector-ref sema 2))
                  (semaphore-wait! sema))))

Marc