769 lines
34 KiB
C#
769 lines
34 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: OneShotReservation.cs
|
|
//
|
|
// Note:
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using Microsoft.Singularity;
|
|
using Microsoft.Singularity.Scheduling;
|
|
|
|
namespace Microsoft.Singularity.Scheduling.Laxity
|
|
{
|
|
/// <summary>
|
|
/// OneShotReservations are created from tasks for the calling thread.
|
|
/// It has fields to track the thread calling and the thread waiting on,
|
|
/// the activity associated when it becomes an activity reservation, its
|
|
/// surrounding reservation, its place on the free reservation list,
|
|
/// general bookkeeping, bookkeeping for possible stolen time, and
|
|
/// references for the general reservation list.
|
|
/// </summary>
|
|
public class OneShotReservation : ISchedulerTask
|
|
{
|
|
// override the global LaxityQueueType enum with our own
|
|
public enum LaxityQueueType
|
|
{
|
|
NoQueue = 5,
|
|
GuaranteedQueue = 1,
|
|
// NonGuaranteedQueue = 2,
|
|
IdleQueue = 3,
|
|
// UnfinishedQueue = 4
|
|
};
|
|
|
|
// heap keyed on laxity holding all guaranteed one-shot reservations
|
|
// that currently have at least one runnable thread.
|
|
private static Heap guaranteedReservations = new Heap();
|
|
public static OneShotReservation TopGuaranteedReservation
|
|
{
|
|
get { return (OneShotReservation)guaranteedReservations.Min; }
|
|
}
|
|
|
|
static OneShotReservation idleReservations = null;
|
|
public static OneShotReservation IdleReservations
|
|
{
|
|
get { return idleReservations; }
|
|
}
|
|
|
|
static OneShotReservation currentReservation = null;
|
|
public static OneShotReservation CurrentReservation
|
|
{
|
|
get { return currentReservation; }
|
|
//set { currentReservation = value; }
|
|
}
|
|
|
|
public Hashtable resourcesGranted = new Hashtable();
|
|
public override Hashtable ResourcesGranted
|
|
{
|
|
get
|
|
{
|
|
resourcesGranted[CpuResource.Provider().ResourceString] = CpuResource.Provider().TimeToCpu(InitialEstimate);
|
|
return resourcesGranted;
|
|
}
|
|
}
|
|
|
|
|
|
private Task enclosingTask;
|
|
public override Task EnclosingTask
|
|
{
|
|
get { return enclosingTask; }
|
|
set { enclosingTask = value; }
|
|
}
|
|
|
|
public OneShotReservation SurroundingReservation;
|
|
public OneShotReservation FreeListNext;
|
|
public LaxityThread ReservTask;
|
|
|
|
TimeSpan constraintExecution;
|
|
public TimeSpan ConstraintExecution
|
|
{
|
|
get { return constraintExecution; }
|
|
}
|
|
|
|
TimeSpan initialThreadExecution;
|
|
|
|
public DateTime Start, Deadline;
|
|
public TimeSpan Estimate, RelativeDeadline;
|
|
|
|
public DateTime Laxity
|
|
{
|
|
// dnarayan
|
|
// 1. This is actually (laxity + timeNow). It has the same effect as laxity
|
|
// for comparing across tasks at any given instant, and the additional
|
|
// advantage that it doesn't change over time, only when resources are consumed.
|
|
// Another invariant is that with this definition, "laxity" of an individual task
|
|
// never increases.
|
|
|
|
// 2. The assumption is that Estimate always holds (in time units) the total
|
|
// remaining amount of resource (i.e. reserved - used). Currently this is just
|
|
// the CPU-remaining estimate
|
|
|
|
// 3. If we use more than our allocation, our laxity starts increasing, i.e.
|
|
// we get punished. This is a feature. However, it's still possible that we
|
|
// have overused one resource but have low laxity due to being behind on another.
|
|
// We might want to punish tasks for that as well?
|
|
|
|
get { return Deadline - Estimate; }
|
|
}
|
|
|
|
public TimeSpan InitialEstimate; // test only
|
|
public LaxityQueueType MyLaxityQueueType;
|
|
public bool Guaranteed;
|
|
public bool Valid;
|
|
public bool Satisfied;
|
|
|
|
// Reservations can be made for Threads XOR Activities!
|
|
public LaxityThread OriginalThread; // always the constraint thread -- non-null until the reservation is complete
|
|
//public LaxityThread ActiveThread; // the above, or the thread blocking it
|
|
//public int ActiveThreadEpoch;
|
|
public LaxityActivity AssociatedActivity; // the two fields above must be null!
|
|
|
|
|
|
public OneShotReservation Next;
|
|
public OneShotReservation Previous;
|
|
|
|
public TimeSpan InheritedEstimate; // Stolen => Inherited, no longer critical
|
|
public int ResolutionEpoch; // Stolen => Resolution, since not stealing.
|
|
|
|
public int ReferenceCount;
|
|
|
|
public OneShotReservation()
|
|
{
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
//ActiveThread = null;
|
|
//ActiveThreadEpoch = 0;
|
|
constraintExecution = new TimeSpan(0); //Move to enclosing class
|
|
initialThreadExecution = new TimeSpan(0); //Move to enclosing class
|
|
Deadline = new DateTime(0);
|
|
RelativeDeadline = new TimeSpan(0);
|
|
Estimate = new TimeSpan(0);
|
|
FreeListNext = null;
|
|
Guaranteed = false;
|
|
InitialEstimate = new TimeSpan(0);
|
|
Next = null;
|
|
OriginalThread = null;
|
|
AssociatedActivity = null;
|
|
Previous = null;
|
|
MyLaxityQueueType = LaxityQueueType.NoQueue;
|
|
ReferenceCount = 0;
|
|
ReservTask = null;
|
|
Satisfied = false;
|
|
Start = new DateTime(0);
|
|
SurroundingReservation = null;
|
|
ResolutionEpoch = 0;
|
|
InheritedEstimate = new TimeSpan(0);
|
|
Valid = false;
|
|
if (enclosingTask != null) {
|
|
enclosingTask.ClearSchedulerTask();
|
|
enclosingTask = null;
|
|
}
|
|
|
|
}
|
|
|
|
// find the runnable thread of a reservation:
|
|
public LaxityThread GetRunnableThread()
|
|
{
|
|
// LaxityThread thread;
|
|
//
|
|
if (AssociatedActivity != null) {
|
|
// if an activity reservation
|
|
return AssociatedActivity.GetRunnableThread();
|
|
}
|
|
|
|
Debug.Assert(OriginalThread != null);
|
|
|
|
// if ( (ActiveThread == OriginalThread) &&
|
|
// (ActiveThread.EnclosingThread.ThreadState == System.Threading.ThreadState.Running))
|
|
// return ActiveThread;
|
|
//
|
|
// thread = OriginalThread; // search for active thread starting w/ original thread
|
|
//
|
|
// if ((ActiveThread != null) &&
|
|
// (ActiveThread.Epoch == ActiveThreadEpoch) ) {
|
|
// if (ActiveThread.EnclosingThread.ThreadState == System.Threading.ThreadState.Running) {
|
|
//#if DEBUG_MUTEX
|
|
// DebugStub.WriteLine("Mutex inheritance (Epoch ok): Orig {0} Active {1} GO ON",
|
|
// thread.Id, ActiveThread.Id);
|
|
//#endif
|
|
// return ActiveThread;
|
|
// }
|
|
// }
|
|
//CKillian -- can't do this because of the array of blockedOn.
|
|
// else if (ActiveThread.EnclosingThread.IsSleeping()) {
|
|
// // more efficient: search for active thread starting w/ current active thread
|
|
// thread = ActiveThread;
|
|
// }
|
|
// else {
|
|
// Debug.Assert(false);
|
|
// }
|
|
//}
|
|
|
|
//A "smarter" thing to do would be to have GetRunnableBeneficiary check for
|
|
// the ActiveProcessor case. But as it stands that's info in the scheduler only
|
|
// the "good" news is that if we return null based on the active processor case
|
|
// we at least know someone is current running on a processor who would inherit
|
|
// time from us.
|
|
Thread temp = /*Active*/OriginalThread.EnclosingThread.GetRunnableBeneficiary();
|
|
if (temp == null || ((LaxityThread)temp.SchedulerThread).ActiveProcessor != null) {
|
|
return null;
|
|
}
|
|
else {
|
|
return (LaxityThread)temp.SchedulerThread;
|
|
}
|
|
}
|
|
|
|
public void StopThreadExecution(LaxityThread thread)
|
|
{
|
|
Debug.Assert(thread.ExecutionTime >= initialThreadExecution);
|
|
constraintExecution += thread.ExecutionTime - initialThreadExecution;
|
|
//Between two reservations which are atomically stopped/started, some
|
|
// time is charged against the default parent resource container. This
|
|
// is because I changed the way we account for tasks to do the general
|
|
// rule we wanted. In particular, I update the scheduling status just
|
|
// before resolving a new reservation. Not sure what the right fix is,
|
|
// so I'm leaving it. The assertion below will reveal the "error." The
|
|
// old code to track CPU usage is still active under constraintExecution,
|
|
// but isn't presently exposed to the applications. Currently UpdateSchedulingStatus()
|
|
// updates the CPU resources used for the whole task stack.
|
|
//Debug.Assert(CpuResource.Provider().TimeToCpu(constraintExecution).Cycles == ((CpuResourceAmount)enclosingTask.resourcesUsed[CpuResource.Provider().ResourceString]).Cycles);
|
|
//EnclosingTask.AddResourceAmountUsed(CpuResource.Provider().ResourceString, CpuResource.Provider().TimeToCpu(constraintExecution));
|
|
}
|
|
|
|
public void StartThreadExecution(LaxityThread thread)
|
|
{
|
|
initialThreadExecution = thread.ExecutionTime;
|
|
}
|
|
|
|
public void StartThreadExecution(LaxityThread thread, TimeSpan delta)
|
|
{
|
|
initialThreadExecution = thread.ExecutionTime + delta;
|
|
}
|
|
|
|
public static void BeginConstraintBeforeWait(LaxityThread thread, bool endPrevious,
|
|
TimeConstraint timeConstraint, DateTime timeNow)
|
|
{
|
|
OneShotReservation reservation;
|
|
|
|
Debug.Assert(thread == LaxityScheduler.GetCurrentThread());
|
|
Debug.Assert(!Processor.InterruptsDisabled());
|
|
if (endPrevious) {
|
|
bool iflag = Processor.DisableInterrupts();
|
|
EndPreviousConstraint(thread, timeNow);
|
|
Processor.RestoreInterrupts(iflag);
|
|
}
|
|
|
|
LaxityScheduler.UpdateSchedulingStatus();
|
|
|
|
reservation = thread.PendingReservation;
|
|
|
|
reservation.StartThreadExecution(thread, (timeNow - LaxityScheduler.SchedulingTime));
|
|
reservation.constraintExecution = new TimeSpan(0);
|
|
reservation.Start = timeConstraint.Start;
|
|
reservation.Deadline = timeConstraint.Deadline;
|
|
reservation.RelativeDeadline = timeConstraint.RelativeDeadline;
|
|
reservation.Estimate = timeConstraint.Estimate;
|
|
reservation.Valid = reservation.Guaranteed = true;
|
|
reservation.MyLaxityQueueType = LaxityQueueType.NoQueue;
|
|
reservation.ReservTask = thread;
|
|
reservation.OriginalThread = /*reservation.ActiveThread =*/ thread;
|
|
thread.AddRef();
|
|
//thread.AddRef();
|
|
//reservation.ActiveThreadEpoch = thread.Epoch;
|
|
reservation.AssociatedActivity = null;
|
|
reservation.Next = reservation.Previous = null;
|
|
|
|
}
|
|
|
|
// DI -- this is a new function used in both Begin and EndConstraint
|
|
public static bool EndPreviousConstraint(LaxityThread thread, DateTime timeNow)
|
|
{
|
|
OneShotReservation reservation, reservationNext;
|
|
bool success;
|
|
LaxityQueueType tempQueue; //Value assigned but never used.
|
|
|
|
Debug.Assert(Processor.InterruptsDisabled());
|
|
|
|
reservation = thread.ReservationStack;
|
|
|
|
success = (timeNow <= reservation.Deadline);
|
|
LaxityScheduler.UpdateSchedulingStatus();
|
|
reservation.StopThreadExecution(thread);
|
|
|
|
Debug.Assert(reservation.ConstraintExecution.Ticks >= 0);
|
|
// if (timeTaken.Ticks != 0) {
|
|
// timeTaken = reservation.ConstraintExecution;
|
|
// Debug.Assert( timeTaken.Ticks >= 0);
|
|
// }
|
|
|
|
thread.ReservationStack = reservation.SurroundingReservation;
|
|
reservation.SurroundingReservation = null;
|
|
|
|
if (currentReservation == reservation) {
|
|
// note that it might be the case that
|
|
// a reservation for the task id exist on the guaranteed Q but the
|
|
// the actual (executed) constraint is in the UnfinishedQ
|
|
currentReservation = null; // ????????????
|
|
LaxityScheduler.Reschedule();
|
|
}
|
|
Debug.Assert(reservation.OriginalThread == thread);
|
|
Debug.Assert(reservation.Start <= timeNow);
|
|
|
|
if (thread.ReservationStack == null) {
|
|
if (reservation.Estimate >= LaxityScheduler.MinSlice) {
|
|
// the constraint used less than estimated:
|
|
Debug.Assert(reservation.MyLaxityQueueType == LaxityQueueType.GuaranteedQueue);
|
|
#if false
|
|
Debug.Assert((reservation.ActiveThread == null) ||
|
|
(reservation.ActiveThread.Epoch != reservation.ActiveThreadEpoch) ||
|
|
(reservation.ActiveThread == reservation.OriginalThread));
|
|
reservation.ActiveThread.ReleaseProtected();
|
|
#endif
|
|
reservation.OriginalThread.ReleaseProtected();
|
|
reservation.AssociatedActivity = reservation.OriginalThread.AssociatedActivity; // and make it an activity reserv
|
|
reservation.OriginalThread = null;
|
|
//reservation.ActiveThread = null;
|
|
reservation.ReservTask = null;
|
|
LaxityScheduler.ActivityObjAddRef(reservation.AssociatedActivity);
|
|
// leave it on whatever Q it happens to be on
|
|
}
|
|
else {
|
|
reservation.DequeueReservation(); // from whatever Q it happens to be on
|
|
}
|
|
}
|
|
else {
|
|
tempQueue = reservation.MyLaxityQueueType;
|
|
reservationNext = thread.ReservationStack;
|
|
reservationNext.Estimate += reservation.Estimate;
|
|
reservationNext.constraintExecution += reservation.constraintExecution;
|
|
reservationNext.StartThreadExecution(thread);
|
|
// Debug.Assert( ((reservation.MyLaxityQueueType == LaxityQueueType.GuaranteedQueue) &&
|
|
// (reservationNext.MyLaxityQueueType == LaxityQueueType.NoQueue)) ||
|
|
// ((reservation.MyLaxityQueueType == LaxityQueueType.UnfinishedQueue) &&
|
|
// ((reservationNext.Estimate.Ticks <= 0) || (reservationNext.MyLaxityQueueType != LaxityQueueType.UnfinishedQueue ))));
|
|
reservation.Estimate = new TimeSpan(0);
|
|
Debug.Assert(reservation.Next != null);
|
|
reservation.DequeueReservation();
|
|
ReplaceOnLaxityHeap(reservationNext, timeNow);
|
|
|
|
}
|
|
// fprintf(stdout,"EndPrevConstr 0x%x %d\n", reservation, reservation.ReferenceCount);
|
|
reservation.ReleaseReservationProtected();
|
|
|
|
Scheduler.LogEndConstraint();
|
|
|
|
if (success == false) {
|
|
Scheduler.LogSchedulerLate();
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
public static bool ResolveConstraint(LaxityThread thread)
|
|
{
|
|
TimeSpan timeLeft, ownNodesTimeToSteal = new TimeSpan(1);
|
|
DateTime start, deadline;
|
|
TimeSpan timeInherited;
|
|
OneShotReservation pendingReservation = thread.PendingReservation, reservationPrevious;
|
|
DateTime timeNow = SystemClock.GetKernelTime();
|
|
bool ok = false;
|
|
|
|
Debug.Assert(Processor.InterruptsDisabled());
|
|
Debug.Assert(pendingReservation != null);
|
|
|
|
Scheduler.LogResolveConstraint();
|
|
|
|
thread.PendingReservation = null; // just clean the place
|
|
|
|
Debug.Assert(pendingReservation.Start.Ticks >= 0);
|
|
start = pendingReservation.Start;
|
|
if (start < timeNow) {
|
|
start = timeNow;
|
|
}
|
|
Debug.Assert(pendingReservation.Deadline.Ticks >= 0);
|
|
deadline = pendingReservation.Deadline;
|
|
if (deadline.Ticks == 0) {
|
|
deadline = timeNow + pendingReservation.RelativeDeadline;
|
|
}
|
|
|
|
if (thread.ReservationStack != null) {
|
|
OneShotReservation reservation = thread.ReservationStack;
|
|
while (!reservation.Valid && ((reservation = reservation.SurroundingReservation)!= null)) {
|
|
// no body.
|
|
}
|
|
|
|
if (reservation!= null) {
|
|
deadline = LaxityScheduler.minTime(deadline, reservation.Deadline);
|
|
}
|
|
}
|
|
|
|
// update data ure
|
|
pendingReservation.Start = start;
|
|
pendingReservation.Deadline = deadline;
|
|
//TODO: Should be for SIM ONLY!
|
|
Scheduler.LogReservationId(pendingReservation); // SIM only
|
|
timeInherited = new TimeSpan(0);
|
|
timeLeft = new TimeSpan(0);
|
|
ok = true;
|
|
pendingReservation.InitialEstimate = pendingReservation.Estimate;
|
|
reservationPrevious = thread.ReservationStack;
|
|
pendingReservation.SurroundingReservation= thread.ReservationStack;
|
|
thread.ReservationStack = pendingReservation;
|
|
LaxityScheduler.AddRefReservation(pendingReservation);
|
|
if (reservationPrevious != null) {
|
|
reservationPrevious.constraintExecution += pendingReservation.initialThreadExecution -
|
|
reservationPrevious.initialThreadExecution;
|
|
}
|
|
//
|
|
// Reschedule() called if currently we are executing on a pendingReservation
|
|
// and the EarliestDeadlineFirst top changed
|
|
// or the current pendingReservation goes into the idle list
|
|
// solve in SetStateWaiting
|
|
//
|
|
pendingReservation.EnqueueReservation(timeNow);
|
|
|
|
return ok;
|
|
}
|
|
|
|
void EnqueueReservation(DateTime timeNow)
|
|
{
|
|
OneShotReservation temp;
|
|
|
|
Debug.Assert((AssociatedActivity != null) ||
|
|
(OriginalThread != null));
|
|
|
|
// dnarayan: for simplicity, we schedule all tasks using global
|
|
// least-laxity, nothing out of individual resource containers.
|
|
#if false
|
|
// Infeasible or (Estimate == 0) Reservations:
|
|
if (Estimate <= LaxityScheduler.AFewSlice) {
|
|
LaxityActivity activity;
|
|
Debug.Assert(OriginalThread != null);
|
|
Debug.Assert(AssociatedActivity == null);
|
|
activity = OriginalThread.AssociatedActivity;
|
|
MyLaxityQueueType = LaxityQueueType.UnfinishedQueue;
|
|
if (activity.UnfinishedConstraints == null) {
|
|
Next = Previous = this;
|
|
activity.UnfinishedConstraints = this;
|
|
}
|
|
else {
|
|
// no order enforced
|
|
Next = activity.UnfinishedConstraints;
|
|
Previous = activity.UnfinishedConstraints.Previous;
|
|
activity.UnfinishedConstraints.Previous.Next = this;
|
|
activity.UnfinishedConstraints.Previous = this;
|
|
activity.UnfinishedConstraints = this; // optional
|
|
}
|
|
// DebugStub.WriteLine("Add: EnqueueReserve 1 0x{0:x} {1}", this, ReferenceCount);
|
|
LaxityScheduler.AddRefReservation(this);
|
|
return;
|
|
}
|
|
// Debug.Assert(Valid);
|
|
#endif
|
|
// Idle Reservations:
|
|
if (Start > timeNow + LaxityScheduler.AFewSlice) {
|
|
// take thread off activity Laxity queue and simulate a sleep
|
|
// i.e. don't set a timer interrupt
|
|
|
|
OriginalThread.InternalSetStateWaiting(DateTime.MaxValue);
|
|
|
|
#if DEBUG_START_RESERV
|
|
DebugStub.WriteLine("Put reservation {0}:{1} in IdleQueue\n", OriginalThread,
|
|
ReservationId);
|
|
#endif
|
|
Debug.Assert(OriginalThread != null);
|
|
MyLaxityQueueType = LaxityQueueType.IdleQueue;
|
|
|
|
if (idleReservations == null) {
|
|
Next = Previous = this;
|
|
idleReservations = this;
|
|
}
|
|
else {
|
|
temp = idleReservations;
|
|
if (Start < temp.Start) {
|
|
idleReservations = this;
|
|
}
|
|
else {
|
|
do {
|
|
temp = temp.Next;
|
|
} while (temp != idleReservations &&
|
|
Start >= temp.Start); // >= is compulsory to keep it 'FIFO'
|
|
} // insert before 'temp'
|
|
Next = temp;
|
|
Previous = temp.Previous;
|
|
temp.Previous.Next = this;
|
|
temp.Previous = this;
|
|
}
|
|
// fprintf(stdout,"Add: EnqueueReserve 2 0x%x %d\n", this, ReferenceCount);
|
|
LaxityScheduler.AddRefReservation(this);
|
|
return;
|
|
}
|
|
|
|
// Guaranteed OneShotReservation:
|
|
MyLaxityQueueType = LaxityQueueType.GuaranteedQueue;
|
|
if (GetRunnableThread() != null) {
|
|
Debug.Assert(guaranteedReservations.Insert(this, Laxity));
|
|
}
|
|
|
|
LaxityScheduler.AddRefReservation(this);
|
|
#if DEBUG_RESERV
|
|
PrintQueueReserv(guaranteedReservations, timeNow); //TODO: PrintQueueReserv
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// XXX dnarayan this is a replacement for ReplaceOnEarliestDeadlineFirst, but I
|
|
// don't really understand what it's supposed to do, so for now it does nothing (!)
|
|
|
|
static void ReplaceOnLaxityHeap(OneShotReservation reservation, DateTime timeNow)
|
|
{
|
|
#if false
|
|
while (reservation != null) {
|
|
if (reservation.Estimate.Ticks > 0) {
|
|
if (reservation.MyLaxityQueueType == LaxityQueueType.NoQueue) {
|
|
reservation.EnqueueReservation(timeNow);
|
|
}
|
|
else {
|
|
Debug.Assert(reservation.MyLaxityQueueType == LaxityQueueType.GuaranteedQueue);
|
|
}
|
|
break;
|
|
}
|
|
Debug.Assert(reservation.MyLaxityQueueType == LaxityQueueType.NoQueue);
|
|
reservation.EnqueueReservation(timeNow);
|
|
|
|
reservation = reservation.SurroundingReservation;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if false
|
|
public static bool SatisfyAcceptedConstraint(DateTime timeNow)
|
|
{
|
|
OneShotReservation reservation;
|
|
|
|
if (currentReservation != null) {
|
|
currentReservation.Estimate -= timeNow - LaxityScheduler.SchedulingTime;
|
|
if (currentReservation.Estimate.Ticks <= 0) {
|
|
LaxityThread tempThread = currentReservation.OriginalThread;
|
|
currentReservation.DequeueReservation();
|
|
if (tempThread != null) {
|
|
// activity reservations vanish here
|
|
//Debug.Assert(currentReservation.ActiveThread == LaxityScheduler.GetCurrentThread()); // only thread reserv are added to
|
|
currentReservation.EnqueueReservation(LaxityScheduler.SchedulingTime); // the UnfinishedConstraints list of the OriginalThread's Activ
|
|
OneShotReservation.ReplaceOnEarliestDeadlineFirst(currentReservation.SurroundingReservation, LaxityScheduler.SchedulingTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
reservation = guaranteedReservations;
|
|
while (reservation != null) {
|
|
reservation = reservation.Next;
|
|
if (reservation == guaranteedReservations) {
|
|
break;
|
|
}
|
|
}
|
|
reservation = idleReservations;
|
|
while (reservation != null) {
|
|
reservation = reservation.Next;
|
|
if (reservation == idleReservations) {
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
public static void UpdateCurrentReservation()
|
|
{
|
|
if ((currentReservation != null) &&
|
|
(currentReservation.Estimate <= LaxityScheduler.AFewSlice) ) {
|
|
// slice used for a reservation (CK: & estimate now empty )
|
|
LaxityThread tempThread = currentReservation.OriginalThread;
|
|
currentReservation.DequeueReservation();
|
|
if (tempThread != null) {
|
|
// activity reservations vanish here
|
|
currentReservation.EnqueueReservation(LaxityScheduler.SchedulingTime); // the UnfinishedConstraints list of the OriginalThread's Activ
|
|
ReplaceOnLaxityHeap(currentReservation.SurroundingReservation, LaxityScheduler.SchedulingTime);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public static void FreshenReservationQueues()
|
|
{
|
|
OneShotReservation tempReservation;
|
|
|
|
// Move 'idle' reservations to the 'active' reservations list, if necessary.
|
|
// A reservation is 'idle' until its Start time is reached.
|
|
// The 'active' reservation list is ordered 'Earliest Deadline Firts'.
|
|
// The 'idle' queue is ordered Earliest Start First.
|
|
while ((tempReservation = IdleReservations) != null) {
|
|
if (LaxityScheduler.SchedulingTime + LaxityScheduler.AFewSlice < tempReservation.Start) {
|
|
break;
|
|
}
|
|
tempReservation.DequeueReservation(); // Remove OneShotReservation from the Idle Queue
|
|
tempReservation.EnqueueReservation(LaxityScheduler.SchedulingTime); // Earliest Deadline First in the (Non)Guaranteed Queue
|
|
LaxityScheduler.EnqueueRunThread(tempReservation.OriginalThread, true);
|
|
#if DEBUG_START_RESERV
|
|
DebugStub.WriteLine("Get reservation {0}:{1} from IdleQueue", tempReservation.OriginalThread,
|
|
tempReservation.ReservationId);
|
|
#endif
|
|
|
|
}
|
|
|
|
// dnarayan: we don't remove deadline-passed tasks from the guaranteed queue,
|
|
// however they should get penalized by having increasing laxity. We might want
|
|
// to reconsider this decision.
|
|
#if false
|
|
// Remove the active reservations from the guaranteed and nonguaranteed queues
|
|
// if their Deadline is <= CurrentTime.
|
|
while ((tempReservation = guaranteedReservations) != null) {
|
|
if (LaxityScheduler.SchedulingTime + LaxityScheduler.AFewSlice < tempReservation.Deadline) {
|
|
break;
|
|
}
|
|
// fprintf(stdout,"Add: Reschedule Guaranteed Deadline 0x%x %d\n", tempReservation, tempReservation.ReferenceCount);
|
|
LaxityScheduler.AddRefReservation(tempReservation);
|
|
tempReservation.DequeueReservation(); // Remove OneShotReservation from the Guaranteed Queue
|
|
if ((tempReservation.OriginalThread != null) && // if a thread reservation
|
|
(tempReservation.OriginalThread.AssociatedActivity != null)) {
|
|
// If a thread reservation.
|
|
tempReservation.Estimate = new TimeSpan(0);
|
|
tempReservation.EnqueueReservation(LaxityScheduler.SchedulingTime); // add it to the Pending End Constraint List
|
|
}
|
|
// fprintf(stdout,"Reschedule Guaranteed Deadline off 0x%x %d\n", tempReservation, tempReservation.ReferenceCount);
|
|
tempReservation.ReleaseReservationProtected();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int ReleaseReservationProtected()
|
|
{
|
|
return LaxityScheduler.ReleaseReservationProtected(this);
|
|
}
|
|
|
|
public void DequeueReservation() //TODO: Should this be a resource container function?
|
|
{
|
|
Debug.Assert(Processor.InterruptsDisabled());
|
|
Debug.Assert((AssociatedActivity != null) ||
|
|
(OriginalThread != null));
|
|
|
|
if (MyLaxityQueueType == LaxityQueueType.GuaranteedQueue) {
|
|
Debug.Assert(guaranteedReservations.Delete(this));
|
|
}
|
|
else {
|
|
Debug.Assert(MyLaxityQueueType == LaxityQueueType.IdleQueue);
|
|
|
|
if (Next != this) {
|
|
//If there's another reservation, remove us from the queue
|
|
Next.Previous = Previous;
|
|
Previous.Next = Next;
|
|
Debug.Assert(Next.Deadline.Ticks > 0);
|
|
}
|
|
else {
|
|
//Otherwise we are only reservation.
|
|
Debug.Assert(Previous == this);
|
|
Next = null;
|
|
}
|
|
|
|
if (this == IdleReservations) {
|
|
// if we were head of the queue
|
|
idleReservations = Next;
|
|
}
|
|
|
|
Next = Previous = null;
|
|
// DebugStub.WriteLine("DequeueReservation 0x{0:x} {1}", this, ReferenceCount);
|
|
MyLaxityQueueType = LaxityQueueType.NoQueue;
|
|
ReleaseReservationProtected();
|
|
}
|
|
}
|
|
|
|
public static void FindRunnableReservation(ref LaxityThread currentThread)
|
|
{
|
|
// dnarayan: this is a bit hokey. What we really want is to maintain the
|
|
// invariant that the heap only contains tasks with runnable threads. However
|
|
// this involves hooking all the places where threads get added/removed as
|
|
// task beneficiaries.
|
|
|
|
ArrayList nonRunnableTasks = new ArrayList();
|
|
currentThread = null;
|
|
while (((currentReservation = (OneShotReservation) guaranteedReservations.Min)
|
|
!= null) && (currentThread == null)) {
|
|
currentThread = currentReservation.GetRunnableThread();
|
|
if (currentThread == null) {
|
|
Debug.Assert(guaranteedReservations.Delete(currentReservation));
|
|
nonRunnableTasks.Add(currentReservation);
|
|
}
|
|
}
|
|
|
|
// Now put all the non-runnable tasks back in the heap (!)
|
|
foreach (OneShotReservation resv in nonRunnableTasks) {
|
|
Debug.Assert(guaranteedReservations.Insert(resv, resv.Laxity));
|
|
}
|
|
}
|
|
|
|
// dnarayan: never called
|
|
#if false
|
|
public static void InheritAndReplaceOnEarliestDeadlineFirst(OneShotReservation reservation,
|
|
TimeSpan timeInherited,
|
|
DateTime timeNow)
|
|
{
|
|
OneShotReservation current = null;
|
|
|
|
while (reservation != null) {
|
|
if (reservation.Estimate.Ticks > 0) {
|
|
if (current == null) {
|
|
Debug.Assert(reservation.MyLaxityQueueType != LaxityQueueType.NoQueue);
|
|
current = reservation;
|
|
}
|
|
else {
|
|
Debug.Assert(reservation.MyLaxityQueueType == LaxityQueueType.NoQueue);
|
|
}
|
|
}
|
|
else if (reservation.MyLaxityQueueType != LaxityQueueType.NoQueue) {
|
|
Debug.Assert (current != null || reservation.MyLaxityQueueType == LaxityQueueType.UnfinishedQueue);
|
|
reservation.DequeueReservation();
|
|
}
|
|
Debug.Assert(timeInherited >= reservation.InheritedEstimate);
|
|
timeInherited -= reservation.InheritedEstimate;
|
|
Debug.Assert(reservation.Estimate >= reservation.InheritedEstimate);
|
|
reservation.Estimate -= reservation.InheritedEstimate;
|
|
reservation = reservation.SurroundingReservation;
|
|
}
|
|
|
|
if (current != null) {
|
|
if (current == CurrentReservation) {
|
|
current.Estimate -= timeNow - LaxityScheduler.SchedulingTime;
|
|
currentReservation = null;
|
|
LaxityScheduler.Reschedule();
|
|
}
|
|
current.DequeueReservation();
|
|
}
|
|
}
|
|
#endif
|
|
public static void InheritOnEarliestDeadlineFirst(OneShotReservation reservation, TimeSpan timeToInherit)
|
|
{
|
|
while (reservation != null && timeToInherit.Ticks > 0) {
|
|
|
|
Debug.Assert(timeToInherit >= reservation.InheritedEstimate);
|
|
reservation.Estimate -= reservation.InheritedEstimate;
|
|
timeToInherit -= reservation.InheritedEstimate;
|
|
reservation = reservation.SurroundingReservation;
|
|
}
|
|
}
|
|
|
|
public static void ClearCurrentReservation()
|
|
{
|
|
currentReservation = null;
|
|
}
|
|
}
|
|
}
|