public void WaitEventToResume(Object eventTargetToResume, long maxWaitTime, IBackgroundWorkerParamDelegate <IProcessResumeItem> resumeDelegate, IBackgroundWorkerParamDelegate <Exception> errorDelegate) { try { IdentityHashSet <Object> pendingSet = new IdentityHashSet <Object>(); if (eventTargetToResume is IEnumerable) { pendingSet.AddAll((IEnumerable)eventTargetToResume); } else { pendingSet.Add(eventTargetToResume); } WaitForResumeItem pauseItem = null; listenersWriteLock.Lock(); try { IList <Object> remainingPausedEventTargets = EvaluatePausedEventTargetsOfForeignThreads(); IdentityLinkedSet <Object> remainingPausedEventTargetsSet = new IdentityLinkedSet <Object>(remainingPausedEventTargets); remainingPausedEventTargetsSet.RetainAll(pendingSet); if (remainingPausedEventTargetsSet.Count > 0) { // We should wait now but we have to check if we are in the UI thread, which must never wait if (GuiThreadHelper.IsInGuiThread()) { // This is the trick: We "requeue" the current action in the UI pipeline to prohibit blocking GuiThreadHelper.InvokeInGuiLate(delegate() { WaitEventToResume(eventTargetToResume, maxWaitTime, resumeDelegate, errorDelegate); }); return; } pauseItem = new WaitForResumeItem(pendingSet); waitForResumeSet.Add(pauseItem); } } finally { listenersWriteLock.Unlock(); } if (pauseItem == null) { resumeDelegate.Invoke(null); return; } CountDownLatch latch = pauseItem.Latch; if (maxWaitTime < 0) { latch.Await(); } else if (maxWaitTime > 0) { latch.Await(TimeSpan.FromMilliseconds(maxWaitTime)); } else { throw new System.Exception("Thread should wait but does not want to"); } resumeDelegate.Invoke(pauseItem); } catch (Exception e) { if (Log.ErrorEnabled) { Log.Error(e); } if (errorDelegate != null) { errorDelegate.Invoke(e); } throw; } }
public void Resume(Object eventTarget) { if (GuiThreadHelper.IsInGuiThread()) { // Nothing to do return; } IEventTargetExtractor eventTargetExtractor = typeToEventTargetExtractorsDict.GetExtension(eventTarget.GetType()); if (eventTargetExtractor == null) { return; } eventTarget = eventTargetExtractor.ExtractEventTarget(eventTarget); if (eventTarget == null) { return; } IdentityLinkedSet <WaitForResumeItem> freeLatchMap = null; try { PausedEventTargetItem pauseETI; listenersWriteLock.Lock(); try { IdentityLinkedMap <Object, PausedEventTargetItem> pausedTargets = this.pausedTargets; pauseETI = pausedTargets.Get(eventTarget); if (pauseETI == null) { throw new System.Exception("No pause() active for target " + eventTarget); } pauseETI.PauseCount--; if (pauseETI.PauseCount > 0) { return; } pausedTargets.Remove(eventTarget); IList <Object> remainingPausedEventTargets = EvaluatePausedEventTargets(); IdentityHashSet <Object> remainingPausedEventTargetsSet = new IdentityHashSet <Object>(); Iterator <WaitForResumeItem> iter = waitForResumeSet.Iterator(); while (iter.MoveNext()) { WaitForResumeItem pauseItem = iter.Current; remainingPausedEventTargetsSet.AddAll(remainingPausedEventTargets); remainingPausedEventTargetsSet.RetainAll(pauseItem.PendingPauses); if (remainingPausedEventTargetsSet.Count == 0) { iter.Remove(); if (freeLatchMap == null) { freeLatchMap = new IdentityLinkedSet <WaitForResumeItem>(); } freeLatchMap.Add(pauseItem); } remainingPausedEventTargetsSet.Clear(); } } finally { listenersWriteLock.Unlock(); } } finally { if (freeLatchMap != null) { foreach (WaitForResumeItem wfrItem in freeLatchMap) { wfrItem.Latch.CountDown(); } foreach (WaitForResumeItem wfrItem in freeLatchMap) { try { wfrItem.ResultLatch.Await(); } catch (System.Exception e) { throw new System.Exception("Fatal state occured. This may result in a global deadlock", e); } } } } }