void ITaskTimerOwner.AddToPending(TaskTimer timer, TaskEnv env, TaskTimerStatus next) { env.Acquire(); if(timer.Env != null) { timer.Env.Release(); } if(_running) { lock(_pending) { timer.Env = env; timer.SetStatus(next); _pending[timer] = null; } } else { env.Release(); timer.Env = null; timer.SetStatus(TaskTimerStatus.Done); } }
void ITaskTimerOwner.AddToQueue(TaskTimer timer, TaskEnv env, TaskTimerStatus next) { env.Acquire(); if(timer.Env != null) { timer.Env.Release(); } if(_running) { lock(_queue) { timer.Env = env; timer.SetStatus(next); _queue.Enqueue(timer); } } else { env.Release(); timer.Env = null; timer.SetStatus(TaskTimerStatus.Done); } }
/// <summary> /// Change when the timer will execute. /// </summary> /// <param name="when">The absolute time.</param> /// <param name="env">The environment to use for invocation.</param> public void Change(DateTime when, TaskEnv env) { DateTime now = DateTime.UtcNow; // determine new status int next; if (when <= now.AddSeconds(QUEUE_CUTOFF)) { next = (int)TaskTimerStatus.Queued; } else if (when < DateTime.MaxValue) { next = (int)TaskTimerStatus.Pending; } else { next = (int)TaskTimerStatus.Done; } // ensure we have a behavior if we need one and we don't if we do not if (next != (int)TaskTimerStatus.Done) { if (env == null) { throw new ArgumentNullException("env"); } } else { env = null; } // attempt to change current status retry: int current; switch (_status) { case (int)TaskTimerStatus.Done: // nothing to do break; case (int)TaskTimerStatus.Pending: // attempt to remove timer from pending list current = Interlocked.CompareExchange(ref _status, (int)TaskTimerStatus.Done, (int)TaskTimerStatus.Pending); switch (current) { case (int)TaskTimerStatus.Done: // nothing to do break; case (int)TaskTimerStatus.Pending: // remove timer from pending list _owner.RemoveFromPending(this); break; case (int)TaskTimerStatus.Queued: // we changed states; retry Interlocked.Increment(ref _retries); goto retry; case (int)TaskTimerStatus.Locked: // somebody else is already changing the timer; no need to compete return; } break; case (int)TaskTimerStatus.Queued: // attempto remove timer from queue current = Interlocked.CompareExchange(ref _status, (int)TaskTimerStatus.Done, (int)TaskTimerStatus.Queued); switch (current) { case (int)TaskTimerStatus.Done: // nothing to do break; case (int)TaskTimerStatus.Pending: // we changed states; retry Interlocked.Increment(ref _retries); goto retry; case (int)TaskTimerStatus.Queued: // remove timer from queue _owner.RemoveFromQueue(this); break; case (int)TaskTimerStatus.Locked: // somebody else is already changing the timer; no need to compete return; } break; case (int)TaskTimerStatus.Locked: // somebody else is already changing the timer; no need to compete return; } // register timer according to new status if (Interlocked.CompareExchange(ref _status, (int)TaskTimerStatus.Locked, (int)TaskTimerStatus.Done) == (int)TaskTimerStatus.Done) { _when = when; switch (next) { case (int)TaskTimerStatus.Done: // release Task Environment if (Env != null) { Env.Release(); } Env = null; Interlocked.Exchange(ref _status, next); return; case (int)TaskTimerStatus.Pending: // add timer to pending list _owner.AddToPending(this, env, (TaskTimerStatus)next); break; case (int)TaskTimerStatus.Queued: // add timer to active queue _owner.AddToQueue(this, env, (TaskTimerStatus)next); break; case (int)TaskTimerStatus.Locked: Interlocked.Exchange(ref _status, (int)TaskTimerStatus.Done); throw new InvalidOperationException("should never happen"); } } }