Merge pull request #757 from mlintner/master
[mono.git] / mcs / class / System.Web.Mvc3 / Mvc / Async / TriggerListener.cs
1 namespace System.Web.Mvc.Async {
2     using System;
3     using System.Threading;
4
5     // This class is used to wait for triggers and a continuation. When the continuation has been provded
6     // and all triggers have been fired, the continuation is called. Similar to WaitHandle.WaitAll().
7     // New instances of this type are initially in the inactive state; activation is enabled by a call
8     // to Activate().
9
10     // This class is thread-safe.
11
12     internal sealed class TriggerListener {
13
14         private readonly Trigger _activateTrigger;
15         private volatile Action _continuation;
16         private readonly SingleEntryGate _continuationFiredGate = new SingleEntryGate();
17         private int _outstandingTriggers;
18         private readonly Trigger _setContinuationTrigger;
19
20         public TriggerListener() {
21             _activateTrigger = CreateTrigger();
22             _setContinuationTrigger = CreateTrigger();
23         }
24
25         public void Activate() {
26             _activateTrigger.Fire();
27         }
28
29         public Trigger CreateTrigger() {
30             Interlocked.Increment(ref _outstandingTriggers);
31
32             SingleEntryGate triggerFiredGate = new SingleEntryGate();
33             return new Trigger(() => {
34                 if (triggerFiredGate.TryEnter()) {
35                     HandleTriggerFired();
36                 }
37             });
38         }
39
40         private void HandleTriggerFired() {
41             if (Interlocked.Decrement(ref _outstandingTriggers) == 0) {
42                 if (_continuationFiredGate.TryEnter()) {
43                     _continuation();
44                 }
45             }
46         }
47
48         public void SetContinuation(Action continuation) {
49             if (continuation != null) {
50                 _continuation = continuation;
51                 _setContinuationTrigger.Fire();
52             }
53         }
54
55     }
56 }