You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,102 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="CancellationTokenHelper.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Web.Util {
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
// Helper class for dealing with CancellationToken instances. Our Cancel and Dispose methods
|
||||
// are fully thread-safe and will never block or throw, while a normal CancellationTokenSource
|
||||
// doesn't make these guarantees.
|
||||
|
||||
internal sealed class CancellationTokenHelper : IDisposable {
|
||||
|
||||
private const int STATE_CREATED = 0;
|
||||
private const int STATE_CANCELING = 1;
|
||||
private const int STATE_CANCELED = 2;
|
||||
private const int STATE_DISPOSING = 3;
|
||||
private const int STATE_DISPOSED = 4; // terminal state
|
||||
|
||||
// A CancellationTokenHelper which is already marked as disposed; useful for avoiding
|
||||
// allocations of CancellationTokenHelper instances which are never observed.
|
||||
internal static readonly CancellationTokenHelper StaticDisposed = GetStaticDisposedHelper();
|
||||
|
||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
private int _state;
|
||||
|
||||
public CancellationTokenHelper(bool canceled) {
|
||||
if (canceled) {
|
||||
_cts.Cancel();
|
||||
}
|
||||
_state = (canceled) ? STATE_CANCELED : STATE_CREATED;
|
||||
}
|
||||
|
||||
internal bool IsCancellationRequested {
|
||||
get { return _cts.IsCancellationRequested; }
|
||||
}
|
||||
|
||||
internal CancellationToken Token {
|
||||
get { return _cts.Token; }
|
||||
}
|
||||
|
||||
// Cancels the token.
|
||||
public void Cancel() {
|
||||
if (Interlocked.CompareExchange(ref _state, STATE_CANCELING, STATE_CREATED) == STATE_CREATED) {
|
||||
// Only allow cancellation if the token hasn't yet been canceled or disposed.
|
||||
// Cancel on a ThreadPool thread so that we can release the original thread back to IIS.
|
||||
// We can use UnsafeQUWI to avoid an extra ExecutionContext capture since CancellationToken already captures it.
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => {
|
||||
try {
|
||||
_cts.Cancel();
|
||||
}
|
||||
catch {
|
||||
// ---- all exceptions to avoid killing the worker process.
|
||||
}
|
||||
finally {
|
||||
if (Interlocked.CompareExchange(ref _state, STATE_CANCELED, STATE_CANCELING) == STATE_DISPOSING) {
|
||||
// A call to Dispose() came in on another thread while we were in the middle of a cancel
|
||||
// operation. That thread will no-op, so we'll dispose of it here.
|
||||
_cts.Dispose();
|
||||
Interlocked.Exchange(ref _state, STATE_DISPOSED);
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Disposes of the token.
|
||||
public void Dispose() {
|
||||
// Only allow a single call to Dispose.
|
||||
int originalState = Interlocked.Exchange(ref _state, STATE_DISPOSING);
|
||||
switch (originalState) {
|
||||
case STATE_CREATED:
|
||||
case STATE_CANCELED:
|
||||
// If Cancel() hasn't yet been called or has already run to completion,
|
||||
// the underlying CTS guarantees that the Dispose method won't block
|
||||
// or throw, so we can just call it directly.
|
||||
_cts.Dispose();
|
||||
Interlocked.Exchange(ref _state, STATE_DISPOSED);
|
||||
break;
|
||||
|
||||
case STATE_DISPOSED:
|
||||
// If the object was already disposed, we need to reset the flag here
|
||||
// since we accidentally blew it away with the original Exchange.
|
||||
Interlocked.Exchange(ref _state, STATE_DISPOSED);
|
||||
break;
|
||||
|
||||
// Otherwise, the object is already canceling or disposing, so the
|
||||
// other thread will handle the call to Dispose().
|
||||
}
|
||||
}
|
||||
|
||||
private static CancellationTokenHelper GetStaticDisposedHelper() {
|
||||
CancellationTokenHelper helper = new CancellationTokenHelper(false);
|
||||
helper.Dispose();
|
||||
return helper;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user