annotate Implab/AbstractEvent.cs @ 145:706fccb85524 v2

RC: cancellation support for promises + tests
author cin
date Sun, 08 Mar 2015 02:52:27 +0300
parents 8c0b95069066
children e6d4b41f0101
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
1 using System;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
2 using Implab.Parallels;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
3 using System.Threading;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
4 using System.Reflection;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
5
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
6 namespace Implab {
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
8
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
9 const int UNRESOLVED_SATE = 0;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
10 const int TRANSITIONAL_STATE = 1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
11 const int SUCCEEDED_STATE = 2;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
12 const int REJECTED_STATE = 3;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
13 const int CANCELLED_STATE = 4;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
14
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
15 const int CANCEL_NOT_REQUESTED = 0;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
16 const int CANCEL_REQUESTING = 1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
17 const int CANCEL_REQUESTED = 2;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
18
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
19 const int RESERVED_HANDLERS_COUNT = 4;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
20
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
21 int m_state;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
22 Exception m_error;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
23 int m_handlersCount;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
24
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
25 readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
26 MTQueue<THandler> m_extraHandlers;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
27 int m_handlerPointer = -1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
28 int m_handlersCommited;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
29
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
30 int m_cancelRequest;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
31 Exception m_cancelationReason;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
32 MTQueue<Action<Exception>> m_cancelationHandlers;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
33
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
34
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
35 #region state managment
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
36 bool BeginTransit() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
37 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
38 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
39
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
40 void CompleteTransit(int state) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
41 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
42 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
43 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
44
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
45 void WaitTransition() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
46 while (m_state == TRANSITIONAL_STATE) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
47 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
48 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
49 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
50
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
51 protected bool BeginSetResult() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
52 if (!BeginTransit()) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
53 WaitTransition();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
54 if (m_state != CANCELLED_STATE)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
55 throw new InvalidOperationException("The promise is already resolved");
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
56 return false;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
57 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
58 return true;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
59 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
60
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
61 protected void EndSetResult() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
62 CompleteTransit(SUCCEEDED_STATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
63 OnSuccess();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
64 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
65
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
66
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
67
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
68 /// <summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
69 /// Выполняет обещание, сообщая об ошибке
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
70 /// </summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
71 /// <remarks>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
72 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
73 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
74 /// будут проигнорированы.
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
75 /// </remarks>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
76 /// <param name="error">Исключение возникшее при выполнении операции</param>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
77 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
78 protected void SetError(Exception error) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
79 if (BeginTransit()) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
80 if (error is OperationCanceledException) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
81 CompleteTransit(CANCELLED_STATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
82 m_error = error.InnerException;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
83 OnCancelled();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
84 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
85 m_error = error is PromiseTransientException ? error.InnerException : error;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
86 CompleteTransit(REJECTED_STATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
87 OnError();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
88 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
89 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
90 WaitTransition();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
91 if (m_state == SUCCEEDED_STATE)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
92 throw new InvalidOperationException("The promise is already resolved");
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
93 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
94 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
95
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
96 /// <summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
97 /// Отменяет операцию, если это возможно.
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
98 /// </summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
99 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
100 protected void SetCancelled(Exception reason) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
101 if (BeginTransit()) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
102 m_error = reason;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
103 CompleteTransit(CANCELLED_STATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
104 OnCancelled();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
105 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
106 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
107
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
108 protected abstract void SignalSuccess(THandler handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
109
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
110 protected abstract void SignalError(THandler handler, Exception error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
111
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
112 protected abstract void SignalCancelled(THandler handler, Exception reason);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
113
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
114 void OnSuccess() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
115 var hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
116 var slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
117 while (slot < m_handlersCommited) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
118 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
119 SignalSuccess(m_handlers[slot]);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
120 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
121 hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
122 slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
123 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
124
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
125
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
126 if (m_extraHandlers != null) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
127 THandler handler;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
128 while (m_extraHandlers.TryDequeue(out handler))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
129 SignalSuccess(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
130 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
131 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
132
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
133 void OnError() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
134 var hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
135 var slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
136 while (slot < m_handlersCommited) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
137 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
138 SignalError(m_handlers[slot],m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
139 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
140 hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
141 slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
142 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
143
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
144 if (m_extraHandlers != null) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
145 THandler handler;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
146 while (m_extraHandlers.TryDequeue(out handler))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
147 SignalError(handler, m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
148 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
149 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
150
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
151 void OnCancelled() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
152 var hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
153 var slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
154 while (slot < m_handlersCommited) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
155 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
156 SignalCancelled(m_handlers[slot], m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
157 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
158 hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
159 slot = hp +1 ;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
160 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
161
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
162 if (m_extraHandlers != null) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
163 THandler handler;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
164 while (m_extraHandlers.TryDequeue(out handler))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
165 SignalCancelled(handler, m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
166 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
167 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
168
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
169 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
170
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
171 protected abstract Signal GetResolveSignal();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
172
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
173 #region synchronization traits
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
174 protected void WaitResult(int timeout) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
175 if (!IsResolved)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
176 GetResolveSignal().Wait(timeout);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
177
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
178 switch (m_state) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
179 case SUCCEEDED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
180 return;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
181 case CANCELLED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
182 throw new OperationCanceledException();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
183 case REJECTED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
184 throw new TargetInvocationException(m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
185 default:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
186 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
187 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
188 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
189 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
190
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
191 #region handlers managment
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
192
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
193 protected void AddHandler(THandler handler) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
194
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
195 if (m_state > 1) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
196 // the promise is in the resolved state, just invoke the handler
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
197 InvokeHandler(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
198 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
199 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
200
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
201 if (slot < RESERVED_HANDLERS_COUNT) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
202
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
203 m_handlers[slot] = handler;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
204
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
205 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
206 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
207
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
208 if (m_state > 1) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
209 do {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
210 var hp = m_handlerPointer;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
211 slot = hp + 1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
212 if (slot < m_handlersCommited) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
213 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
214 continue;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
215 InvokeHandler(m_handlers[slot]);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
216 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
217 break;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
218 } while(true);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
219 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
220 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
221 if (slot == RESERVED_HANDLERS_COUNT) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
222 m_extraHandlers = new MTQueue<THandler>();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
223 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
224 while (m_extraHandlers == null)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
225 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
226 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
227
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
228 m_extraHandlers.Enqueue(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
229
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
230 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
231 // if the promise have been resolved while we was adding the handler to the queue
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
232 // we can't guarantee that someone is still processing it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
233 // therefore we need to fetch a handler from the queue and execute it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
234 // note that fetched handler may be not the one that we have added
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
235 // even we can fetch no handlers at all :)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
236 InvokeHandler(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
237 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
238 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
239 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
240
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
241 protected void InvokeHandler(THandler handler) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
242 switch (m_state) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
243 case SUCCEEDED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
244 SignalSuccess(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
245 break;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
246 case CANCELLED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
247 SignalCancelled(handler, m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
248 break;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
249 case REJECTED_STATE:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
250 SignalError(handler, m_error);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
251 break;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
252 default:
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
253 throw new Exception(String.Format("Invalid promise state {0}", m_state));
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
254 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
255 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
256
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
257 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
258
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
259 #region IPromise implementation
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
260
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
261 public bool IsResolved {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
262 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
263 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
264 return m_state > 1;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
265 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
266 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
267
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
268 public bool IsCancelled {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
269 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
270 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
271 return m_state == CANCELLED_STATE;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
272 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
273 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
274
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
275 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
276
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
277 public Exception Error {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
278 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
279 return m_error;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
280 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
281 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
282
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
283 public bool CancelOperationIfRequested() {
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
284 if (IsCancellationRequested) {
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
285 CancelOperation(CancellationReason);
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
286 return true;
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
287 }
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
288 return false;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
289 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
290
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
291 public virtual void CancelOperation(Exception reason) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
292 SetCancelled(reason);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
293 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
294
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
295 public void CancellationRequested(Action<Exception> handler) {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
296 Safe.ArgumentNotNull(handler, "handler");
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
297 if (IsCancellationRequested)
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
298 handler(CancellationReason);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
299
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
300 if (m_cancelationHandlers == null)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
301 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
302
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
303 m_cancelationHandlers.Enqueue(handler);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
304
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
305 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
306 // TryDeque implies MemoryBarrier()
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
307 handler(m_cancelationReason);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
308 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
309
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
310 public bool IsCancellationRequested {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
311 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
312 do {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
313 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
314 return false;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
315 if (m_cancelRequest == CANCEL_REQUESTED)
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
316 return true;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
317 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
318 } while(true);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
319 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
320 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
321
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
322 public Exception CancellationReason {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
323 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
324 do {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
325 Thread.MemoryBarrier();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
326 } while(m_cancelRequest == CANCEL_REQUESTING);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
327
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
328 return m_cancelationReason;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
329 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
330 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
331
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
332 #region ICancellable implementation
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
333
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
334 public void Cancel() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
335 Cancel(null);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
336 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
337
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
338 public void Cancel(Exception reason) {
145
706fccb85524 RC: cancellation support for promises + tests
cin
parents: 144
diff changeset
339 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
340 m_cancelationReason = reason;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
341 m_cancelRequest = CANCEL_REQUESTED;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
342 if (m_cancelationHandlers != null) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
343 Action<Exception> handler;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
344 while (m_cancelationHandlers.TryDequeue(out handler))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
345 handler(m_cancelationReason);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
346 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
347 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
348 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
349
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
350 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
351 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
352 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
353