in rd-net/Lifetimes/Lifetimes/LifetimeDefinition.cs [439:487]
public void Terminate()
{
if (IsEternal || Status > LifetimeStatus.Canceling)
return ;
Diagnostics(nameof(LifetimeStatus.Canceling));
var supportsTerminationUnderExecuting = AllowTerminationUnderExecution || ourAllowTerminationUnderExecutionThreadStatic > 0;
if (!supportsTerminationUnderExecuting && ThreadLocalExecuting() > 0)
throw new InvalidOperationException($"{this}: can't terminate under `ExecuteIfAlive` because termination doesn't support this. Use `{nameof(AllowTerminationUnderExecution)}` or `{nameof(Lifetime.UsingAllowTerminationUnderExecution)}`.");
//parent could ask for canceled already
MarkCancelingRecursively();
var terminationTimeoutMs = GetTerminationTimeoutMs(TerminationTimeoutKind);
if (ourExecutingSlice[myState] > 0 /*optimization*/ && !SpinWait.SpinUntil(() => ourExecutingSlice[myState] <= ThreadLocalExecuting(), terminationTimeoutMs))
{
Log.Warn($"{this}: can't wait for `ExecuteIfAlive` completed on other thread in {terminationTimeoutMs} ms. Keep termination." + Environment.NewLine
+ "This may happen either because of the ExecuteIfAlive failed to complete in a timely manner. In the case there will be following error messages." + Environment.NewLine
+ "This is also possible if the thread waiting for the termination wasn't able to receive execution time during the wait in SpinWait.spinUntil, so it has missed the fact that the lifetime was terminated in time.");
if (AdditionalDiagnostics is { } additionalDiagnostics)
{
try
{
ourAdditionalDiagnosticsStorage.AddData(this, additionalDiagnostics.GetAdditionalDiagnosticsIfExecutionWasNotCancelledByTimeoutAsync(Lifetime));
}
catch (Exception e)
{
Log.Error(e);
}
}
ourLogErrorAfterExecution.InterlockedUpdate(ref myState, true);
}
if (!IncrementStatusIfEqualsTo(LifetimeStatus.Canceling))
return;
Diagnostics(nameof(LifetimeStatus.Terminating));
//Now status is 'Terminating' and we have to wait for all resource modifications to complete. No mutex acquire is possible beyond this point.
if (ourMutexSlice[myState]) //optimization
SpinWaitEx.SpinUntil(() => !ourMutexSlice[myState]);
Destruct();
if (Mode.IsAssertion) Assertion.Assert(Status == LifetimeStatus.Terminated, "{0}: bad status for termination finish", this);
Diagnostics(nameof(LifetimeStatus.Terminated));
}