Mercurial > pub > ImplabNet
annotate Implab/Components/RunnableComponent.cs @ 203:4d9830a9bbb8 v2
Added 'Fail' method to RunnableComponent which allows component to move from
Running to Failed state.
Added PollingComponent a timer based runnable component
More tests
Added FailPromise a thin class to wrap exceptions
Fixed error handling in SuccessPromise classes.
author | cin |
---|---|
date | Tue, 18 Oct 2016 17:49:54 +0300 |
parents | 2651cb9a4250 |
children | 8200ab154c8a |
rev | line source |
---|---|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
1 using System; |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
2 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
3 namespace Implab.Components { |
185 | 4 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable { |
184 | 5 enum Commands { |
6 Ok = 0, | |
7 Fail, | |
8 Init, | |
9 Start, | |
10 Stop, | |
11 Dispose, | |
12 Last = Dispose | |
13 } | |
14 | |
15 class StateMachine { | |
16 static readonly ExecutionState[,] _transitions; | |
17 | |
18 static StateMachine() { | |
19 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; | |
20 | |
185 | 21 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init); |
22 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose); | |
23 | |
24 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok); | |
25 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail); | |
184 | 26 |
27 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start); | |
28 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose); | |
29 | |
30 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok); | |
31 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail); | |
32 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop); | |
33 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose); | |
34 | |
35 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail); | |
36 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop); | |
37 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose); | |
38 | |
39 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail); | |
40 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok); | |
185 | 41 |
42 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose); | |
184 | 43 } |
44 | |
45 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { | |
46 _transitions[(int)s1, (int)cmd] = s2; | |
47 } | |
48 | |
49 public ExecutionState State { | |
50 get; | |
51 private set; | |
52 } | |
53 | |
54 public StateMachine(ExecutionState initial) { | |
55 State = initial; | |
56 } | |
57 | |
58 public bool Move(Commands cmd) { | |
59 var next = _transitions[(int)State, (int)cmd]; | |
60 if (next == ExecutionState.Undefined) | |
61 return false; | |
62 State = next; | |
63 return true; | |
64 } | |
65 } | |
66 | |
67 IPromise m_pending; | |
68 Exception m_lastError; | |
69 | |
70 readonly StateMachine m_stateMachine; | |
71 | |
72 protected RunnableComponent(bool initialized) { | |
73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created); | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
74 DisposeTimeout = 10000; |
184 | 75 } |
76 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
77 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
78 /// Gets or sets the timeout to wait for the pending operation to complete. If the pending operation doesn't finish than the component will be disposed anyway. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
79 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
80 protected int DisposeTimeout { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
81 get; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
82 set; |
185 | 83 } |
84 | |
184 | 85 void ThrowInvalidCommand(Commands cmd) { |
185 | 86 if (m_stateMachine.State == ExecutionState.Disposed) |
87 throw new ObjectDisposedException(ToString()); | |
88 | |
184 | 89 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); |
90 } | |
91 | |
185 | 92 void Move(Commands cmd) { |
93 if (!m_stateMachine.Move(cmd)) | |
94 ThrowInvalidCommand(cmd); | |
184 | 95 } |
96 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
97 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
98 /// Moves the component from running to failed state. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
99 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
100 /// <param name="error">The exception which is describing the error.</param> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
101 /// <returns>Returns true if the component is set to the failed state, false - otherwise. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
102 /// This method works only for the running state, in any other state it will return false.</returns> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
103 protected bool Fail(Exception error) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
104 lock (m_stateMachine) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
105 if(m_stateMachine.State == ExecutionState.Running) { |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
106 m_stateMachine.Move(Commands.Fail); |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
107 m_lastError = error; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
108 return true; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
109 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
110 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
111 return false; |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
112 } |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
113 |
185 | 114 void Invoke(Commands cmd, Action action) { |
115 lock (m_stateMachine) | |
116 Move(cmd); | |
117 | |
184 | 118 try { |
119 action(); | |
185 | 120 lock(m_stateMachine) |
121 Move(Commands.Ok); | |
122 | |
184 | 123 } catch (Exception err) { |
185 | 124 lock (m_stateMachine) { |
125 Move(Commands.Fail); | |
126 m_lastError = err; | |
127 } | |
184 | 128 throw; |
129 } | |
130 } | |
131 | |
185 | 132 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { |
133 IPromise promise = null; | |
134 IPromise prev; | |
184 | 135 |
185 | 136 var task = new ActionChainTask(action, null, null, true); |
137 | |
138 lock (m_stateMachine) { | |
139 Move(cmd); | |
140 | |
141 prev = m_pending; | |
184 | 142 |
196
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
143 Action<Exception> errorOrCancel = e => { |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
144 if (e == null) |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
145 e = new OperationCanceledException(); |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
146 |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
147 lock (m_stateMachine) { |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
148 if (m_pending == promise) { |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
149 Move(Commands.Fail); |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
150 m_pending = null; |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
151 m_lastError = e; |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
152 } |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
153 } |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
154 throw new PromiseTransientException(e); |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
155 }; |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
156 |
185 | 157 promise = task.Then( |
158 () => { | |
159 lock(m_stateMachine) { | |
160 if (m_pending == promise) { | |
161 Move(Commands.Ok); | |
162 m_pending = null; | |
163 } | |
184 | 164 } |
196
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
165 }, |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
166 errorOrCancel, |
40d7fed4a09e
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
cin
parents:
187
diff
changeset
|
167 errorOrCancel |
185 | 168 ); |
157 | 169 |
185 | 170 m_pending = promise; |
171 } | |
157 | 172 |
185 | 173 if (prev == null) |
174 task.Resolve(); | |
175 else | |
176 chain(prev, task); | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
177 |
185 | 178 return promise; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
179 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
180 |
184 | 181 |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
182 #region IInitializable implementation |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
183 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
184 public void Init() { |
184 | 185 Invoke(Commands.Init, OnInitialize); |
186 } | |
187 | |
188 protected virtual void OnInitialize() { | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
189 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
190 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
191 #endregion |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
192 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
193 #region IRunnable implementation |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
194 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
195 public IPromise Start() { |
185 | 196 return InvokeAsync(Commands.Start, OnStart, null); |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
197 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
198 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
199 protected virtual IPromise OnStart() { |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
200 return Promise.SUCCESS; |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
201 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
202 |
185 | 203 public IPromise Stop() { |
204 return InvokeAsync(Commands.Stop, OnStop, StopPending).Then(Dispose); | |
205 } | |
206 | |
207 protected virtual IPromise OnStop() { | |
208 return Promise.SUCCESS; | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
209 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
210 |
185 | 211 /// <summary> |
212 /// Stops the current operation if one exists. | |
213 /// </summary> | |
214 /// <param name="current">Current.</param> | |
215 /// <param name="stop">Stop.</param> | |
216 protected virtual void StopPending(IPromise current, IDeferred stop) { | |
217 if (current == null) { | |
218 stop.Resolve(); | |
219 } else { | |
187
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
220 // связваем текущую операцию с операцией остановки |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
221 current.On( |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
222 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
223 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
224 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
225 ); |
dd4a3590f9c6
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
cin
parents:
186
diff
changeset
|
226 // посылаем текущей операции сигнал остановки |
185 | 227 current.Cancel(); |
228 } | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
229 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
230 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
231 public ExecutionState State { |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
232 get { |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
233 return m_stateMachine.State; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
234 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
235 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
236 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
237 public Exception LastError { |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
238 get { |
185 | 239 return m_lastError; |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
240 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
241 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
242 |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
243 #endregion |
185 | 244 |
245 #region IDisposable implementation | |
246 | |
203
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
247 /// <summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
248 /// Releases all resource used by the <see cref="Implab.Components.RunnableComponent"/> object. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
249 /// </summary> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
250 /// <remarks> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
251 /// <para>Will not try to stop the component, it will just release all resources. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
252 /// To cleanup the component gracefully use <see cref="Stop()"/> method.</para> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
253 /// <para> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
254 /// In normal cases the <see cref="Dispose()"/> method shouldn't be called, the call to the <see cref="Stop()"/> |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
255 /// method is sufficient to cleanup the component. Call <see cref="Dispose()"/> only to cleanup after errors, |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
256 /// especially if <see cref="Stop"/> method is failed. Using this method insted of <see cref="Stop()"/> may |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
257 /// lead to the data loss by the component. |
4d9830a9bbb8
Added 'Fail' method to RunnableComponent which allows component to move from
cin
parents:
202
diff
changeset
|
258 /// </para></remarks> |
185 | 259 public void Dispose() { |
260 IPromise pending; | |
261 lock (m_stateMachine) { | |
262 if (m_stateMachine.State == ExecutionState.Disposed) | |
263 return; | |
264 | |
265 Move(Commands.Dispose); | |
266 | |
267 GC.SuppressFinalize(this); | |
268 | |
269 pending = m_pending; | |
270 m_pending = null; | |
271 } | |
272 if (pending != null) { | |
273 pending.Cancel(); | |
274 pending.Timeout(DisposeTimeout).On( | |
275 () => Dispose(true, null), | |
276 err => Dispose(true, err), | |
277 reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason)) | |
278 ); | |
279 } else { | |
280 Dispose(true, m_lastError); | |
281 } | |
282 } | |
283 | |
284 ~RunnableComponent() { | |
285 Dispose(false, null); | |
286 } | |
287 | |
288 #endregion | |
289 | |
290 protected virtual void Dispose(bool disposing, Exception lastError) { | |
291 | |
292 } | |
293 | |
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
294 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
295 } |
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
diff
changeset
|
296 |