public void NotifyUnhandledException(Exception exception, ActivityInstance source) { Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in NotifyUnhandledException."); this.activityExecutor.NotifyUnhandledException(exception, source); }
public void SchedulerIdle() { Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in SchedulerIdle."); this.activityExecutor.OnSchedulerIdle(); }
public void ThreadAcquired() { Fx.Assert(this.activityExecutor != null, "ActivityExecutor null in ThreadAcquired."); this.activityExecutor.OnSchedulerThreadAcquired(); }
internal void Open(Scheduler oldScheduler) { Fx.Assert(this.synchronizationContext == null, "can only open when in the created state"); this.synchronizationContext = SynchronizationContextHelper.CloneSynchronizationContext(oldScheduler.synchronizationContext); }
private static void OnScheduledWork(object state) { Scheduler thisPtr = (Scheduler)state; // We snapshot these values here so that we can // use them after calling OnSchedulerIdle. //bool isTracingEnabled = FxTrace.Trace.ShouldTraceToTraceSource(TraceEventLevel.Informational); Guid oldActivityId = Guid.Empty; Guid workflowInstanceId = Guid.Empty; //if (isTracingEnabled) //{ // oldActivityId = DiagnosticTraceBase.ActivityId; // workflowInstanceId = thisPtr.callbacks.WorkflowInstanceId; // FxTrace.Trace.SetAndTraceTransfer(workflowInstanceId, true); // if (thisPtr.resumeTraceRequired) // { // if (TD.WorkflowActivityResumeIsEnabled()) // { // TD.WorkflowActivityResume(workflowInstanceId); // } // } //} thisPtr.callbacks.ThreadAcquired(); RequestedAction nextAction = continueAction; bool idleOrPaused = false; while (object.ReferenceEquals(nextAction, continueAction)) { if (thisPtr.IsIdle || thisPtr.isPausing) { idleOrPaused = true; break; } // cycle through (queue->thisPtr.firstWorkItem->currentWorkItem) WorkItem currentWorkItem = thisPtr.firstWorkItem; // promote an item out of our work queue if necessary if (thisPtr.workItemQueue != null && thisPtr.workItemQueue.Count > 0) { thisPtr.firstWorkItem = thisPtr.workItemQueue.Dequeue(); } else { thisPtr.firstWorkItem = null; } if (TD.ExecuteWorkItemStartIsEnabled()) { TD.ExecuteWorkItemStart(); } nextAction = thisPtr.callbacks.ExecuteWorkItem(currentWorkItem); if (TD.ExecuteWorkItemStopIsEnabled()) { TD.ExecuteWorkItemStop(); } } bool notifiedCompletion = false; bool isInstanceComplete = false; if (idleOrPaused || object.ReferenceEquals(nextAction, abortAction)) { thisPtr.isPausing = false; thisPtr.isRunning = false; thisPtr.NotifyWorkCompletion(); notifiedCompletion = true; //if (isTracingEnabled) //{ // isInstanceComplete = thisPtr.callbacks.IsCompleted; //} // After calling SchedulerIdle we no longer have the lock. That means // that any subsequent processing in this method won't have the single // threaded guarantee. thisPtr.callbacks.SchedulerIdle(); } else if (!object.ReferenceEquals(nextAction, yieldSilentlyAction)) { Fx.Assert(nextAction is NotifyUnhandledExceptionAction, "This is the only other option"); NotifyUnhandledExceptionAction notifyAction = (NotifyUnhandledExceptionAction)nextAction; // We only set isRunning back to false so that the host doesn't // have to treat this like a pause notification. As an example, // a host could turn around and call run again in response to // UnhandledException without having to go through its operation // dispatch loop first (or request pause again). If we reset // isPausing here then any outstanding operations wouldn't get // signaled with that type of host. thisPtr.isRunning = false; thisPtr.NotifyWorkCompletion(); notifiedCompletion = true; //if (isTracingEnabled) //{ // isInstanceComplete = thisPtr.callbacks.IsCompleted; //} thisPtr.callbacks.NotifyUnhandledException(notifyAction.Exception, notifyAction.Source); } //if (isTracingEnabled) //{ // if (notifiedCompletion) // { // if (isInstanceComplete) // { // if (TD.WorkflowActivityStopIsEnabled()) // { // TD.WorkflowActivityStop(workflowInstanceId); // } // } // else // { // if (TD.WorkflowActivitySuspendIsEnabled()) // { // TD.WorkflowActivitySuspend(workflowInstanceId); // } // } // } // DiagnosticTraceBase.ActivityId = oldActivityId; //} }
public void OnDeserialized(Callbacks callbacks) { Initialize(callbacks); Fx.Assert(this.firstWorkItem != null || this.workItemQueue == null, "cannot have items in the queue unless we also have a firstWorkItem set"); }
// This method should only be called when we relinquished the thread but did not // complete the operation (silent yield is the current example) public void InternalResume(RequestedAction action) { Fx.Assert(this.isRunning, "We should still be processing work - we just don't have a thread"); bool isTracingEnabled = FxTrace.ShouldTraceInformation; bool notifiedCompletion = false; bool isInstanceComplete = false; if (this.callbacks.IsAbortPending) { this.isPausing = false; this.isRunning = false; this.NotifyWorkCompletion(); notifiedCompletion = true; if (isTracingEnabled) { isInstanceComplete = this.callbacks.IsCompleted; } // After calling SchedulerIdle we no longer have the lock. That means // that any subsequent processing in this method won't have the single // threaded guarantee. this.callbacks.SchedulerIdle(); } else if (object.ReferenceEquals(action, continueAction)) { ScheduleWork(false); } else { Fx.Assert(action is NotifyUnhandledExceptionAction, "This is the only other choice because we should never have YieldSilently here"); NotifyUnhandledExceptionAction notifyAction = (NotifyUnhandledExceptionAction)action; // We only set isRunning back to false so that the host doesn't // have to treat this like a pause notification. As an example, // a host could turn around and call run again in response to // UnhandledException without having to go through its operation // dispatch loop first (or request pause again). If we reset // isPausing here then any outstanding operations wouldn't get // signaled with that type of host. this.isRunning = false; this.NotifyWorkCompletion(); notifiedCompletion = true; if (isTracingEnabled) { isInstanceComplete = this.callbacks.IsCompleted; } this.callbacks.NotifyUnhandledException(notifyAction.Exception, notifyAction.Source); } if (isTracingEnabled) { if (notifiedCompletion) { Guid oldActivityId = Guid.Empty; bool resetId = false; if (isInstanceComplete) { if (TD.WorkflowActivityStopIsEnabled()) { oldActivityId = WfEventSource.CurrentThreadActivityId; WfEventSource.SetCurrentThreadActivityId(this.callbacks.WorkflowInstanceId); resetId = true; TD.WorkflowActivityStop(this.callbacks.WorkflowInstanceId); } } else { if (TD.WorkflowActivitySuspendIsEnabled()) { oldActivityId = WfEventSource.CurrentThreadActivityId; WfEventSource.SetCurrentThreadActivityId(this.callbacks.WorkflowInstanceId); resetId = true; TD.WorkflowActivitySuspend(this.callbacks.WorkflowInstanceId); } } if (resetId) { WfEventSource.SetCurrentThreadActivityId(oldActivityId); } } } }
protected void Complete(bool completedSynchronously) { if (_isCompleted) { throw Fx.Exception.AsError(new InvalidOperationException(SR.AsyncResultCompletedTwice(GetType()))); } //#if DEBUG // this.marker.AsyncResult = null; // this.marker = null; // if (!Fx.FastDebug && completeStack == null) // { // completeStack = new StackTrace(); // } //#endif _completedSynchronously = completedSynchronously; if (OnCompleting != null) { // Allow exception replacement, like a catch/throw pattern. try { OnCompleting(this, _exception); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } _exception = exception; } } if (completedSynchronously) { // If we completedSynchronously, then there's no chance that the manualResetEvent was created so // we don't need to worry about a race condition Fx.Assert(_manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult."); _isCompleted = true; } else { lock (ThisLock) { _isCompleted = true; if (_manualResetEvent != null) { _manualResetEvent.Set(); } } } if (_callback != null) { try { if (VirtualCallback != null) { VirtualCallback(_callback, this); } else { _callback(this); } } #pragma warning disable 1634 #pragma warning suppress 56500 // transferring exception to another thread catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw Fx.Exception.AsError(new CallbackException(SR.AsyncCallbackThrewException, e)); } #pragma warning restore 1634 } }
private void ScheduleCallback(Action <object> callback) { Fx.Assert(callback != null, "Cannot schedule a null callback"); Task.Factory.StartNew(callback, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); }
public BookmarkResumptionResult TryGenerateWorkItem(ActivityExecutor executor, ref Bookmark bookmark, BookmarkScope scope, object value, ActivityInstance isolationInstance, bool nonScopedBookmarksExist, out ActivityExecutionWorkItem workItem) { Fx.Assert(scope != null, "We should never have a null sub instance."); workItem = null; BookmarkScope lookupScope = scope; if (scope.IsDefault) { lookupScope = this.defaultScope; } // We don't really care about the return value since we'll // use null to know we should check uninitialized sub instances this.bookmarkManagers.TryGetValue(lookupScope, out BookmarkManager manager); if (manager == null) { Fx.Assert(lookupScope != null, "The sub instance should not be default if we are here."); BookmarkResumptionResult finalResult = BookmarkResumptionResult.NotFound; // Check the uninitialized sub instances for a matching bookmark if (this.uninitializedScopes != null) { for (int i = 0; i < this.uninitializedScopes.Count; i++) { BookmarkScope uninitializedScope = this.uninitializedScopes[i]; Fx.Assert(this.bookmarkManagers.ContainsKey(uninitializedScope), "We must always have the uninitialized sub instances."); BookmarkResumptionResult resumptionResult; if (!this.bookmarkManagers[uninitializedScope].TryGetBookmarkFromInternalList(bookmark, out Bookmark internalBookmark, out BookmarkCallbackWrapper callbackWrapper)) { resumptionResult = BookmarkResumptionResult.NotFound; } else if (IsExclusiveScopeUnstable(internalBookmark)) { resumptionResult = BookmarkResumptionResult.NotReady; } else { resumptionResult = this.bookmarkManagers[uninitializedScope].TryGenerateWorkItem(executor, true, ref bookmark, value, isolationInstance, out workItem); } if (resumptionResult == BookmarkResumptionResult.Success) { // We are using InitializeBookmarkScopeWithoutKeyAssociation because we know this is a new uninitialized scope and // the key we would associate is already associated. And if we did the association here, the subsequent call to // FlushBookmarkScopeKeys would try to flush it out, but it won't have the transaction correct so will hang waiting for // the transaction that has the PersistenceContext locked to complete. But it won't complete successfully until // we finish processing here. InitializeBookmarkScopeWithoutKeyAssociation(uninitializedScope, scope.Id); // We've found what we were looking for return(BookmarkResumptionResult.Success); } else if (resumptionResult == BookmarkResumptionResult.NotReady) { // This uninitialized sub-instance has a matching bookmark but // it can't currently be resumed. We won't return BookmarkNotFound // because of this. finalResult = BookmarkResumptionResult.NotReady; } else { if (finalResult == BookmarkResumptionResult.NotFound) { // If we still are planning on returning failure then // we'll incur the cost of seeing if this scope is // stable or not. if (!IsStable(uninitializedScope, nonScopedBookmarksExist)) { // There exists an uninitialized scope which is unstable. // At the very least this means we'll return NotReady since // this uninitialized scope might eventually contain this // bookmark. finalResult = BookmarkResumptionResult.NotReady; } } } } }
// this isn't just public for performance reasons. We avoid the virtual call // by going through Dispose() protected virtual void ReleaseToPool(ActivityExecutor executor) { Fx.Assert("This should never be called ... only overridden versions should get called."); }
public IOAsyncResult(PersistencePipeline pipeline, bool isLoad, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { _pipeline = pipeline; _isLoad = isLoad; _pendingModules = _pipeline._modules.Where(value => value.IsIOParticipant).ToArray(); _remainingModules = _pendingModules.Length; bool completeSelf = false; if (_pendingModules.Length == 0) { completeSelf = true; } else { for (int i = 0; i < _pendingModules.Length; i++) { Fx.Assert(!completeSelf, "Shouldn't have been completed yet."); IPersistencePipelineModule module = _pendingModules[i]; IAsyncResult result = null; try { if (_isLoad) { result = module.BeginOnLoad(_pipeline._readWriteView, timeout, Fx.ThunkCallback(new AsyncCallback(OnIOComplete)), i); } else { result = module.BeginOnSave(_pipeline._readWriteView, _pipeline._writeOnlyView, timeout, Fx.ThunkCallback(new AsyncCallback(OnIOComplete)), i); } } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } _pendingModules[i] = null; ProcessException(exception); } if (result == null) { if (CompleteOne()) { completeSelf = true; } } else if (result.CompletedSynchronously) { _pendingModules[i] = null; if (IOComplete(result, module)) { completeSelf = true; } } } } if (completeSelf) { Complete(true, _exception); } }
public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) { Fx.Assert("Empty work items should never been executed."); return(true); }
public FatalException(string message, Exception innerException) : base(message, innerException) { // This can't throw something like ArgumentException because that would be worse than // throwing the fatal exception that was requested. Fx.Assert(innerException == null || !Fx.IsFatal(innerException), "FatalException can't be used to wrap fatal exceptions."); }