do not check order sequence if option /order was not used
[mono.git] / mcs / class / System / System.Threading / Barrier.cs
1 // 
2 // Barrier.cs
3 //  
4 // Author:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // 
7 // Copyright (c) 2009 Jérémie "Garuma" Laval
8 // 
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26
27 #if NET_4_0
28
29 using System;
30 using System.Diagnostics;
31
32 namespace System.Threading
33 {
34         [DebuggerDisplay ("Participant Count={ParticipantCount},Participants Remaining={ParticipantsRemaining}")]
35         public class Barrier : IDisposable
36         {
37                 const int MaxParticipants = 32767;
38                 Action<Barrier> postPhaseAction;
39                 
40                 int participants;
41                 bool cleaned;
42                 CountdownEvent cntd;
43                 ManualResetEventSlim postPhaseEvt = new ManualResetEventSlim ();
44                 long phase;
45                 
46                 public Barrier (int participantCount)
47                         : this (participantCount, null)
48                 {
49                 }
50                 
51                 public Barrier (int participantCount, Action<Barrier> postPhaseAction)
52                 {
53                         if (participantCount < 0 || participantCount > MaxParticipants)
54                                 throw new ArgumentOutOfRangeException ("participantCount");
55                         
56                         this.participants = participantCount;
57                         this.postPhaseAction = postPhaseAction;
58                         
59                         InitCountdownEvent ();
60                 }
61
62                 public void Dispose ()
63                 {
64                         Dispose (true);
65                 }
66
67                 protected virtual void Dispose (bool disposing)
68                 {
69                         if (disposing){
70                                 if (cntd != null){
71                                         cntd.Dispose ();
72                                         cntd = null;
73                                 }
74                                 postPhaseAction = null;
75                                 cleaned = true;
76                         }
77                 }
78                         
79                 void InitCountdownEvent ()
80                 {
81                         postPhaseEvt = new ManualResetEventSlim (false);
82                         cntd = new CountdownEvent (participants);
83                 }
84                 
85                 public long AddParticipant ()
86                 {
87                         return AddParticipants (1);
88                 }
89
90                 static Exception GetDisposed ()
91                 {
92                         return new ObjectDisposedException ("Barrier");
93                 }
94                 
95                 public long AddParticipants (int participantCount)
96                 {
97                         if (cleaned)
98                                 throw GetDisposed ();
99                         
100                         if (participantCount < 0)
101                                 throw new InvalidOperationException ();
102                         
103                         // Basically, we try to add ourselves and return
104                         // the phase. If the call return false, we repeatdly try
105                         // to add ourselves for the next phase
106                         do {
107                                 if (cntd.TryAddCount (participantCount)) {
108                                         Interlocked.Add (ref participants, participantCount);
109                                         return phase;
110                                 }
111                         } while (true);
112                 }
113                 
114                 public void RemoveParticipant ()
115                 {
116                         RemoveParticipants (1);
117                 }
118                 
119                 public void RemoveParticipants (int participantCount)
120                 {
121                         if (cleaned)
122                                 throw GetDisposed ();
123                         if (participantCount < 0)
124                                 throw new ArgumentOutOfRangeException ("participantCount");
125                         
126                         if (cntd.Signal (participantCount))
127                                 PostPhaseAction (postPhaseEvt);
128
129                         Interlocked.Add (ref participants, -participantCount);
130                 }
131                 
132                 public void SignalAndWait ()
133                 {
134                         if (cleaned)
135                                 throw GetDisposed ();
136                         SignalAndWait ((c) => { c.Wait (); return true; });
137                 }
138                 
139                 public void SignalAndWait (CancellationToken cancellationToken)
140                 {
141                         if (cleaned)
142                                 throw GetDisposed ();
143                         SignalAndWait ((c) => { c.Wait (cancellationToken); return true; });
144                 }
145
146                 public bool SignalAndWait (int millisecondsTimeout)
147                 {
148                         if (cleaned)
149                                 throw GetDisposed ();
150                         return SignalAndWait ((c) => c.Wait (millisecondsTimeout));
151                 }
152
153                 public bool SignalAndWait (TimeSpan timeout)
154                 {
155                         if (cleaned)
156                                 throw GetDisposed ();
157                         return SignalAndWait ((c) => c.Wait (timeout));
158                 }
159                 
160                 public bool SignalAndWait (int millisecondsTimeout, CancellationToken cancellationToken)
161                 {
162                         if (cleaned)
163                                 throw GetDisposed ();
164                         return SignalAndWait ((c) => c.Wait (millisecondsTimeout, cancellationToken));
165                 }
166                 
167                 public bool SignalAndWait (TimeSpan timeout, CancellationToken cancellationToken)
168                 {
169                         if (cleaned)
170                                 throw GetDisposed ();
171                         return SignalAndWait ((c) => c.Wait (timeout, cancellationToken));
172                 }
173                 
174                 bool SignalAndWait (Func<CountdownEvent, bool> associate)
175                 {
176                         bool result;
177                         CountdownEvent temp = cntd;
178                         ManualResetEventSlim evt = postPhaseEvt;
179                         
180                         if (!temp.Signal ()) {
181                                 result = Wait (associate, temp, evt);
182                         } else {
183                                 result = true;
184                                 PostPhaseAction (evt);
185                         }
186                         
187                         return result;
188                 }
189                 
190                 bool Wait (Func<CountdownEvent, bool> associate, CountdownEvent temp, ManualResetEventSlim evt)
191                 {
192                         if (!associate (temp))
193                                 return false;
194                         
195                         evt.Wait ();
196                         
197                         return true;
198                 }
199                 
200                 void PostPhaseAction (ManualResetEventSlim evt)
201                 {
202                         if (postPhaseAction != null) {
203                                 try {
204                                         postPhaseAction (this);
205                                 } catch (Exception e) {
206                                         throw new BarrierPostPhaseException (e);
207                                 }
208                         }
209                         
210                         InitCountdownEvent ();
211                         phase++;
212
213                         evt.Set ();
214                 }
215                 
216                 public long CurrentPhaseNumber {
217                         get {
218                                 return phase;
219                         }
220                 }
221                 
222                 public int ParticipantCount  {
223                         get {
224                                 return participants;
225                         }
226                 }
227                 
228                 [MonoTODO]
229                 public int ParticipantsRemaining {
230                         get {
231                                 return -1;
232                         }
233                 }
234         }
235 }
236 #endif