Update mcs/class/Commons.Xml.Relaxng/Commons.Xml.Relaxng/RelaxngPattern.cs
[mono.git] / mcs / class / System.Threading.Tasks.Dataflow / System.Threading.Tasks.Dataflow / TargetBuffer.cs
1 // TargetBuffer.cs
2 //
3 // Copyright (c) 2011 Jérémie "garuma" Laval
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 //
24
25
26 using System;
27 using System.Linq;
28 using System.Threading.Tasks;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Concurrent;
32
33 namespace System.Threading.Tasks.Dataflow
34 {
35         internal class TargetBuffer<T> : IEnumerable<ITargetBlock<T>>
36         {
37                 ConcurrentQueue<TargetWaiter> targetWaiters = new ConcurrentQueue<TargetWaiter> ();
38
39                 class TargetWaiter : IDisposable
40                 {
41                         public volatile bool Disabled;
42                         public readonly ITargetBlock<T> Target;
43                         public readonly bool UnlinkAfterOne;
44                         
45                         ConcurrentQueue<TargetWaiter> queue;
46                         AtomicBooleanValue removed;
47
48                         public TargetWaiter (ITargetBlock<T> target, bool unlinkAfterOne, ConcurrentQueue<TargetWaiter> queue)
49                         {
50                                 Target = target;
51                                 UnlinkAfterOne = unlinkAfterOne;
52                                 this.queue = queue;
53                         }
54
55                         public void Dispose ()
56                         {
57                                 TargetWaiter t;
58                                 Disabled = true;
59
60                                 Thread.MemoryBarrier ();
61
62                                 if (queue.TryPeek (out t) && t == this && removed.TryRelaxedSet ()) {
63                                         queue.TryDequeue (out t);
64                                 } else {
65                                         SpinWait wait = new SpinWait ();
66                                         while (queue.TryPeek (out t) && t == this)
67                                                 wait.SpinOnce ();
68                                 }
69                         }
70                 }
71
72                 public IDisposable AddTarget (ITargetBlock<T> block, bool unlinkAfterOne)
73                 {
74                         TargetWaiter w = new TargetWaiter (block, unlinkAfterOne, targetWaiters);
75                         targetWaiters.Enqueue (w);
76
77                         return w;
78                 }
79
80                 public ITargetBlock<T> Current {
81                         get {
82                                 TargetWaiter w;
83                                 
84                                 while (true) {
85                                         if (!targetWaiters.TryPeek (out w))
86                                                 return null;
87
88                                         if (w.Disabled == true) {
89                                                 w.Dispose ();
90                                                 continue;
91                                         } else if (w.UnlinkAfterOne) {
92                                                 w.Dispose ();
93                                         }
94
95                                         return w.Target;
96                                 }
97                         }
98                 }
99
100                 public IEnumerator<ITargetBlock<T>> GetEnumerator ()
101                 {
102                         return targetWaiters.Select (w => w.Target).GetEnumerator ();
103                 }
104
105                 IEnumerator IEnumerable.GetEnumerator ()
106                 {
107                         return targetWaiters.Select (w => w.Target).GetEnumerator ();
108                 }
109         }
110 }
111