annotate Implab/AbstractEvent.cs @ 242:cbe10ac0731e v3

Working on promises
author cin
date Wed, 24 Jan 2018 03:03:21 +0300
parents fa6cbf4d8841
children b1e0ffdf3451
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;
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
5 using System.Diagnostics;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
6
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
7 namespace Implab {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
8 public abstract class AbstractEvent<THandler> where THandler : class {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
9
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
10 const int PENDING_SATE = 0;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
11 protected const int TRANSITIONAL_STATE = 1;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
12
156
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
13 protected const int SUCCEEDED_STATE = 2;
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
14 protected const int REJECTED_STATE = 3;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
15
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
16 volatile int m_state;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
17 Exception m_error;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
18
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
19 THandler m_handler;
233
d6fe09f5592c Improved AsyncQueue
cin
parents: 186
diff changeset
20 SimpleAsyncQueue<THandler> m_extraHandlers;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
21
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
22 #region state managment
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
23 protected bool BeginTransit() {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
24 return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
25 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
26
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
27 protected void CompleteTransit(int state) {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
28 #if DEBUG
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
29 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
30 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
31 #else
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
32 m_state = state;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
33 #endif
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
34 Signal();
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
35 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
36
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
37 protected void WaitTransition() {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
38 if (m_state == TRANSITIONAL_STATE) {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
39 SpinWait spin;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
40 do {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
41 spin.SpinOnce();
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
42 } while (m_state == TRANSITIONAL_STATE);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
43 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
44 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
45
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
46 protected bool BeginSetResult() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
47 if (!BeginTransit()) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
48 WaitTransition();
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
49 return false;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
50 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
51 return true;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
52 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
53
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
54 protected void EndSetResult() {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
55 CompleteTransit(SUCCEEDED_STATE);
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
56 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
57
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
58
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
59
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
60 /// <summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
61 /// Выполняет обещание, сообщая об ошибке
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
62 /// </summary>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
63 /// <remarks>
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 /// </remarks>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
68 /// <param name="error">Исключение возникшее при выполнении операции</param>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
69 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
70 protected void SetError(Exception error) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
71 if (BeginTransit()) {
186
75103928da09 working on cancelation and error handling
cin
parents: 185
diff changeset
72 m_error = error;
75103928da09 working on cancelation and error handling
cin
parents: 185
diff changeset
73 CompleteTransit(REJECTED_STATE);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
74 } else {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
75 WaitTransition();
186
75103928da09 working on cancelation and error handling
cin
parents: 185
diff changeset
76 if (m_state == SUCCEEDED_STATE)
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
77 throw new InvalidOperationException("The promise is already resolved");
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
78 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
79 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
80
156
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
81 protected abstract void SignalHandler(THandler handler, int signal);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
82
156
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
83 void Signal() {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
84 THandler handler;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
85 while (TryDequeueHandler(out handler))
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
86 SignalHandler(handler, m_state);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
87 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
88
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
89 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
90
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
91 protected abstract Signal GetFulfillSignal();
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
92
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
93 #region synchronization traits
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
94 protected void WaitResult(int timeout) {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
95 if (!(IsFulfilled || GetFulfillSignal().Wait(timeout)))
148
e6d4b41f0101 fixed timeout handling in promises
cin
parents: 145
diff changeset
96 throw new TimeoutException();
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
97
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
98 if (IsRejected)
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
99 Rethrow();
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
100 }
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
101
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
102 protected void Rethrow() {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
103 Debug.Assert(m_error != null);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
104 if (m_error is OperationCanceledException)
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
105 throw new OperationCanceledException("Operation cancelled", m_error);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
106 else
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
107 throw new TargetInvocationException(m_error);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
108 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
109 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
110
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
111 #region handlers managment
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
112
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
113 protected void AddHandler(THandler handler) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
114
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
115 if (m_state > 1) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
116 // the promise is in the resolved state, just invoke the handler
156
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
117 SignalHandler(handler, m_state);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
118 } else {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
119 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
120 if (m_extraHandlers == null)
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
121 // compare-exchange will fprotect from loosing already created queue
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
122 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
123 m_extraHandlers.Enqueue(handler);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
124 }
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
125
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
126 if (m_state > 1 && TryDequeueHandler(out handler))
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
127 // if the promise have been resolved while we was adding the handler to the queue
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
128 // we can't guarantee that someone is still processing it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
129 // therefore we need to fetch a handler from the queue and execute it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
130 // note that fetched handler may be not the one that we have added
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
131 // even we can fetch no handlers at all :)
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
132 SignalHandler(handler, m_state);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
133 }
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
134
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
135 }
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
136
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
137 bool TryDequeueHandler(out THandler handler) {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
138 handler = Interlocked.Exchange(ref m_handler, null);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
139 if (handler != null)
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
140 return true;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
141 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
142 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
143
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
144 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
145
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
146 #region IPromise implementation
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
147
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
148 public bool IsFulfilled {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
149 get {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
150 return m_state > TRANSITIONAL_STATE;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
151 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
152 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
153
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
154 public bool IsRejected {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
155 get {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
156 return m_state == REJECTED_STATE;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
157 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
158 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
159
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
160 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
161
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
162 public Exception RejectReason {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
163 get {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
164 return m_error;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
165 }
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 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
170