protected static void InlineIfPossibleOrElseQueue(Task task, bool needsProtection) { if (needsProtection) { if (!task.MarkStarted()) { return; } } else { task.m_stateFlags |= 65536; } try { if (task.m_taskScheduler.TryRunInline(task, false)) { return; } task.m_taskScheduler.InternalQueueTask(task); } catch (Exception ex) { if (ex is ThreadAbortException && (task.m_stateFlags & 134217728) != 0) { return; } TaskSchedulerException schedulerException = new TaskSchedulerException(ex); task.AddException((object)schedulerException); task.Finish(false); } }
internal bool InternalStart(TaskScheduler scheduler, bool inline, bool throwSchedulerExceptions) { ExecutingTaskScheduler = scheduler; var result = Interlocked.CompareExchange(ref _status, (int)TaskStatus.WaitingForActivation, (int)TaskStatus.Created); if (result != (int)TaskStatus.Created && result != (int)TaskStatus.WaitingForActivation) { return(false); } var didInline = false; try { if (inline) { // Should I worry about this task being a continuation? // WaitAntecedent(CancellationToken); didInline = scheduler.InternalTryExecuteTaskInline(this, IsScheduled); } if (!didInline) { scheduler.QueueTask(this); Interlocked.CompareExchange(ref _status, (int)TaskStatus.WaitingToRun, (int)TaskStatus.WaitingForActivation); } else { PrivateWait(CancellationToken, false); } } catch (ThreadAbortException exception) { if (didInline) { return(true); } AddException(exception); FinishThreadAbortedTask(true, false); } catch (Exception exception) { var taskSchedulerException = new TaskSchedulerException(exception); RecordException(taskSchedulerException); if (throwSchedulerExceptions) { throw taskSchedulerException; } } return(true); }
private void RecordException(TaskSchedulerException taskSchedulerException) { AddException(taskSchedulerException); Finish(false); if ((_internalOptions & InternalTaskOptions.ContinuationTask) != 0) { return; } if (_exceptionsHolder != null) { Contract.Assert(_exceptionsHolder.ContainsFaultList, "Expected _exceptionsHolder to have faults recorded."); _exceptionsHolder.MarkAsHandled(false); } else { Contract.Assert(false, "Expected _exceptionsHolder to exist."); } }
protected static void InlineIfPossibleOrElseQueue(Task task, bool needsProtection) { Contract.Requires(task != null); Contract.Assert(task.m_taskScheduler != null); // Set the TASK_STATE_STARTED flag. This only needs to be done // if the task may be canceled or if someone else has a reference to it // that may try to execute it. if (needsProtection) { if (!task.MarkStarted()) { return; // task has been previously started or canceled. Stop processing. } } else { task.m_stateFlags |= Task.TASK_STATE_STARTED; } // Try to inline it but queue if we can't try { if (!task.m_taskScheduler.TryRunInline(task, taskWasPreviouslyQueued: false)) { task.m_taskScheduler.InternalQueueTask(task); } } catch (Exception e) { // Either TryRunInline() or QueueTask() threw an exception. Record the exception, marking the task as Faulted. // However if it was a ThreadAbortException coming from TryRunInline we need to skip here, // because it would already have been handled in Task.Execute() if (!(e is ThreadAbortException && (task.m_stateFlags & Task.TASK_STATE_THREAD_WAS_ABORTED) != 0)) // this ensures TAEs from QueueTask will be wrapped in TSE { TaskSchedulerException tse = new TaskSchedulerException(e); task.AddException(tse); task.Finish(false); } // Don't re-throw. } }
internal bool InternalCancel(bool cancelNonExecutingOnly) { Contract.Requires((_internalOptions & InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); var cancelSucceeded = false; TaskSchedulerException taskSchedulerException = null; RecordInternalCancellationRequest(); var status = Thread.VolatileRead(ref _status); if (status <= (int)TaskStatus.WaitingToRun) { // Note: status may advance to TaskStatus.Running or even TaskStatus.RanToCompletion during the execution of this method var scheduler = Scheduler; var requiresAtomicStartTransition = scheduler.RequiresAtomicStartTransition; var popSucceeded = scheduler.InernalTryDequeue(this, ref requiresAtomicStartTransition); if (!popSucceeded && requiresAtomicStartTransition) { status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.Created); cancelSucceeded = status == (int)TaskStatus.Created; status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingForActivation); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingForActivation; status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingToRun); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingToRun; } } if (Thread.VolatileRead(ref _status) >= (int)TaskStatus.Running && !cancelNonExecutingOnly) { // We are going to pretend that the cancel call came after the task finished running, but we may still set to cancel on TaskStatus.WaitingForChildrenToComplete status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingForChildrenToComplete); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingForChildrenToComplete; } if (cancelSucceeded) { MarkCompleted(); FinishStageThree(); } if (taskSchedulerException != null) { throw taskSchedulerException; } return(cancelSucceeded); }
public static void RunTaskSchedulerExceptionTests() { TaskSchedulerException tse = null; tse = new TaskSchedulerException(); Assert.Null(tse.InnerException); // , "RunTaskSchedulerExceptionTests: Expected InnerException==null after empty ctor") InvalidOperationException ioe = new InvalidOperationException(); tse = new TaskSchedulerException(ioe); Assert.True(tse.InnerException == ioe, "RunTaskSchedulerExceptionTests: Expected InnerException == ioe passed to ctor(ex)"); string message = "my exception message"; tse = new TaskSchedulerException(message); Assert.Null(tse.InnerException); // , "RunTaskSchedulerExceptionTests: Expected InnerException==null after ctor(string)") Assert.True(tse.Message.Equals(message), "RunTaskSchedulerExceptionTests: Expected Message = message passed to ctor(string)"); tse = new TaskSchedulerException(message, ioe); Assert.True(tse.InnerException == ioe, "RunTaskSchedulerExceptionTests: Expected InnerException == ioe passed to ctor(string, ex)"); Assert.True(tse.Message.Equals(message), "RunTaskSchedulerExceptionTests: Expected Message = message passed to ctor(string, ex)"); }
private bool PrivateStart(TaskScheduler scheduler, bool inline, bool throwSchedulerExceptions) { Scheduler = scheduler; var result = Interlocked.CompareExchange(ref _status, (int)TaskStatus.WaitingForActivation, (int)TaskStatus.Created); if (result != (int)TaskStatus.Created && result != (int)TaskStatus.WaitingForActivation) { return false; } var didInline = false; try { if (inline) { didInline = scheduler.TryExecuteTaskInline(this, IsScheduled); } if (!didInline) { scheduler.QueueTask(this); Interlocked.CompareExchange(ref _status, (int)TaskStatus.WaitingToRun, (int)TaskStatus.WaitingForActivation); } else { PrivateWait(CancellationToken, false); } } catch (ThreadAbortException exception) { if (!didInline) { AddException(exception); FinishThreadAbortedTask(true, false); } } catch (Exception exception) { var taskSchedulerException = new TaskSchedulerException(exception); RecordException(taskSchedulerException); if (throwSchedulerExceptions) { throw taskSchedulerException; } } return true; }
internal bool InternalCancel(bool cancelNonExecutingOnly) { Contract.Requires((_internalOptions & InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); var popSucceeded = false; var cancelSucceeded = false; TaskSchedulerException taskSchedulerException = null; RecordInternalCancellationRequest(); var status = Thread.VolatileRead(ref _status); if (status <= (int)TaskStatus.WaitingToRun) { // Note: status may advance to TaskStatus.Running or even TaskStatus.RanToCompletion during the execution of this method var scheduler = Scheduler; var requiresAtomicStartTransition = scheduler.RequiresAtomicStartTransition; try { popSucceeded = scheduler.TryDequeue(this); } catch (Exception exception) { if (exception is InternalSpecialCancelException) { // Special path for ThreadPool requiresAtomicStartTransition = true; } else if (exception is ThreadAbortException) { // Ignore the exception } else { taskSchedulerException = new TaskSchedulerException(exception); } } if (!popSucceeded && requiresAtomicStartTransition) { status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.Created); cancelSucceeded = status == (int)TaskStatus.Created; status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingForActivation); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingForActivation; status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingToRun); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingToRun; } } if (Thread.VolatileRead(ref _status) >= (int)TaskStatus.Running && !cancelNonExecutingOnly) { // We are going to pretend that the cancel call came after the task finished running, but we may still set to cancel on TaskStatus.WaitingForChildrenToComplete status = Interlocked.CompareExchange(ref _status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingForChildrenToComplete); cancelSucceeded = cancelSucceeded || status == (int)TaskStatus.WaitingForChildrenToComplete; } if (cancelSucceeded) { SetCompleted(); FinishStageThree(); } if (taskSchedulerException != null) { throw taskSchedulerException; } return cancelSucceeded; }