In "Priority Inheritance Protocols and their Implementation" we discussed the behaviour of different priority inheritance protocols and their basic implementations under a strict set of execution restrictions. We also discussed how these restrictions (no blocking, no programmatic changing of priority etc) were not met in a real-time Java environment, and that consequently implementation of some of those protocols -- notably the Basic Priority Inheritance Protocol (BPIP) -- was greatly complicated compared to the simple schemes outlined in the literature. In this document we discuss an implementation approach for the BPIP within a real-time Java environment.
The base priority of a thread is the priority assigned to the thread by the application program. In terms of the Realtime Specification for Java, this is the priority defined in the PriorityParameters object bound to the realtime thread and which we assume can be changed at any time.
The active priority of a thread is its current execution priority as seen by the scheduler. This is the priority value used to establish execution eligibility and to order the thread on any system queues that are ordered by priority (such as monitor lock acquisition queues, and monitor wait-set queues).
The owner of a monitor is the thread that currently holds the monitor lock.
The lock-set of a monitor is the set of all threads blocked trying to acquire that monitor (ordered by active priority).
The top of the lock-set is the thread with the highest active priority.
The lock-set.top thread bequests its priority to the monitor owner. If the bequested priority is greater than the owners active priority then the owner inherits the bequested priority as its active priority. The lock-set.top thread is known as a priority source for the monitor owner.
The owned-set is the set of monitors owned by a thread.
The inheritance-queue of a thread is the ordered set of priority sources for that thread. The top of the inheritance-queue is the thread with the highest active priority.
Invariant: for all threads t
Invariant: for all threads t
Invariant: for all threads t, for all monitors m in t.ownedSet:
Invariant: a thread can exist in only one lock-set at a time, and so only in one inheritance queue.
Invariant: for all monitors m:
Invariant: for all threads t:
Property: when a thread t is started:
Property: when a thread t terminates:
Iin all cases correct operation simply involves maintaining the invariants that were previously listed, for all threads. We define two helper functions to express the basic actions that must occur in each case: maintainPriority and propagatePriority.
MaintainPriority: Causes a thread to check that it’s active priority invariant is met, and if not to change its active priority so that the invariant is met. An implementation can optimise things by checking for actual changes in active priority.
PropagatePriority: For a thread t this has the following effect:
if t is blocked acquiring a monitor m then m.lockSet.reposition(t); // ensure the lock set is correctly ordered if m.lockSet.top != old m.lockSet.top then m.owner.inheritanceQueue.remove(old m.lockSet.top); m.owner.inheritanceQueue.insert(m.lockSet.top); m.owner.maintainPriority(); m.owner.propagatePriority(); else if t == m.lockSet.top then m.owner.inheritanceQueue.reposition(t); m.owner.maintainPriority(); m.owner.propogatePriority(); else nop else if t is runnable/running reorder ready queue else nop
if (t == m.lockSet.top) then m.owner.inheritanceQueue.remove(old m.lockSet.top); m.owner.inheritanceQueue.insert(t); m.owner.maintainPriority(); m.owner.propagatePriority(); else nopWhen t eventually acquires the monitor then the following happens:
t.inheritanceQueue.insert(m.lockSet.top); t.maintainPriority(); t.propagatePriority();
When a thread t releases a monitor m, such that t is no longer the owner of m, then the following occurs:
t.inheritanceQueue.remove(m.lockSet.top); t.maintainPriority(); t.propagatePriority();
If a thread t has its priority changed to a value p then the following occurs:
t.basePriority = p; t.maintainPriority(); t.propagatePriority();