Wrap always_inline and noinline attributes in compiler checks and use MSVC equivalent.
[mono.git] / mcs / class / corlib / System.Collections.Concurrent / ConcurrentQueue.cs
1 // ConcurrentQueue.cs
2 //
3 // Copyright (c) 2008 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 #if NET_4_0 || MOBILE
26
27 using System;
28 using System.Threading;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.Serialization;
32
33 namespace System.Collections.Concurrent
34 {
35
36         [System.Diagnostics.DebuggerDisplay ("Count={Count}")]
37         [System.Diagnostics.DebuggerTypeProxy (typeof (CollectionDebuggerView<>))]
38         public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IEnumerable<T>, ICollection,
39                                           IEnumerable
40         {
41                 class Node
42                 {
43                         public T Value;
44                         public Node Next;
45                 }
46                 
47                 Node head = new Node ();
48                 Node tail;
49                 int count;
50
51                 class NodeObjectPool : ObjectPool<Node> {
52                         protected override Node Creator ()
53                         {
54                                 return new Node ();
55                         }
56                 }
57                 static readonly NodeObjectPool pool = new NodeObjectPool ();
58
59                 static Node ZeroOut (Node node)
60                 {
61                         node.Value = default(T);
62                         node.Next = null;
63                         return node;
64                 }
65
66                 public ConcurrentQueue ()
67                 {
68                         tail = head;
69                 }
70                 
71                 public ConcurrentQueue (IEnumerable<T> collection): this()
72                 {
73                         foreach (T item in collection)
74                                 Enqueue (item);
75                 }
76                 
77                 public void Enqueue (T item)
78                 {
79                         Node node = pool.Take ();
80                         node.Value = item;
81                         
82                         Node oldTail = null;
83                         Node oldNext = null;
84                         
85                         bool update = false;
86                         while (!update) {
87                                 oldTail = tail;
88                                 oldNext = oldTail.Next;
89                                 
90                                 // Did tail was already updated ?
91                                 if (tail == oldTail) {
92                                         if (oldNext == null) {
93                                                 // The place is for us
94                                                 update = Interlocked.CompareExchange (ref tail.Next, node, null) == null;
95                                         } else {
96                                                 // another Thread already used the place so give him a hand by putting tail where it should be
97                                                 Interlocked.CompareExchange (ref tail, oldNext, oldTail);
98                                         }
99                                 }
100                         }
101                         // At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
102                         Interlocked.CompareExchange (ref tail, node, oldTail);
103
104                         Interlocked.Increment (ref count);
105                 }
106                 
107                 bool IProducerConsumerCollection<T>.TryAdd (T item)
108                 {
109                         Enqueue (item);
110                         return true;
111                 }
112
113                 public bool TryDequeue (out T result)
114                 {
115                         result = default (T);
116                         bool advanced = false;
117
118                         while (!advanced) {
119                                 Node oldHead = head;
120                                 Node oldTail = tail;
121                                 Node oldNext = oldHead.Next;
122                                 
123                                 if (oldHead == head) {
124                                         // Empty case ?
125                                         if (oldHead == oldTail) {       
126                                                 // This should be false then
127                                                 if (oldNext != null) {
128                                                         // If not then the linked list is mal formed, update tail
129                                                         Interlocked.CompareExchange (ref tail, oldNext, oldTail);
130                                                 }
131                                                 result = default (T);
132                                                 return false;
133                                         } else {
134                                                 result = oldNext.Value;
135                                                 advanced = Interlocked.CompareExchange (ref head, oldNext, oldHead) == oldHead;
136                                                 if (advanced)
137                                                         pool.Release (ZeroOut (oldHead));
138                                         }
139                                 }
140                         }
141
142                         Interlocked.Decrement (ref count);
143
144                         return true;
145                 }
146                 
147                 public bool TryPeek (out T result)
148                 {
149                         if (IsEmpty) {
150                                 result = default (T);
151                                 return false;
152                         }
153                         
154                         Node first = head.Next;
155                         result = first.Value;
156                         return true;
157                 }
158                 
159                 internal void Clear ()
160                 {
161                         count = 0;
162                         tail = head = new Node ();
163                 }
164                 
165                 IEnumerator IEnumerable.GetEnumerator ()
166                 {
167                         return (IEnumerator)InternalGetEnumerator ();
168                 }
169                 
170                 public IEnumerator<T> GetEnumerator ()
171                 {
172                         return InternalGetEnumerator ();
173                 }
174                 
175                 IEnumerator<T> InternalGetEnumerator ()
176                 {
177                         Node my_head = head;
178                         while ((my_head = my_head.Next) != null) {
179                                 yield return my_head.Value;
180                         }
181                 }
182                 
183                 void ICollection.CopyTo (Array array, int index)
184                 {
185                         if (array == null)
186                                 throw new ArgumentNullException ("array");
187                         if (array.Rank > 1)
188                                 throw new ArgumentException ("The array can't be multidimensional");
189                         if (array.GetLowerBound (0) != 0)
190                                 throw new ArgumentException ("The array needs to be 0-based");
191
192                         T[] dest = array as T[];
193                         if (dest == null)
194                                 throw new ArgumentException ("The array cannot be cast to the collection element type", "array");
195                         CopyTo (dest, index);
196                 }
197                 
198                 public void CopyTo (T[] array, int index)
199                 {
200                         if (array == null)
201                                 throw new ArgumentNullException ("array");
202                         if (index < 0)
203                                 throw new ArgumentOutOfRangeException ("index");
204                         if (index >= array.Length)
205                                 throw new ArgumentException ("index is equals or greather than array length", "index");
206
207                         IEnumerator<T> e = InternalGetEnumerator ();
208                         int i = index;
209                         while (e.MoveNext ()) {
210                                 if (i == array.Length - index)
211                                         throw new ArgumentException ("The number of elememts in the collection exceeds the capacity of array", "array");
212                                 array[i++] = e.Current;
213                         }
214                 }
215                 
216                 public T[] ToArray ()
217                 {
218                         return new List<T> (this).ToArray ();
219                 }
220                 
221                 bool ICollection.IsSynchronized {
222                         get { return true; }
223                 }
224
225                 bool IProducerConsumerCollection<T>.TryTake (out T item)
226                 {
227                         return TryDequeue (out item);
228                 }
229                 
230                 object syncRoot = new object();
231                 object ICollection.SyncRoot {
232                         get { return syncRoot; }
233                 }
234                 
235                 public int Count {
236                         get {
237                                 return count;
238                         }
239                 }
240                 
241                 public bool IsEmpty {
242                         get {
243                                 return count == 0;
244                         }
245                 }
246         }
247 }
248 #endif