555 lines
21 KiB
C#
555 lines
21 KiB
C#
|
////////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// Microsoft Research Singularity
|
|||
|
//
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//
|
|||
|
// File: RialtoThread.cs
|
|||
|
//
|
|||
|
// Note:
|
|||
|
//
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.Threading;
|
|||
|
using Microsoft.Singularity;
|
|||
|
using Microsoft.Singularity.Scheduling;
|
|||
|
|
|||
|
namespace Microsoft.Singularity.Scheduling.Rialto
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// The kernel structure for the thread. Contains an associated activity, a
|
|||
|
/// stack of reservations executing the activity, a reference for a free
|
|||
|
/// reservation (rather than allocating a new one all the time), a pending
|
|||
|
/// reservation (used when new constraints are being created), a reference to the
|
|||
|
/// thread it<69>s waiting on (for use in scheduling inheritance), the basic thread
|
|||
|
/// queue and sleep queue pointers, lists of people waiting on mutexes and cv<63>s
|
|||
|
/// owned by this thread, bookkeeping for the type of waiting that I<>m doing, and
|
|||
|
/// general bookkeeping.
|
|||
|
/// </summary>
|
|||
|
public class RialtoThread : ISchedulerThread
|
|||
|
{
|
|||
|
// Thread State values passed to SetState
|
|||
|
// ThreadReady 0 Able to be run but not yet running
|
|||
|
// ThreadWaiting 1 Waiting for object and/or timeout
|
|||
|
// ThreadRunning 2 Current thread (for a given CPU)
|
|||
|
|
|||
|
//public enum ThreadState { ThreadReady = 0, ThreadWaiting = 1, ThreadRunning = 2};
|
|||
|
|
|||
|
static private ListNode sleepingThreads = null; // list of sleeping threads
|
|||
|
static private DateTime sleepTimeout = DateTime.MaxValue; // Next thread wakeup time
|
|||
|
private TimeSpan executionTime;
|
|||
|
|
|||
|
public override TimeSpan ExecutionTime
|
|||
|
{
|
|||
|
get { return executionTime; }
|
|||
|
}
|
|||
|
|
|||
|
public RialtoActivity AssociatedActivity; // Thread Activity
|
|||
|
//public RialtoThread.ThreadState State; // RUNNING, WAITING, SLEEPING
|
|||
|
|
|||
|
public OneShotReservation ReservationStack;
|
|||
|
// Stack of Reservations, one per active Constraint
|
|||
|
public OneShotReservation FreeReservation;
|
|||
|
public OneShotReservation PendingReservation;
|
|||
|
// PendingConstraint if any
|
|||
|
|
|||
|
// DI :: NOTE the Owner field in Kernel is used only for Inheritance control
|
|||
|
// need to REMOVE it -- this will help to locate easy all these functions and
|
|||
|
// comment them out
|
|||
|
//public int Epoch; // inc-ed at every kernel unlock
|
|||
|
|
|||
|
public DateTime StartTime; // only while on the sleep Q
|
|||
|
public RialtoThread Next; // Next and previous threads
|
|||
|
public RialtoThread Previous;
|
|||
|
|
|||
|
// DI -- ??!! this might replace Next and Previous from above
|
|||
|
public ListNode Queue; // List of threads in a queue
|
|||
|
// DI -- need it as a thread may wait on a condition (i.e. use Queue)
|
|||
|
// and wait for the timeout (Condition_TimedWait)
|
|||
|
public ListNode SleepQueue; // Another queue link, for sleeping only
|
|||
|
|
|||
|
public int ReferenceCount;
|
|||
|
public readonly Thread enclosingThread;
|
|||
|
|
|||
|
//public interface
|
|||
|
public RialtoThread(Thread thread)
|
|||
|
{
|
|||
|
enclosingThread = thread;
|
|||
|
Queue = new ListNode(this);
|
|||
|
SleepQueue = new ListNode(this);
|
|||
|
AssociatedActivity = null;
|
|||
|
StartTime = new DateTime(0);
|
|||
|
//TODO: BUGBUGBUG
|
|||
|
//Tid = Id; REPLACE WITH DEFAULT TASK?
|
|||
|
Queue.Next = Queue.Previous = Queue;
|
|||
|
SleepQueue.Next = SleepQueue.Previous = SleepQueue;
|
|||
|
//State = RialtoThread.ThreadState.ThreadWaiting;
|
|||
|
}
|
|||
|
|
|||
|
#region ISchedulerThread Members
|
|||
|
|
|||
|
public override Thread EnclosingThread
|
|||
|
{
|
|||
|
get { return enclosingThread; }
|
|||
|
}
|
|||
|
|
|||
|
//public interface
|
|||
|
public override void SetActivity(ISchedulerActivity iActivityNew)
|
|||
|
{
|
|||
|
// DebugStub.Print("RialtoThread.SetActivity()\n");
|
|||
|
Debug.Assert(iActivityNew != null);
|
|||
|
Debug.Assert(iActivityNew is RialtoActivity);
|
|||
|
RialtoActivity activityNew = (RialtoActivity)iActivityNew;
|
|||
|
RialtoActivity activityOld = AssociatedActivity;
|
|||
|
|
|||
|
|
|||
|
if (activityOld == activityNew) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
bool iflag = Processor.DisableInterrupts();
|
|||
|
|
|||
|
if (activityOld != null) {
|
|||
|
//if (State != RialtoThread.ThreadState.ThreadWaiting)
|
|||
|
if (enclosingThread.ThreadState == System.Threading.ThreadState.Running)
|
|||
|
RialtoScheduler.DequeueRunThread(this);
|
|||
|
RialtoScheduler.ActivityReleaseProtected(activityOld);
|
|||
|
}
|
|||
|
|
|||
|
if (activityNew != null) {
|
|||
|
//if (State != RialtoThread.ThreadState.ThreadWaiting)
|
|||
|
if (enclosingThread.ThreadState == System.Threading.ThreadState.Running) {
|
|||
|
AssociatedActivity = activityNew;
|
|||
|
RialtoScheduler.EnqueueRunThread(this);
|
|||
|
}
|
|||
|
RialtoScheduler.ActivityObjAddRef(activityNew);
|
|||
|
}
|
|||
|
else if (this == RialtoScheduler.GetCurrentThread()) {
|
|||
|
//TODO: Double Check! //State == RialtoThread.ThreadState.ThreadRunning)
|
|||
|
if (this == RialtoScheduler.GetCurrentThread() && activityOld != null) {
|
|||
|
RialtoScheduler.UpdateSchedulingStatus();
|
|||
|
}
|
|||
|
}
|
|||
|
AssociatedActivity = activityNew;
|
|||
|
// DebugStub.Print("Exiting RialtoThread.SetActivity()\n");
|
|||
|
Processor.RestoreInterrupts(iflag);
|
|||
|
}
|
|||
|
|
|||
|
//public interface
|
|||
|
public override void Start()
|
|||
|
{
|
|||
|
//TODO: No need for assertion perhaps -- default somehow?
|
|||
|
Debug.Assert(AssociatedActivity != null);
|
|||
|
bool iflag = Processor.DisableInterrupts();
|
|||
|
IReady();
|
|||
|
Processor.RestoreInterrupts(iflag);
|
|||
|
}
|
|||
|
|
|||
|
//public interface
|
|||
|
public override void Cleanup()
|
|||
|
{
|
|||
|
OneShotReservation reservation;
|
|||
|
// DebugStub.Print("Cleaning RialtoThread\n");
|
|||
|
|
|||
|
SetStateWaiting(DateTime.MaxValue);
|
|||
|
// DebugStub.Print("At this point thread is dequeued.\n");
|
|||
|
|
|||
|
while ((reservation = ReservationStack) != null) {
|
|||
|
ReservationStack = reservation.Next; // !!!! don't remove Caller's constraints !!!
|
|||
|
reservation.DequeueReservation();
|
|||
|
}
|
|||
|
|
|||
|
RialtoScheduler.ActivityObjRelease(AssociatedActivity);
|
|||
|
|
|||
|
//TODO: In the "real" system, cleanup is called by someone who will pick next thread, right?
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
public static DateTime GetSleepTimeout()
|
|||
|
{
|
|||
|
if (sleepingThreads != null) {
|
|||
|
return sleepTimeout;
|
|||
|
}
|
|||
|
else {
|
|||
|
return DateTime.MaxValue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void AddRef()
|
|||
|
{
|
|||
|
ReferenceCount++;
|
|||
|
}
|
|||
|
|
|||
|
// DI -- instead of calling this, one should call ::ReleaseActivity
|
|||
|
public void Release()
|
|||
|
{
|
|||
|
ReferenceCount--;
|
|||
|
Debug.Assert(ReferenceCount >= 0);
|
|||
|
}
|
|||
|
|
|||
|
public void ReleaseProtected()
|
|||
|
{
|
|||
|
ReferenceCount--;
|
|||
|
Debug.Assert(ReferenceCount >= 0);
|
|||
|
}
|
|||
|
|
|||
|
public override void SetStateWaiting(DateTime timeOut)
|
|||
|
{
|
|||
|
bool iflag = Processor.DisableInterrupts();
|
|||
|
InternalSetStateWaiting(timeOut);
|
|||
|
RialtoScheduler.DirectSwitchOnWait();
|
|||
|
Processor.RestoreInterrupts(iflag);
|
|||
|
}
|
|||
|
|
|||
|
public void InternalSetStateWaiting(DateTime timeOut)
|
|||
|
{
|
|||
|
Debug.Assert(Processor.InterruptsDisabled());
|
|||
|
// DI -- don't need activity state update
|
|||
|
//This to handle sleeps and timed waits.
|
|||
|
if (timeOut != DateTime.MaxValue) {
|
|||
|
if (timeOut - SystemClock.GetKernelTime() > RialtoScheduler.MinSlice) {
|
|||
|
Scheduler.LogSleepAdd();
|
|||
|
StartTime = timeOut;
|
|||
|
|
|||
|
PutOnSleepQueue();
|
|||
|
}
|
|||
|
else {
|
|||
|
//Sleeping for less than MinSlice is treated as not sleeping/yield.
|
|||
|
if (PendingReservation != null) {
|
|||
|
ResolvePendingReservation();
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RialtoScheduler.DequeueRunThread(this); // from RunnableThreads
|
|||
|
if (this == RialtoScheduler.GetCurrentThread()) {
|
|||
|
// if activity blocks during its own regular CPU slice; same code as in Sleep!
|
|||
|
if ((AssociatedActivity.RunnableThreads == null) &&
|
|||
|
(RialtoScheduler.CurrentPlanNode.Type == GraphNode.NodeType.Used) &&
|
|||
|
(RialtoScheduler.CurrentPlanNode.DefaultActivity == AssociatedActivity) &&
|
|||
|
((AssociatedActivity.MyRecurringCpuReservation.SliceLeft =
|
|||
|
RialtoScheduler.CurrentPlanNode.NextExec + RialtoScheduler.CurrentPlanNode.Slice
|
|||
|
- SystemClock.GetKernelTime()) >= RialtoScheduler.MinSlice)) {
|
|||
|
|
|||
|
AssociatedActivity.LastNode = RialtoScheduler.CurrentPlanNode; // record it
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// DI -- this is the function in !LAXITY version
|
|||
|
//TODO: REPLACE WITH ENCLOSING LOGIC!
|
|||
|
//public void SetState(ThreadState newState)
|
|||
|
//{
|
|||
|
// State = newState;
|
|||
|
// Debug.Assert(newState != ThreadState.ThreadWaiting);
|
|||
|
//}
|
|||
|
|
|||
|
// DI -- safe
|
|||
|
//TODO: REPLACE WITH ENCLOSING LOGIC!
|
|||
|
void IReady()
|
|||
|
{
|
|||
|
Debug.Assert(Processor.InterruptsDisabled());
|
|||
|
// TODO -- maybe something for directed context switch
|
|||
|
// DI -- don't need PutThreadOnReadyQueue outside schedule.c
|
|||
|
// PutThreadOnReadyQueue(thread);
|
|||
|
|
|||
|
RialtoScheduler.EnqueueRunThread(this);
|
|||
|
|
|||
|
// When an activity becomes runnable during
|
|||
|
// its own regular CPU slice, a reschedule occurs.
|
|||
|
if (AssociatedActivity.LastNode != null)
|
|||
|
{
|
|||
|
RialtoScheduler.EnqueueStandbyActivity(AssociatedActivity); // sets 'thread.AssociatedActivity.LastNode' to null
|
|||
|
Debug.Assert(AssociatedActivity.LastNode == null && RialtoScheduler.CurrentPlanNode != null, "Removing unused code! IF EXCEPTION HAPPENS, CODE SHOULD BE REPLACED");
|
|||
|
// if (RialtoScheduler.CurrentPlanNode == thread.AssociatedActivity.LastNode) { //TODO: This is really an equivalence with null?
|
|||
|
// RialtoScheduler.Reschedule();
|
|||
|
// }
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// DI -- this is called only from PutThreadOnSleepQueue
|
|||
|
// DI -- merge them ??
|
|||
|
static ListNode InsertThreadOnSleepQueue(RialtoThread thread, ListNode listThreadHead)
|
|||
|
{
|
|||
|
RialtoThread threadHead, threadTail, tempThread;
|
|||
|
|
|||
|
if (listThreadHead == null) {
|
|||
|
// Queue empty
|
|||
|
return thread.SleepQueue;
|
|||
|
}
|
|||
|
|
|||
|
threadHead = GetThreadFromListNode(listThreadHead);
|
|||
|
threadTail = GetThreadFromListNode(threadHead.SleepQueue.Previous);
|
|||
|
|
|||
|
if (thread.StartTime >= threadTail.StartTime) {
|
|||
|
thread.SleepQueue.InsertIntoList(threadTail.SleepQueue);
|
|||
|
// DI -- if merge: update sleepTimeout here
|
|||
|
return threadHead.SleepQueue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (thread.StartTime < threadHead.StartTime) {
|
|||
|
thread.SleepQueue.InsertIntoList(threadTail.SleepQueue);
|
|||
|
return thread.SleepQueue;
|
|||
|
}
|
|||
|
|
|||
|
tempThread = GetThreadFromListNode(threadHead.SleepQueue.Next);
|
|||
|
for (;;) {
|
|||
|
if (tempThread.StartTime > thread.StartTime) {
|
|||
|
thread.SleepQueue.InsertIntoList(tempThread.SleepQueue.Previous);
|
|||
|
break;
|
|||
|
}
|
|||
|
tempThread = GetThreadFromListNode(tempThread.SleepQueue.Next);
|
|||
|
}
|
|||
|
|
|||
|
return threadHead.SleepQueue;
|
|||
|
}
|
|||
|
|
|||
|
public void PutOnSleepQueue()
|
|||
|
{
|
|||
|
sleepingThreads = InsertThreadOnSleepQueue(this,sleepingThreads);
|
|||
|
sleepTimeout = (GetThreadFromListNode(sleepingThreads)).StartTime;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// public void Sleep(DateTime time)
|
|||
|
// {
|
|||
|
// if (time - SystemClock.GetKernelTime() > GraphNode.MinSlice) {
|
|||
|
// RialtoScheduler.LogSleepAdd();
|
|||
|
// StartTime = time;
|
|||
|
//
|
|||
|
// SetStateWaiting();
|
|||
|
//
|
|||
|
// // DI -- need it, called from WaitCond also
|
|||
|
// PutOnSleepQueue();
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
// Di -- safe -- optimized
|
|||
|
void PullThreadOffSleepQueue()
|
|||
|
{
|
|||
|
ListNode listThread, listNewHead;
|
|||
|
|
|||
|
listThread = SleepQueue;
|
|||
|
listNewHead = listThread.ListRemove();
|
|||
|
|
|||
|
if (sleepingThreads == listThread) {
|
|||
|
if ((sleepingThreads = listNewHead) != null) {
|
|||
|
sleepTimeout = (GetThreadFromListNode(sleepingThreads)).StartTime;
|
|||
|
}
|
|||
|
else {
|
|||
|
sleepTimeout = DateTime.MaxValue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void ResolvePendingReservation()
|
|||
|
{
|
|||
|
Debug.Assert(Processor.InterruptsDisabled());
|
|||
|
Debug.Assert(PendingReservation != null);
|
|||
|
bool admitted = OneShotReservation.ResolveConstraint(this);
|
|||
|
//else { DebugStub.WriteLine("Wake()-Resolve returned non S_OK"); }
|
|||
|
if (ReservationStack.EnclosingTask != null) {
|
|||
|
// Not clear if this will work in real system or not. Here for simulator mainly.
|
|||
|
ReservationStack.EnclosingTask.UpdateSchedulingState(admitted, ReservationStack.Deadline, ReservationStack.ResourcesGranted);
|
|||
|
}
|
|||
|
else {
|
|||
|
Debug.Assert(false);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// DI -- safe
|
|||
|
public override void Wake()
|
|||
|
{
|
|||
|
bool iflag = Processor.DisableInterrupts();
|
|||
|
PullThreadOffSleepQueue();
|
|||
|
IReady();
|
|||
|
|
|||
|
if (PendingReservation != null) {
|
|||
|
ResolvePendingReservation();
|
|||
|
}
|
|||
|
|
|||
|
RialtoScheduler.DirectSwitchOnWakeup();
|
|||
|
Processor.RestoreInterrupts(iflag);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
OneShotReservation AllocationReservation()
|
|||
|
{
|
|||
|
OneShotReservation reservation = FreeReservation;
|
|||
|
|
|||
|
Debug.Assert(reservation != null);
|
|||
|
FreeReservation = null;
|
|||
|
reservation.Clear();
|
|||
|
return reservation;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void IpcCheckFreeConstraint()
|
|||
|
{
|
|||
|
if (FreeReservation == null) {
|
|||
|
OneShotReservation reservation;
|
|||
|
|
|||
|
reservation = RialtoScheduler.IpcAllocateReservation();
|
|||
|
|
|||
|
if (reservation == null) {
|
|||
|
reservation = RialtoScheduler.AllocateReservation();
|
|||
|
}
|
|||
|
|
|||
|
FreeReservation = reservation;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If this thread doesn't have a free OneShotReservation reserved
|
|||
|
// for its use, then try to grab one from the global free list.
|
|||
|
// If there aren't any there, then allocate a new one.
|
|||
|
void ICheckFreeConstraint()
|
|||
|
{
|
|||
|
if (FreeReservation == null) {
|
|||
|
OneShotReservation reservation;
|
|||
|
|
|||
|
reservation = RialtoScheduler.AllocateReservation();
|
|||
|
|
|||
|
FreeReservation = reservation;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Free the Reservations associated with a thread.
|
|||
|
// Used by thread cleanup.
|
|||
|
public void IFreeConstraints()
|
|||
|
{
|
|||
|
OneShotReservation reservation;
|
|||
|
|
|||
|
// Debug.Assert(!Processor.InterruptsDisabled());
|
|||
|
|
|||
|
if (FreeReservation != null) {
|
|||
|
RialtoScheduler.IpcFreeReservation(FreeReservation);
|
|||
|
}
|
|||
|
|
|||
|
while ((reservation = ReservationStack) != null) {
|
|||
|
ReservationStack = reservation.SurroundingReservation;
|
|||
|
RialtoScheduler.ReleaseReservation(reservation);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// DI -- safe but optimize to because don't need QueueType
|
|||
|
public ListNode Dequeue()
|
|||
|
{
|
|||
|
return Queue.ListRemove();
|
|||
|
}
|
|||
|
|
|||
|
public static ListNode QueueFifo(RialtoThread thread, ListNode threadHead)
|
|||
|
{
|
|||
|
if (threadHead != null) {
|
|||
|
thread.Queue.InsertIntoList(threadHead.Previous);
|
|||
|
}
|
|||
|
else {
|
|||
|
threadHead = thread.Queue;
|
|||
|
}
|
|||
|
return threadHead;
|
|||
|
}
|
|||
|
|
|||
|
// DI -- safe
|
|||
|
public static RialtoThread GetThreadFromListNode(ListNode listNode)
|
|||
|
{
|
|||
|
Debug.Assert(listNode == null || listNode.Data is RialtoThread);
|
|||
|
if (listNode == null) {
|
|||
|
return null;
|
|||
|
}
|
|||
|
if (listNode.Data is RialtoThread) {
|
|||
|
return (RialtoThread)listNode.Data;
|
|||
|
}
|
|||
|
else {
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void WakeThreads()
|
|||
|
{
|
|||
|
RialtoThread ptemp;
|
|||
|
Debug.Assert(Processor.InterruptsDisabled());
|
|||
|
while ((ptemp = RialtoThread.GetThreadFromListNode(sleepingThreads)) != null &&
|
|||
|
ptemp.StartTime < RialtoScheduler.SchedulingTime + RialtoScheduler.LA_Time) {
|
|||
|
//TODO: LA_Time here?
|
|||
|
sleepingThreads = sleepingThreads.ListRemove();
|
|||
|
|
|||
|
RialtoScheduler.MoveToStandby(ptemp, true); //NOTE: Sets LastNode to null, prevents IReadythread from also EnqueueingStandbyActivity
|
|||
|
ptemp.IReady();
|
|||
|
|
|||
|
if (ptemp.PendingReservation != null) {
|
|||
|
ptemp.ResolvePendingReservation();
|
|||
|
}
|
|||
|
Scheduler.LogWakeThread(ptemp.EnclosingThread);
|
|||
|
}
|
|||
|
|
|||
|
if (ptemp != null)
|
|||
|
sleepTimeout = ptemp.StartTime;
|
|||
|
else
|
|||
|
sleepTimeout = DateTime.MaxValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="thread"></param>
|
|||
|
/// <param name="EndPrevious"></param>
|
|||
|
/// <param name="timeConstraint"></param>
|
|||
|
/// <param name="timeNow">TODO: UNUSED</param>
|
|||
|
/// <returns></returns>
|
|||
|
public bool BeginConstraintBeforeWaitValidate(bool endPrevious,
|
|||
|
ref TimeConstraint timeConstraint,
|
|||
|
DateTime timeNow)
|
|||
|
{
|
|||
|
if (endPrevious && // check to have a valid constraint in the stack.
|
|||
|
(ReservationStack == null || ReservationStack.OriginalThread == null)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (timeConstraint.Estimate.Ticks < 0) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// By this time, something should be in FreeReservation
|
|||
|
// grab it now such to enable the EndPreviousConstraint to
|
|||
|
// save its reservation in the cache
|
|||
|
Debug.Assert(FreeReservation != null);
|
|||
|
Debug.Assert(FreeReservation != OneShotReservation.CurrentReservation);
|
|||
|
|
|||
|
PendingReservation = AllocationReservation();
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
public void AddExecutionTime(TimeSpan delta)
|
|||
|
{
|
|||
|
executionTime += delta;
|
|||
|
}
|
|||
|
|
|||
|
public override ISchedulerTask PrepareDelayedTask(ISchedulerTask taskToEnd,
|
|||
|
ref TimeConstraint timeConstraint,
|
|||
|
DateTime timeNow)
|
|||
|
{
|
|||
|
// DI -- the Next calls are from TimedWaitAndBeginConstraint
|
|||
|
IpcCheckFreeConstraint();
|
|||
|
|
|||
|
Debug.Assert(taskToEnd == null || taskToEnd == ReservationStack);
|
|||
|
bool endPrevious = (taskToEnd != null);
|
|||
|
|
|||
|
if (!BeginConstraintBeforeWaitValidate(endPrevious, ref timeConstraint, timeNow)) {
|
|||
|
goto Exit;
|
|||
|
}
|
|||
|
|
|||
|
OneShotReservation.BeginConstraintBeforeWait(this, endPrevious, timeConstraint, timeNow);
|
|||
|
Exit:
|
|||
|
return PendingReservation;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|