diff --git a/Implab/AbstractEvent.cs b/Implab/AbstractEvent.cs --- a/Implab/AbstractEvent.cs +++ b/Implab/AbstractEvent.cs @@ -77,19 +77,14 @@ namespace Implab { /// Исключение возникшее при выполнении операции /// Данное обещание уже выполнено protected void SetError(Exception error) { - while (error is PromiseTransientException) - error = error.InnerException; - - var isCancel = error is OperationCanceledException; - if (BeginTransit()) { - m_error = isCancel ? error.InnerException : error; - CompleteTransit(isCancel ? CANCELLED_STATE : REJECTED_STATE); + m_error = error; + CompleteTransit(REJECTED_STATE); Signal(); } else { WaitTransition(); - if (!isCancel || m_state == SUCCEEDED_STATE) + if (m_state == SUCCEEDED_STATE) throw new InvalidOperationException("The promise is already resolved"); } } @@ -140,11 +135,11 @@ namespace Implab { case SUCCEEDED_STATE: return; case CANCELLED_STATE: - throw new OperationCanceledException(); + throw new OperationCanceledException("The operation has been cancelled", m_error); case REJECTED_STATE: throw new TargetInvocationException(m_error); default: - throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); + throw new ApplicationException(String.Format("The promise state {0} is invalid", m_state)); } } #endregion diff --git a/Implab/AbstractPromise.cs b/Implab/AbstractPromise.cs --- a/Implab/AbstractPromise.cs +++ b/Implab/AbstractPromise.cs @@ -134,8 +134,8 @@ namespace Implab { } protected void SetResult() { - BeginSetResult(); - EndSetResult(); + if(BeginSetResult()) + EndSetResult(); } } } diff --git a/Implab/ActionChainTaskBase.cs b/Implab/ActionChainTaskBase.cs --- a/Implab/ActionChainTaskBase.cs +++ b/Implab/ActionChainTaskBase.cs @@ -20,34 +20,51 @@ namespace Implab { HandleErrorInternal(error); } - - public override void CancelOperation(Exception reason) { if (LockCancelation()) { + if (!(reason is OperationCanceledException)) + reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException(); + if (m_cancel != null) { try { - m_cancel(reason).On(SetResult, SetError, SetCancelled); + m_cancel(reason).On(SetResult, HandleErrorInternal, HandleCancelInternal); } catch (Exception err) { HandleErrorInternal(err); } } else { - SetCancelled(reason); + HandleErrorInternal(reason); } } } - protected void HandleErrorInternal(Exception error) { + void HandleCancelInternal(Exception reason) { + if (!(reason is OperationCanceledException)) + reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException(); + HandleErrorInternal(reason); + } + + void HandleErrorInternal(Exception error) { if (m_error != null) { try { var p = m_error(error); - p.On(SetResult,SetError,SetCancelled); + p.On(SetResult, SetError, SetCancelled); CancellationRequested(p.Cancel); } catch (Exception err) { - SetError(err); + error = err; } } else { + SetErrorInternal(error); + } + } + + void SetErrorInternal(Exception error) { + while (error is PromiseTransientException) + error = error.InnerException; + + if (error is OperationCanceledException) + SetCancelled(error); + else SetError(error); - } } protected bool LockCancelation() { diff --git a/Implab/Components/RunnableComponent.cs b/Implab/Components/RunnableComponent.cs --- a/Implab/Components/RunnableComponent.cs +++ b/Implab/Components/RunnableComponent.cs @@ -139,14 +139,7 @@ namespace Implab.Components { throw new PromiseTransientException(e); }, r => { - lock(m_stateMachine) { - if (m_pending == promise) { - Move(Commands.Fail); - m_pending = null; - m_lastError = new OperationCanceledException("The operation has been cancelled", r); - } - - } + // handle cancellation as exception throw new OperationCanceledException("The operation has been cancelled", r); } ); @@ -201,7 +194,7 @@ namespace Implab.Components { if (current == null) { stop.Resolve(); } else { - current.On(stop.Resolve, stop.Reject, stop.CancelOperation); + current.On(stop.Resolve, stop.Reject, e => stop.Resolve()); current.Cancel(); } }