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,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="BackgroundWorkScheduler.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Web.Hosting {
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Util;
|
||||
|
||||
internal sealed class BackgroundWorkScheduler : IRegisteredObject {
|
||||
|
||||
private readonly CancellationTokenHelper _cancellationTokenHelper = new CancellationTokenHelper(canceled: false);
|
||||
private int _numExecutingWorkItems; // number of executing work items, not scheduled work items; a work item might never be scheduled
|
||||
private readonly Action<BackgroundWorkScheduler> _unregisterCallback;
|
||||
private readonly Action<AppDomain, Exception> _logCallback;
|
||||
private readonly Action _workItemCompleteCallback;
|
||||
|
||||
internal BackgroundWorkScheduler(Action<BackgroundWorkScheduler> unregisterCallback, Action<AppDomain, Exception> logCallback, Action workItemCompleteCallback = null) {
|
||||
Debug.Assert(unregisterCallback != null);
|
||||
_unregisterCallback = unregisterCallback;
|
||||
_logCallback = logCallback;
|
||||
_workItemCompleteCallback = workItemCompleteCallback;
|
||||
}
|
||||
|
||||
private void FinalShutdown() {
|
||||
_unregisterCallback(this);
|
||||
}
|
||||
|
||||
// we can use 'async void' here since we're guaranteed to be off the AspNetSynchronizationContext
|
||||
private async void RunWorkItemImpl(Func<CancellationToken, Task> workItem) {
|
||||
Task returnedTask = null;
|
||||
try {
|
||||
returnedTask = workItem(_cancellationTokenHelper.Token);
|
||||
await returnedTask.ConfigureAwait(continueOnCapturedContext: false);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// ---- exceptions caused by the returned task being canceled
|
||||
if (returnedTask != null && returnedTask.IsCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- exceptions caused by CancellationToken.ThrowIfCancellationRequested()
|
||||
OperationCanceledException operationCanceledException = ex as OperationCanceledException;
|
||||
if (operationCanceledException != null && operationCanceledException.CancellationToken == _cancellationTokenHelper.Token) {
|
||||
return;
|
||||
}
|
||||
|
||||
_logCallback(AppDomain.CurrentDomain, ex); // method shouldn't throw
|
||||
}
|
||||
finally {
|
||||
WorkItemComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public void ScheduleWorkItem(Func<CancellationToken, Task> workItem) {
|
||||
Debug.Assert(workItem != null);
|
||||
|
||||
if (_cancellationTokenHelper.IsCancellationRequested) {
|
||||
return; // we're not going to run this work item
|
||||
}
|
||||
|
||||
// Unsafe* since we want to get rid of Principal and other constructs specific to the current ExecutionContext
|
||||
ThreadPool.UnsafeQueueUserWorkItem(state => {
|
||||
lock (this) {
|
||||
if (_cancellationTokenHelper.IsCancellationRequested) {
|
||||
return; // we're not going to run this work item
|
||||
}
|
||||
else {
|
||||
_numExecutingWorkItems++;
|
||||
}
|
||||
}
|
||||
|
||||
RunWorkItemImpl((Func<CancellationToken, Task>)state);
|
||||
}, workItem);
|
||||
}
|
||||
|
||||
public void Stop(bool immediate) {
|
||||
// Hold the lock for as little time as possible
|
||||
int currentWorkItemCount;
|
||||
lock (this) {
|
||||
_cancellationTokenHelper.Cancel(); // dispatched onto a new thread
|
||||
currentWorkItemCount = _numExecutingWorkItems;
|
||||
}
|
||||
|
||||
if (currentWorkItemCount == 0) {
|
||||
// There was no scheduled work, so we're done
|
||||
FinalShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void WorkItemComplete() {
|
||||
// Hold the lock for as little time as possible
|
||||
int newWorkItemCount;
|
||||
bool isCancellationRequested;
|
||||
lock (this) {
|
||||
newWorkItemCount = --_numExecutingWorkItems;
|
||||
isCancellationRequested = _cancellationTokenHelper.IsCancellationRequested;
|
||||
}
|
||||
|
||||
// for debugging & unit tests
|
||||
if (_workItemCompleteCallback != null) {
|
||||
_workItemCompleteCallback();
|
||||
}
|
||||
|
||||
if (newWorkItemCount == 0 && isCancellationRequested) {
|
||||
// Cancellation was requested, and we were the last work item to complete, so everybody is finished
|
||||
FinalShutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user