static bool WaitInternal(int?msTimeout, Func <bool> condition) { bool timedOut = false; Debug.Assert(SynchronizationContext.Current is DispatcherSynchronizationContext); DispatcherFrame frame = new DispatcherFrame(); DispatcherHookEventHandler onOperationCompleted = null; Action popFrame = () => { frame.Continue = false; Dispatcher.CurrentDispatcher.Hooks.OperationCompleted -= onOperationCompleted; }; onOperationCompleted = (s, ea) => { if (condition()) { popFrame(); } }; Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { Dispatcher.CurrentDispatcher.Hooks.OperationCompleted += onOperationCompleted; })); if (msTimeout != null) { PumpTimer.DoLater(msTimeout.Value, () => { timedOut = true; popFrame(); }); } Dispatcher.PushFrame(frame); return(!timedOut); }
internal void EmitOperationPriorityChanged(DispatcherOperation op) { DispatcherHookEventHandler prio = this.OperationPriorityChanged; if (prio != null) { prio(this.owner, new DispatcherHookEventArgs(op)); } }
internal void EmitOperationAborted(DispatcherOperation op) { DispatcherHookEventHandler aborted = this.OperationAborted; if (aborted != null) { aborted(this.owner, new DispatcherHookEventArgs(op)); } }
internal void EmitOperationCompleted(DispatcherOperation op) { DispatcherHookEventHandler completed = this.OperationCompleted; if (completed != null) { completed(this.owner, new DispatcherHookEventArgs(op)); } }
internal void RaiseOperationAborted(Dispatcher dispatcher, DispatcherOperation operation) { DispatcherHookEventHandler operationAborted = _operationAborted; if (operationAborted != null) { operationAborted(dispatcher, new DispatcherHookEventArgs(operation)); } }
internal void EmitOperationPosted(DispatcherOperation op) { DispatcherHookEventHandler posted = OperationPosted; if (posted != null) { posted(owner, new DispatcherHookEventArgs(op)); } }
private void Watchdog() { while (!_shuttingDown) { _idleReached = false; Thread.Sleep(MaxBusy); if (!_idleReached && !Debugger.IsAttached) { //Make sure we don't see our own post monitoring! //TODO: should we sample more than once? #pragma warning disable 612,618 var thread = _dispatcher.Thread; thread.Suspend(); var timedOutTrace = new StackTrace(thread, false); thread.Resume(); #pragma warning restore 612,618 var postedOperations = new BlockingCollection <DispatcherOperation>(); DispatcherHookEventHandler hooksOnOperationPosted = null; const int maxOperationToLog = 100; hooksOnOperationPosted = delegate(object sender, DispatcherHookEventArgs e) { if (postedOperations.Count < maxOperationToLog) { postedOperations.Add(e.Operation); } else { _dispatcher.Hooks.OperationPosted -= hooksOnOperationPosted; } }; _dispatcher.Hooks.OperationPosted += hooksOnOperationPosted; var sb = new StringBuilder(); sb.AppendLine("Dispatcher is blocked:"); sb.AppendLine(timedOutTrace.ToString()); Thread.Sleep(SamplePeriod); //wait for some posts var nameGetter = typeof(DispatcherOperation).GetProperty("Name", BindingFlags.Default | BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true); foreach (var operation in postedOperations) { sb.AppendLine(nameGetter.Invoke(operation, new object[] { }).ToString()); } var message = sb.ToString(); Logger.Error(message); throw new OpenGammaException(message); //Should be caught by general error handler } } }
public static bool WaitOneAndPump(this WaitHandle handle, int millisecondsTimeout) { using (var operationPendingMre = new ManualResetEvent(false)) { bool result = false; Exception error = null; var startTick = Environment.TickCount; var handles = new[] { handle.SafeWaitHandle.DangerousGetHandle(), operationPendingMre.SafeWaitHandle.DangerousGetHandle() }; var dispatcher = Dispatcher.CurrentDispatcher; var frame = new DispatcherFrame(); var getTimeout = (Timeout.Infinite == millisecondsTimeout) ? new Func <uint>(() => INFINITE) : new Func <uint>(() => (uint)Math.Max(0, millisecondsTimeout + startTick - Environment.TickCount)); DispatcherHookEventHandler onOperationPosted = (s, e) => { // this may occur on a random thread, // trigger a helper event and // unblock MsgWaitForMultipleObjectsEx inside onDispatcherInactive operationPendingMre.Set(); }; DispatcherHookEventHandler onOperationCompleted = (s, e) => { // this should occur on the Dispather thread Debug.Assert(Thread.CurrentThread == dispatcher.Thread); // do an instant handle check var nativeResult = WaitForSingleObject(handles[0], 0); if (nativeResult == WAIT_OBJECT_0) { result = true; } else if (nativeResult == WAIT_ABANDONED_0) { error = new AbandonedMutexException(-1, handle); } else if (getTimeout() == 0) { result = false; } else if (nativeResult == WAIT_TIMEOUT) { return; } else { error = new InvalidOperationException("WaitForSingleObject"); } // end the nested Dispatcher loop frame.Continue = false; }; EventHandler onDispatcherInactive = (s, e) => { operationPendingMre.Reset(); // wait for the handle or a message var timeout = getTimeout(); var nativeResult = MsgWaitForMultipleObjectsEx( (uint)handles.Length, handles, timeout, QS_EVENTMASK, MWMO_INPUTAVAILABLE); if (nativeResult == WAIT_OBJECT_0) { result = true; // handle signalled } else if (nativeResult == WAIT_TIMEOUT) { result = false; // timed-out } else if (nativeResult == WAIT_ABANDONED_0) { error = new AbandonedMutexException(-1, handle); } else if (nativeResult != WAIT_OBJECT_0 + 1 && nativeResult != WAIT_OBJECT_0 + 2) { error = new InvalidOperationException("MsgWaitForMultipleObjectsEx"); } else { // a Windows message or a Dispatcher operation is pending if (timeout == 0) { result = false; // timed-out } else { return; } } // end the nested Dispatcher loop frame.Continue = false; }; dispatcher.Hooks.OperationCompleted += onOperationCompleted; dispatcher.Hooks.OperationPosted += onOperationPosted; dispatcher.Hooks.DispatcherInactive += onDispatcherInactive; try { // onDispatcherInactive will be called on the new frame, // as soon as Dispatcher becomes idle Dispatcher.PushFrame(frame); } finally { dispatcher.Hooks.OperationCompleted -= onOperationCompleted; dispatcher.Hooks.OperationPosted -= onOperationPosted; dispatcher.Hooks.DispatcherInactive -= onDispatcherInactive; } if (error != null) { throw error; } return(result); } }
public static bool WaitOneAndPump(this WaitHandle handle, int millisecondsTimeout) { using (var operationPendingMre = new ManualResetEvent(false)) { var result = false; var startTick = Environment.TickCount; var dispatcher = Dispatcher.CurrentDispatcher; var frame = new DispatcherFrame(); var handles = new[] { handle.SafeWaitHandle.DangerousGetHandle(), operationPendingMre.SafeWaitHandle.DangerousGetHandle() }; Action idleAction = () => operationPendingMre.Set(); DispatcherOperation idleOperation = null; Func <uint> getTimeout; if (Timeout.Infinite == millisecondsTimeout) { getTimeout = () => INFINITE; } else { getTimeout = () => (uint)Math.Max(0, millisecondsTimeout + startTick - Environment.TickCount); } DispatcherHookEventHandler onOperationPosted = (s, e) => { // this may occur on a random thread, // trigger a helper event and // unblock MsgWaitForMultipleObjectsEx inside onDispatcherInactive operationPendingMre.Set(); }; DispatcherHookEventHandler onOperationCompleted = (s, e) => { // this should be fired on the Dispather thread Debug.Assert(Thread.CurrentThread == dispatcher.Thread); // do an instant handle check var nativeResult = WaitForSingleObject(handles[0], 0); if (nativeResult == WAIT_OBJECT_0) { result = true; } else if (nativeResult == WAIT_ABANDONED_0) { throw new AbandonedMutexException(-1, handle); } else if (getTimeout() == 0) { result = false; } else if (nativeResult == WAIT_TIMEOUT) { return; } else { throw new InvalidOperationException("WaitForSingleObject"); } // end the nested Dispatcher loop frame.Continue = false; }; EventHandler onDispatcherInactive = (s, e) => { operationPendingMre.Reset(); // wait for the handle or a message var timeout = getTimeout(); var nativeResult = MsgWaitForMultipleObjectsEx( (uint)handles.Length, handles, timeout, QS_EVENTMASK, MWMO_INPUTAVAILABLE); if (nativeResult == WAIT_OBJECT_0) { // handle signalled result = true; } else if (nativeResult == WAIT_TIMEOUT) { // timed out result = false; } else if (nativeResult == WAIT_ABANDONED_0) { // abandonded mutex throw new AbandonedMutexException(-1, handle); } else if (nativeResult == WAIT_OBJECT_0 + 1) { // operation posted from another thread, yield to the frame loop return; } else if (nativeResult == WAIT_OBJECT_0 + 2) { // a Windows message if (getTimeout() > 0) { // message pending, yield to the frame loop idleOperation.Abort(); idleOperation = dispatcher.BeginInvoke(idleAction, DispatcherPriority.ApplicationIdle); return; } // timed out result = false; } else { // unknown result throw new InvalidOperationException("MsgWaitForMultipleObjectsEx"); } // end the nested Dispatcher loop frame.Continue = false; }; dispatcher.Hooks.OperationCompleted += onOperationCompleted; dispatcher.Hooks.OperationPosted += onOperationPosted; dispatcher.Hooks.DispatcherInactive += onDispatcherInactive; idleOperation = dispatcher.BeginInvoke(idleAction, DispatcherPriority.ApplicationIdle); try { // onDispatcherInactive will be called on the new frame, // as soon as Dispatcher becomes idle Dispatcher.PushFrame(frame); } finally { idleOperation.Abort(); dispatcher.Hooks.OperationCompleted -= onOperationCompleted; dispatcher.Hooks.OperationPosted -= onOperationPosted; dispatcher.Hooks.DispatcherInactive -= onDispatcherInactive; } return(result); } }