/// <summary> /// Initialize the instance. /// </summary> /// <param name="owner">The object that "owns" this operation (or <c>null</c>).</param> /// <param name="callback">The delegate to call when the operation completes.</param> /// <param name="state">The application defined state.</param> /// <remarks> /// The owner parameter is optionally used to identify the object that "owns" /// this operation. This parameter may be null or any object type. Additional /// information will be tracked by <see cref="AsyncTracker" /> if the object implements the /// <see cref="IAsyncResultOwner" /> interface. /// </remarks> public AsyncResult(object owner, AsyncCallback callback, object state) { this.owner = owner; this.callback = callback; this.asyncState = state; this.internalState = default(TInternalState); this.ttd = DateTime.MaxValue; this.result = default(TResult); this.wait = null; this.isCompleted = false; this.syncCompletion = false; this.exception = null; this.notifyQueued = false; #if DEBUG && !MOBILE_DEVICE this.isWaiting = false; this.isReleased = false; this.traceID = -1; this.traceName = null; this.inCallback = false; this.disposed = false; this.createStack = CallStack.AsyncTrace(1, true); this.startStack = null; this.notifyStack = null; this.completeStack = null; this.waitStack = null; #endif }
public void Started() { #if DEBUG && !MOBILE_DEVICE Trace("Started()"); this.startStack = CallStack.AsyncTrace(1, true); AsyncTracker.Add(this); AsyncTracker.Yield(); #endif }
/// <summary> /// Blocks the current thread until the operation completes. /// This is more efficient than calling <b>AsyncWaitHandle.WaitOne()</b> /// since it won't allocate an event if the operation has already /// completed. /// </summary> public void Wait() { #if DEBUG && !MOBILE_DEVICE using (TimedLock.Lock(this)) { if (waitStack == null) { waitStack = CallStack.AsyncTrace(0, true); } if (isWaiting) { Trace("Wait(exception): Another thread is already waiting."); throw new InvalidOperationException("Another thread is already waiting."); } if (isReleased) { Trace("Wait(release): Already released"); return; } if (isCompleted) { isReleased = true; Trace("Wait(no wait): Result={0} Sync={1}", result == null ? "null" : result.ToString(), syncCompletion); return; } isWaiting = true; } #endif #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif #if DEBUG && !MOBILE_DEVICE Trace("Wait(block)"); ((AsyncEvent)this.AsyncWaitHandle).WaitOne(); isReleased = true; Trace("Wait(release): Result={0} Sync={1}", result == null ? "null" : result.ToString(), syncCompletion); #else this.AsyncWaitHandle.WaitOne(); #endif #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif }
/// <summary> /// Release any resources associated with this object. /// </summary> public void Dispose() { using (TimedLock.Lock(this)) { #if DEBUG && !MOBILE_DEVICE if (!isCompleted) { AsyncTracker.Dump(this, "Disposing AsyncResult before operation completes."); SysLog.LogErrorStackDump("Disposing AsyncResult before operation completes."); return; } if (disposed) { var sb = new StringBuilder(1024); AsyncTracker.Dump(this, "AsyncResult has already been disposed."); sb.AppendLine("AsyncResult has already been disposed."); sb.AppendLine(); sb.AppendLine("Current stack:"); CallStack.AsyncTrace(1, true).Dump(sb); sb.AppendLine(); sb.AppendLine("Completion stack:"); completeStack.Dump(sb); SysLog.LogError(sb.ToString()); return; } this.disposed = true; this.completeStack = CallStack.AsyncTrace(1, true); #endif if (wait != null) { wait.Close(); wait = null; } } #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif }
public override bool WaitOne() { using (TimedLock.Lock(owner)) { if (owner.WaitStack == null) { owner.WaitStack = CallStack.AsyncTrace(0, true); } if (isWaiting) { throw new InvalidOperationException("Another thread is already waiting."); } isWaiting = true; } return(wait.WaitOne()); }
public override bool WaitOne(int millisecondTimeout, bool exitContext) { using (TimedLock.Lock(owner)) { if (owner.WaitStack == null) { owner.WaitStack = CallStack.AsyncTrace(0, true); } if (!isWaiting) { throw new InvalidOperationException("Another thread is already waiting."); } isWaiting = true; } return(wait.WaitOne(millisecondTimeout, exitContext)); }
public void Started(bool traceEnable) { #if DEBUG && !MOBILE_DEVICE if (traceEnable) { // The trace name will be the name of the object type and method // that called this method. var stack = new CallStack(1, false); var method = stack.GetFrame(0).GetMethod(); this.traceName = method.DeclaringType.Name + "." + method.Name; this.traceID = AsyncTraceID.GetNextID(); } Trace("Started()"); this.startStack = CallStack.AsyncTrace(1, true); AsyncTracker.Add(this); AsyncTracker.Yield(); #endif }
/// <summary> /// Notify the application that the operation is complete /// via the call back delegate. /// </summary> /// <param name="e"> /// The exception to be thrown in the <see cref="Finish" /> method /// or <c>null</c> if the operation was completed successfully. /// </param> /// <remarks> /// <note> /// Although this method may be called more than once for /// a particular async result instance, all but the first call /// will be ignored. /// </note> /// </remarks> public void Notify(Exception e) { #if DEBUG && !MOBILE_DEVICE // Wait up to a second to verify that Started() has been // called before reporting a warning. DateTime endTime = SysTime.Now + TimeSpan.FromSeconds(1); bool started = this.startStack != null; while (!started && SysTime.Now < endTime) { Thread.Sleep(10); started = this.startStack != null; } if (!started) { Trace("Notify({0}): Warning: Started() not called", exception != null ? exception.GetType().Name : (result == null ? "null" : result.ToString())); AsyncTracker.Dump(this, "Warning: Started() not called before Notifiy()"); } if (notifyQueued) { Trace("Notify({0}: Already queued)", exception != null ? exception.GetType().Name : (result == null ? "null" : result.ToString())); return; } Trace("Notify({0})", exception != null ? exception.GetType().Name : (result == null ? "null" : result.ToString())); notifyStack = CallStack.AsyncTrace(1, true); if (NotifyHook != null) { NotifyHook(this, e); } #endif #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif using (TimedLock.Lock(this)) { notifyQueued = true; if (isCompleted) { return; // We've already signaled completion } exception = e; if (callback != null) { if (syncCompletion) { callback(this); } else { Helper.UnsafeQueueUserWorkItem(onComplete, this); } } else { isCompleted = true; if (wait != null) { wait.Set(); } } } #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif }