/// <summary> /// Forwards queued completion notifications to the proper /// async result handler. /// </summary> /// <param name="state">The queued async result.</param> private static void OnComplete(object state) { AsyncResult <TResult, TInternalState> ar = (AsyncResult <TResult, TInternalState>)state; #if DEBUG && !MOBILE_DEVICE ar.inCallback = true; #endif try { #if !MOBILE_DEVICE AsyncTracker.Yield(); #endif using (TimedLock.Lock(ar)) { #if DEBUG && !MOBILE_DEVICE if (ar.disposed) { ar.Trace("OnComplete(): AsyncResult has been disposed before operation completes"); AsyncTracker.Dump(ar, "AsyncResult has been disposed before operation completes."); SysLog.LogErrorStackDump("AsyncResult has been disposed before operation completes."); if (Debugger.IsAttached) { Debugger.Break(); } } ar.Trace("Callback({0})", ar.callback == null ? "null" : ""); #endif if (ar.callback == null) { return; } ar.isCompleted = true; if (ar.wait != null) { ar.wait.Set(); } ar.callback(ar); } } catch (Exception e) { SysLog.LogException(e); } finally { #if DEBUG && !MOBILE_DEVICE ar.inCallback = false; #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 }
/// <summary> /// Writes the async result's state in human readable form to the /// system log. /// </summary> public void Dump() { AsyncTracker.Dump(this, null); }
/// <summary> /// Writes the async result's state in human readable form to the /// system log. /// </summary> /// <param name="title">An optional title line (or <c>null</c>).</param> public void Dump(string title) { AsyncTracker.Dump(this, title); }
/// <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 }