Ejemplo n.º 1
0
        /// <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
        }
Ejemplo n.º 2
0
            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());
            }
Ejemplo n.º 3
0
            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));
            }
Ejemplo n.º 4
0
        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
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Adds additional information about the current thread (the thread that
        /// could not acquire the lock) and other locks held by the current thread and the
        /// thread that did acquire the lock to the <see cref="LockInfo" /> instance
        /// so that errors can be reported.
        /// </summary>
        /// <param name="info">The source lock information.</param>
        /// <param name="curStack">The current call stack.</param>
        /// <returns>A cloned version of the source with the additonal information.</returns>
        private LockInfo GetDiagnosticInfo(LockInfo info, CallStack curStack)
        {
            info = info.Clone();
            info.FailNativeThreadID  = GetCurrentThreadId();
            info.FailManagedThreadID = Thread.CurrentThread.ManagedThreadId;
            info.FailStack           = curStack;
            info.Locks     = new List <LockInfo>();
            info.FailLocks = new List <LockInfo>();

            foreach (LockInfo l in locks.Values)
            {
                if (l.ManagedThreadID == info.ManagedThreadID)
                {
                    info.Locks.Add(l);
                }
                else if (l.ManagedThreadID == info.FailManagedThreadID)
                {
                    info.FailLocks.Add(l);
                }
            }

            return(info);
        }
Ejemplo n.º 6
0
        /// <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
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Attempts to obtain a lock on an object with the specified timeout.
        /// </summary>
        /// <param name="target">The object whose lock is to be acquired.</param>
        /// <param name="timeout">The maximum time to wait.</param>
        private void _Lock(object target, TimeSpan timeout)
        {
            if (fullDiagnostics && lockableWarning && target as ILockable == null)
            {
                string typeName = target.GetType().FullName;
                bool   warn;

                lock (locks)
                {
                    warn = !prevWarnings.ContainsKey(typeName);
                    if (warn)
                    {
                        prevWarnings.Add(typeName, true);
                    }
                }

                if (warn)
                {
                    SysLog.LogWarning("Type [{0}] does not implement [ILockable] at:\r\n\r\n" + new CallStack(2, true).ToString(), typeName);
                }
            }

#if !WINFULL
            // There appears to be some problems with [Monitor.TryEnter()] on Windows Phone and possibly
            // also on Silverlight where exclusive access cannot be obtained sometimes when there
            // are no other locks.  Simply replacing [TryEnter()] with [Enter()] fixes the problem and
            // since we were using [TryEnter()] only for enhanced diagnostics, removing this will
            // really doesn't change the programming model.  The only difference will be that WINFULL
            // builds will throw a [DeadlockException] when the lock timeout has been exceeded whereas
            // SILVERLIGHT and MOBILE_DEVICE builds will simply block forever in [Enter()]
            // for deadlocks.

            Monitor.Enter(target);
#else
            if (!Monitor.TryEnter(target, timeout))
            {
                var failStack = new CallStack(2, true);

#if LEAK_DETECTOR
                leakDetector.SuppressFinalize();
#endif
                if (fullDiagnostics)
                {
                    var lockable = target as ILockable;

                    if (lockable == null)
                    {
                        DumpAndBreak(target, null);
                        throw new DeadlockException(this, failStack, null, "#1");
                    }

                    lock (locks)
                    {
                        LockInfo info;

                        if (locks.TryGetValue(lockable.GetLockKey(), out info))
                        {
                            var diagnostics = GetDiagnosticInfo(info, failStack);

                            DumpAndBreak(target, diagnostics);
                            throw new DeadlockException(this, failStack, diagnostics, "#2");
                        }
                        else
                        {
                            DumpAndBreak(target, null);
                            throw new DeadlockException(this, failStack, null, "#3");
                        }
                    }
                }
                else
                {
                    DumpAndBreak(target, null);
                    throw new DeadlockException(this, failStack, null, "#4");
                }
            }
            else
            {
#if DEBUG
                var lockTime = DateTime.MinValue;

                if (excessiveHoldTime > 0)
                {
                    lockTime = SysTime.Now;
                }
#endif
                if (fullDiagnostics)
                {
                    lock (locks)
                    {
                        var lockable = target as ILockable;

                        if (lockable != null)
                        {
                            object   lockKey = lockable.GetLockKey();
                            LockInfo info;

                            if (!locks.TryGetValue(lockKey, out info))
                            {
                                locks.Add(lockKey, new LockInfo(target, new CallStack(2, true)));
                            }
                            else
                            {
                                info.LockCount++;
                            }
                        }
                    }
                }
#if DEBUG
                if (excessiveHoldTime > 0 && SysTime.Now - lockTime >= TimeSpan.FromMilliseconds(excessiveHoldTime))
                {
                    SysLog.LogErrorStackDump("Warning: Lock held for an excessive period of time: {0}ms", (SysTime.Now - lockTime).TotalMilliseconds);
                }
#endif
            }
#endif // WINFULL
        }