1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc.Async {
\r
15 using System.Threading;
\r
17 // This class is used to wait for triggers and a continuation. When the continuation has been provded
\r
18 // and all triggers have been fired, the continuation is called. Similar to WaitHandle.WaitAll().
\r
19 // New instances of this type are initially in the inactive state; activation is enabled by a call
\r
22 // This class is thread-safe.
\r
24 internal sealed class TriggerListener {
\r
26 private readonly Trigger _activateTrigger;
\r
27 private volatile Action _continuation;
\r
28 private readonly SingleEntryGate _continuationFiredGate = new SingleEntryGate();
\r
29 private int _outstandingTriggers;
\r
30 private readonly Trigger _setContinuationTrigger;
\r
32 public TriggerListener() {
\r
33 _activateTrigger = CreateTrigger();
\r
34 _setContinuationTrigger = CreateTrigger();
\r
37 public void Activate() {
\r
38 _activateTrigger.Fire();
\r
41 public Trigger CreateTrigger() {
\r
42 Interlocked.Increment(ref _outstandingTriggers);
\r
44 SingleEntryGate triggerFiredGate = new SingleEntryGate();
\r
45 return new Trigger(() => {
\r
46 if (triggerFiredGate.TryEnter()) {
\r
47 HandleTriggerFired();
\r
52 private void HandleTriggerFired() {
\r
53 if (Interlocked.Decrement(ref _outstandingTriggers) == 0) {
\r
54 if (_continuationFiredGate.TryEnter()) {
\r
60 public void SetContinuation(Action continuation) {
\r
61 if (continuation != null) {
\r
62 _continuation = continuation;
\r
63 _setContinuationTrigger.Fire();
\r