[NUI] Rebase develnui (DevelNUI only patches --> master) (#3910)
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.Devel.Tests.Ubuntu / nunit.framework / Internal / Execution / EventQueue.cs
1 // ***********************************************************************
2 // Copyright (c) 2007-2016 Charlie Poole
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
23 #define PORTABLE
24 #define TIZEN
25 #define NUNIT_FRAMEWORK
26 #define NUNITLITE
27 #define NET_4_5
28 #define PARALLEL
29 #if PARALLEL
30 using System;
31 using System.Collections;
32 using System.Collections.Concurrent;
33 using System.Globalization;
34 //using System.Runtime.Serialization;
35 using System.Threading;
36 #if NET_2_0 || NET_3_5 || NETCF
37 using ManualResetEventSlim = System.Threading.ManualResetEvent;
38 #endif
39 using NUnit.Framework.Interfaces;
40
41 namespace NUnit.Framework.Internal.Execution
42 {
43
44 #region Individual Event Classes
45
46     /// <summary>
47     /// NUnit.Core.Event is the abstract base for all stored events.
48     /// An Event is the stored representation of a call to the
49     /// ITestListener interface and is used to record such calls
50     /// or to queue them for forwarding on another thread or at
51     /// a later time.
52     /// </summary>
53     public abstract class Event
54     {
55         /// <summary>
56         /// The Send method is implemented by derived classes to send the event to the specified listener.
57         /// </summary>
58         /// <param name="listener">The listener.</param>
59         public abstract void Send(ITestListener listener);
60     }
61
62     /// <summary>
63     /// TestStartedEvent holds information needed to call the TestStarted method.
64     /// </summary>
65     public class TestStartedEvent : Event
66     {
67         private readonly ITest _test;
68
69         /// <summary>
70         /// Initializes a new instance of the <see cref="TestStartedEvent"/> class.
71         /// </summary>
72         /// <param name="test">The test.</param>
73         public TestStartedEvent(ITest test)
74         {
75             _test = test;
76         }
77
78         /// <summary>
79         /// Calls TestStarted on the specified listener.
80         /// </summary>
81         /// <param name="listener">The listener.</param>
82         public override void Send(ITestListener listener)
83         {
84             listener.TestStarted(_test);
85         }
86     }
87
88     /// <summary>
89     /// TestFinishedEvent holds information needed to call the TestFinished method.
90     /// </summary>
91     public class TestFinishedEvent : Event
92     {
93         private readonly ITestResult _result;
94
95         /// <summary>
96         /// Initializes a new instance of the <see cref="TestFinishedEvent"/> class.
97         /// </summary>
98         /// <param name="result">The result.</param>
99         public TestFinishedEvent(ITestResult result)
100         {
101             _result = result;
102         }
103
104         /// <summary>
105         /// Calls TestFinished on the specified listener.
106         /// </summary>
107         /// <param name="listener">The listener.</param>
108         public override void Send(ITestListener listener)
109         {
110             listener.TestFinished(_result);
111         }
112     }
113
114     /// <summary>
115     /// TestOutputEvent holds information needed to call the TestOutput method.
116     /// </summary>
117     public class TestOutputEvent : Event
118     {
119         private readonly TestOutput _output;
120
121         /// <summary>
122         /// Initializes a new instance of the <see cref="TestOutputEvent"/> class.
123         /// </summary>
124         /// <param name="output">The output object.</param>
125         public TestOutputEvent(TestOutput output)
126         {
127             _output = output;
128         }
129
130         /// <summary>
131         /// Calls TestOutput on the specified listener.
132         /// </summary>
133         /// <param name="listener">The listener.</param>
134         public override void Send(ITestListener listener)
135         {
136             listener.TestOutput(_output);
137         }
138     }
139
140     #endregion
141
142     /// <summary>
143     /// Implements a queue of work items each of which
144     /// is queued as a WaitCallback.
145     /// </summary>
146     public class EventQueue
147     {
148         private const int spinCount = 5;
149
150 //        static readonly Logger log = InternalTrace.GetLogger("EventQueue");
151
152         private readonly ConcurrentQueue<Event> _queue = new ConcurrentQueue<Event>();
153
154         /* This event is used solely for the purpose of having an optimized sleep cycle when
155          * we have to wait on an external event (Add or Remove for instance)
156          */
157         private readonly ManualResetEventSlim _mreAdd = new ManualResetEventSlim(false);
158
159         /* The whole idea is to use these two values in a transactional
160          * way to track and manage the actual data inside the underlying lock-free collection
161          * instead of directly working with it or using external locking.
162          *
163          * They are manipulated with CAS and are guaranteed to increase over time and use
164          * of the instance thus preventing ABA problems.
165          */
166         private int _addId = int.MinValue;
167         private int _removeId = int.MinValue;
168
169         private int _stopped;
170
171         /// <summary>
172         /// Gets the count of items in the queue.
173         /// </summary>
174         public int Count
175         {
176             get
177             {
178                 return _queue.Count;
179             }
180         }
181
182         /// <summary>
183         /// Enqueues the specified event
184         /// </summary>
185         /// <param name="e">The event to enqueue.</param>
186         public void Enqueue(Event e)
187         {
188             do
189             {
190                 int cachedAddId = _addId;
191
192                 // Validate that we have are the current enqueuer
193                 if (Interlocked.CompareExchange(ref _addId, cachedAddId + 1, cachedAddId) != cachedAddId)
194                     continue;
195
196                 // Add to the collection
197                 _queue.Enqueue(e);
198
199                 // Wake up threads that may have been sleeping
200                 _mreAdd.Set();
201
202                 break;
203             } while (true);
204
205             Thread.Sleep(1);  // give EventPump thread a chance to process the event
206         }
207
208         /// <summary>
209         /// Removes the first element from the queue and returns it (or <c>null</c>).
210         /// </summary>
211         /// <param name="blockWhenEmpty">
212         /// If <c>true</c> and the queue is empty, the calling thread is blocked until
213         /// either an element is enqueued, or <see cref="Stop"/> is called.
214         /// </param>
215         /// <returns>
216         /// <list type="bullet">
217         ///   <item>
218         ///     <term>If the queue not empty</term>
219         ///     <description>the first element.</description>
220         ///   </item>
221         ///   <item>
222         ///     <term>otherwise, if <paramref name="blockWhenEmpty"/>==<c>false</c>
223         ///       or <see cref="Stop"/> has been called</term>
224         ///     <description><c>null</c>.</description>
225         ///   </item>
226         /// </list>
227         /// </returns>
228         public Event Dequeue(bool blockWhenEmpty)
229         {
230             SpinWait sw = new SpinWait();
231
232             do
233             {
234                 int cachedRemoveId = _removeId;
235                 int cachedAddId = _addId;
236
237                 // Empty case
238                 if (cachedRemoveId == cachedAddId)
239                 {
240                     if (!blockWhenEmpty || _stopped != 0)
241                         return null;
242
243                     // Spin a few times to see if something changes
244                     if (sw.Count <= spinCount)
245                     {
246                         sw.SpinOnce();
247                     }
248                     else
249                     {
250                         // Reset to wait for an enqueue
251                         _mreAdd.Reset();
252
253                         // Recheck for an enqueue to avoid a Wait
254                         if (cachedRemoveId != _removeId || cachedAddId != _addId)
255                         {
256                             // Queue is not empty, set the event
257                             _mreAdd.Set();
258                             continue;
259                         }
260
261                         // Wait for something to happen
262                         _mreAdd.Wait(500);
263                     }
264
265                     continue;
266                 }
267
268                 // Validate that we are the current dequeuer
269                 if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId)
270                     continue;
271
272
273                 // Dequeue our work item
274                 Event e;
275                 while (!_queue.TryDequeue (out e))
276                 {
277                     if (!blockWhenEmpty || _stopped != 0)
278                         return null;
279                 }
280
281                 return e;
282             } while (true);
283         }
284
285         /// <summary>
286         /// Stop processing of the queue
287         /// </summary>
288         public void Stop()
289         {
290             if (Interlocked.CompareExchange(ref _stopped, 1, 0) == 0)
291                 _mreAdd.Set();
292         }
293     }
294 }
295
296 #endif