/// <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 } }
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 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 }