##// END OF EJS Templates
PollingComponent: implemented correct stopping
cin -
r259:7d52dc684bbd v3
parent child
Show More
@@ -0,0 +1,42
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using Implab.Components;
5 using Xunit;
6
7 namespace Implab.Test
8 {
9 class TimeLog : PollingComponent {
10 public TimeLog() : base(true) {
11 }
12
13 protected override Task Poll(CancellationToken ct) {
14 Console.WriteLine("Poll");
15 return Task.CompletedTask;
16 }
17 }
18
19 public class UnitTest1
20 {
21 [Fact]
22 public async Task Test1()
23 {
24
25 using(var tl = new TimeLog()) {
26 tl.StateChanged += (self, args) => Console.WriteLine("{0}", args.State);
27 tl.Delay = 1000;
28 tl.Interval = 500;
29
30
31 tl.Start(CancellationToken.None);
32 await tl.Completion;
33
34 await Task.Delay(2000);
35
36 tl.Stop(CancellationToken.None);
37 await tl.Completion;
38 await Task.Delay(3000);
39 }
40 }
41 }
42 }
@@ -1,17 +1,17
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 2
3 3 <PropertyGroup>
4 <TargetFramework>net46</TargetFramework>
5 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
4 <TargetFramework>netcoreapp2.1</TargetFramework>
6 5
7 6 <IsPackable>false</IsPackable>
8 7 </PropertyGroup>
8
9 9 <ItemGroup>
10 <ProjectReference Include="../Implab/Implab.csproj" />
11 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
10 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
12 11 <PackageReference Include="xunit" Version="2.3.1" />
13 12 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
13 <ProjectReference Include="../Implab/Implab.csproj"/>
14 14 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
15 15 </ItemGroup>
16 16
17 17 </Project>
@@ -1,73 +1,89
1 1 using System;
2 2 using System.Threading;
3 3 using System.Threading.Tasks;
4 4
5 5 namespace Implab.Components {
6 6 public abstract class PollingComponent : RunnableComponent {
7 7
8 8 readonly Timer m_timer;
9 9
10 10 readonly CancellationTokenSource m_cancellation = new CancellationTokenSource();
11 11
12 Task m_pending;
13 Task m_poll;
14
12 15 /// <summary>
13 16 /// Poll interval in milliseconds.
14 17 /// </summary>
15 18 /// <returns></returns>
16 19 public int Interval { get; set; }
17 20
18 21 /// <summary>
19 22 /// Delay to the first poll after start in milliseconds
20 23 /// </summary>
21 24 /// <returns></returns>
22 25 public int Delay { get; set; }
23 26
24 27 /// <summary>
25 28 /// Indicates how to handle unhandled exceptions in <see cref="Poll()"/> method.
26 29 /// </summary>
27 30 /// <returns></returns>
28 31 public bool FailOnError { get; set; }
29 32
30 33 /// <summary>
31 34 /// Event for the unhandled exceptions in <see cref="Poll()"/> method.
32 35 /// </summary>
33 36 public event EventHandler<UnhandledExceptionEventArgs> UnhandledException;
34 37
35 38 protected PollingComponent(bool initialized) : base(initialized) {
36 39 m_timer = new Timer(OnTimer);
37 40 }
38 41
39 42 protected override void RunInternal() {
40 43 ScheduleNextPoll(Delay);
41 44 }
42 45
43 46
44 //TODO override stop
47 protected override async Task StopInternalAsync(CancellationToken ct) {
48 // component in Stopping state, no new polls will be scheduled
49 m_cancellation.Cancel();
50 try {
51 // await for pending poll
52 await m_poll;
53 } catch (OperationCanceledException e) {
54 // OK
55 }
56 }
45 57
46 58 protected abstract Task Poll(CancellationToken ct);
47 59
48 60 void ScheduleNextPoll(int timeout) {
49 61 lock (SynchronizationObject) {
50 if (State == ExecutionState.Running)
62 if (State == ExecutionState.Running) {
63 m_pending = Safe.CreateTask(m_cancellation.Token);
64 m_poll = m_pending.Then(() => Poll(m_cancellation.Token));
51 65 m_timer.Change(timeout, Timeout.Infinite);
66 }
52 67 }
53 68 }
54 69
55 void OnTimer(object state) {
70 async void OnTimer(object state) {
56 71 try {
57 Poll(m_cancellation.Token);
72 m_pending.Start();
73 await m_poll;
58 74 } catch (Exception e) {
59 75 UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false));
60 76 if (FailOnError)
61 77 Fail(e);
62 78 }
63 79 ScheduleNextPoll(Interval);
64 80 }
65 81
66 82 protected override void Dispose(bool disposing) {
67 83 if (disposing)
68 84 Safe.Dispose(m_timer, m_cancellation);
69 85 base.Dispose(disposing);
70 86 }
71 87
72 88 }
73 89 } No newline at end of file
@@ -1,217 +1,226
1 1 using System.Threading;
2 2 using System;
3 3 using Implab.Diagnostics;
4 4 using System.Collections.Generic;
5 5 using System.Linq;
6 6
7 7 namespace Implab {
8 8 public static class PromiseExtensions {
9 9
10 10 public static IPromise Then(this IPromise that, Action fulfilled, Action<Exception> rejected) {
11 11 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
12 12 that.Then(reaction);
13 13 return reaction.Promise;
14 14 }
15 15
16 16 public static IPromise Then(this IPromise that, Action fulfilled) {
17 17 var reaction = PromiseActionReaction.Create(fulfilled, null, Promise.DefaultDispatcher);
18 18 that.Then(reaction);
19 19 return reaction.Promise;
20 20 }
21 21
22 22 public static IPromise Then(this IPromise that, Action fulfilled, Func<Exception, IPromise> rejected) {
23 23 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
24 24 that.Then(reaction);
25 25 return reaction.Promise;
26 26 }
27 27
28 28 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Action<Exception> rejected) {
29 29 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
30 30 that.Then(reaction);
31 31 return reaction.Promise;
32 32 }
33 33
34 34 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled) {
35 35 var reaction = PromiseActionReaction.Create(fulfilled, null, Promise.DefaultDispatcher);
36 36 that.Then(reaction);
37 37 return reaction.Promise;
38 38 }
39 39
40 40 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Func<Exception, IPromise> rejected) {
41 41 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
42 42 that.Then(reaction);
43 43 return reaction.Promise;
44 44 }
45 45
46 46 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Action<Exception> rejected) {
47 47 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
48 48 that.Then(reaction);
49 49 return reaction.Promise;
50 50 }
51 51
52 52 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled) {
53 53 var reaction = PromiseActionReaction<T>.Create(fulfilled, null, Promise.DefaultDispatcher);
54 54 that.Then(reaction);
55 55 return reaction.Promise;
56 56 }
57 57
58 58 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Func<Exception, IPromise> rejected) {
59 59 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
60 60 that.Then(reaction);
61 61 return reaction.Promise;
62 62 }
63 63
64 64 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Action<Exception> rejected) {
65 65 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
66 66 that.Then(reaction);
67 67 return reaction.Promise;
68 68 }
69 69
70 70 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled) {
71 71 var reaction = PromiseActionReaction<T>.Create(fulfilled, null, Promise.DefaultDispatcher);
72 72 that.Then(reaction);
73 73 return reaction.Promise;
74 74 }
75 75
76 76 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected) {
77 77 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
78 78 that.Then(reaction);
79 79 return reaction.Promise;
80 80 }
81 81
82 82 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, Tout> rejected) {
83 83 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
84 84 that.Then(reaction);
85 85 return reaction.Promise;
86 86 }
87 87
88 88 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled) {
89 89 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
90 90 that.Then(reaction);
91 91 return reaction.Promise;
92 92 }
93 93
94 94 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
95 95 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
96 96 that.Then(reaction);
97 97 return reaction.Promise;
98 98 }
99 99
100 100 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
101 101 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
102 102 that.Then(reaction);
103 103 return reaction.Promise;
104 104 }
105 105
106 106 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled) {
107 107 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
108 108 that.Then(reaction);
109 109 return reaction.Promise;
110 110 }
111 111
112 112 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
113 113 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
114 114 that.Then(reaction);
115 115 return reaction.Promise;
116 116 }
117 117
118 118 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, Tout> rejected) {
119 119 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
120 120 that.Then(reaction);
121 121 return reaction.Promise;
122 122 }
123 123
124 124 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled) {
125 125 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
126 126 that.Then(reaction);
127 127 return reaction.Promise;
128 128 }
129 129
130 130 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
131 131 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
132 132 that.Then(reaction);
133 133 return reaction.Promise;
134 134 }
135 135
136 136 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
137 137 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
138 138 that.Then(reaction);
139 139 return reaction.Promise;
140 140 }
141 141
142 142 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled) {
143 143 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
144 144 that.Then(reaction);
145 145 return reaction.Promise;
146 146 }
147 147
148 148 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
149 149 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
150 150 that.Then(reaction);
151 151 return reaction.Promise;
152 152 }
153 153
154 154 public static IPromise Catch(this IPromise that, Action<Exception> rejected) {
155 155 return Then(that, null, rejected);
156 156 }
157 157
158 158 public static IPromise Catch(this IPromise that, Func<Exception, IPromise> rejected) {
159 159 return Then(that, null, rejected);
160 160 }
161 161
162 162 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) {
163 163 return Then(that, (Func<Tout>)null, rejected);
164 164 }
165 165
166 166 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) {
167 167 return Then(that, (Func<Tout>)null, rejected);
168 168 }
169 169
170 170 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, Tout> rejected) {
171 171 return Then(that, (Func<Tin, Tout>)null, rejected);
172 172 }
173 173
174 174 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, IPromise<Tout>> rejected) {
175 175 return Then(that, (Func<Tin, Tout>)null, rejected);
176 176 }
177 177
178 178 public static IPromise Finally(this IPromise that, Action final) {
179 179 return Then(that, final, e => {
180 180 final();
181 181 throw e.Rethrow();
182 182 });
183 183 }
184 184
185 185 public static IPromise Finally(this IPromise that, Func<IPromise> final) {
186 186 return Then(that, final, e => {
187 187 final();
188 188 throw e.Rethrow();
189 189 });
190 190 }
191 191
192 192 public static IPromise<T> Finally<T>(this IPromise<T> that, Action final) {
193 193 return Then<T, T>(that, x => {
194 194 final();
195 195 return x;
196 196 }, new Func<Exception, T>(e => {
197 197 final();
198 198 throw e.Rethrow();
199 199 }));
200 200 }
201 201
202 202 public static IPromise<T> Finally<T>(this IPromise<T> that, Func<IPromise> final) {
203 203 return Then<T, T>(that, x => {
204 204 return final()
205 205 .Then(() => x);
206 206 }, new Func<Exception, IPromise<T>>(e => {
207 207 return final()
208 208 .Then(new Func<T>(() => {
209 209 throw e.Rethrow();
210 210 }));
211 211 }));
212 212 }
213 213
214 public static PromiseAwaiter GetAwaiter(this IPromise that) {
215 Safe.ArgumentNotNull(that, nameof(that));
216 return new PromiseAwaiter(that);
217 }
218
219 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
220 Safe.ArgumentNotNull(that, nameof(that));
221 return new PromiseAwaiter<T>(that);
222 }
214 223
215 224 }
216 225 }
217 226
@@ -1,171 +1,182
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Text.RegularExpressions;
6 6 using System.Diagnostics;
7 7 using System.Collections;
8 8 using System.Runtime.CompilerServices;
9 9 using System.Threading.Tasks;
10 using System.Threading;
10 11
11 12 #if NET_4_5
12 13 using System.Threading.Tasks;
13 14 #endif
14 15
15 16 namespace Implab
16 17 {
17 18 public static class Safe
18 19 {
19 20 [MethodImpl(MethodImplOptions.AggressiveInlining)]
20 21 public static void ArgumentAssert(bool condition, string paramName) {
21 22 if (!condition)
22 23 throw new ArgumentException("The parameter is invalid", paramName);
23 24 }
24 25
25 26 [MethodImpl(MethodImplOptions.AggressiveInlining)]
26 27 public static void ArgumentMatch(string value, string paramName, Regex rx) {
27 28 if (rx == null)
28 29 throw new ArgumentNullException("rx");
29 30 if (!rx.IsMatch(value))
30 31 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
31 32 }
32 33
33 34 [MethodImpl(MethodImplOptions.AggressiveInlining)]
34 35 public static void ArgumentNotEmpty(string value, string paramName) {
35 36 if (String.IsNullOrEmpty(value))
36 37 throw new ArgumentException("The parameter can't be empty", paramName);
37 38 }
38 39
39 40 [MethodImpl(MethodImplOptions.AggressiveInlining)]
40 41 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
41 42 if (value == null || value.Length == 0)
42 43 throw new ArgumentException("The array must be not emty", paramName);
43 44 }
44 45
45 46 [MethodImpl(MethodImplOptions.AggressiveInlining)]
46 47 public static void ArgumentNotNull(object value, string paramName) {
47 48 if (value == null)
48 49 throw new ArgumentNullException(paramName);
49 50 }
50 51
51 52 [MethodImpl(MethodImplOptions.AggressiveInlining)]
52 53 internal static void ArgumentGreaterEqThan(int value, int min, string paramName) {
53 54 if (value < min)
54 55 throw new ArgumentOutOfRangeException(paramName);
55 56 }
56 57
57 58 [MethodImpl(MethodImplOptions.AggressiveInlining)]
58 59 public static void ArgumentInRange(bool condition, string paramName) {
59 60 if (!condition)
60 61 throw new ArgumentOutOfRangeException(paramName);
61 62 }
62 63
63 64 [MethodImpl(MethodImplOptions.AggressiveInlining)]
64 65 public static void ArgumentOfType(object value, Type type, string paramName) {
65 66 if (!type.IsInstanceOfType(value))
66 67 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
67 68 }
68 69
69 70 public static void Dispose(params IDisposable[] objects) {
70 71 foreach (var d in objects)
71 72 if (d != null)
72 73 d.Dispose();
73 74 }
74 75
75 76 public static void Dispose(params object[] objects) {
76 77 foreach (var obj in objects) {
77 78 var d = obj as IDisposable;
78 79 if (d != null)
79 80 d.Dispose();
80 81 }
81 82 }
82 83
83 84 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
84 85 foreach (var d in objects)
85 86 Dispose(d);
86 87 }
87 88
88 89 public static void DisposeCollection(IEnumerable objects) {
89 90 foreach (var d in objects)
90 91 Dispose(d);
91 92 }
92 93
93 94 public static void Dispose(object obj) {
94 95 if (obj is IDisposable)
95 96 Dispose((IDisposable)obj);
96 97
97 98 }
98 99
99 100 [DebuggerStepThrough]
100 101 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
101 102 if (handler != null)
102 103 handler(sender, args);
103 104 }
104 105
105 106 [DebuggerStepThrough]
106 107 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
107 108 if (handler != null)
108 109 handler(sender, args);
109 110 }
110 111
111 112 [DebuggerStepThrough]
112 113 public static IPromise<T> Run<T>(Func<T> action) {
113 114 ArgumentNotNull(action, "action");
114 115
115 116 try {
116 117 return Promise.Resolve(action());
117 118 } catch (Exception err) {
118 119 return Promise.Reject<T>(err);
119 120 }
120 121 }
121 122
122 123 [DebuggerStepThrough]
123 124 public static IPromise Run(Action action) {
124 125 ArgumentNotNull(action, "action");
125 126
126 127 try {
127 128 action();
128 129 return Promise.Resolve();
129 130 } catch (Exception err) {
130 131 return Promise.Reject(err);
131 132 }
132 133 }
133 134
134 135 [DebuggerStepThrough]
135 136 public static IPromise Run(Func<IPromise> action) {
136 137 ArgumentNotNull(action, "action");
137 138
138 139 try {
139 140 return action() ?? Promise.Reject(new Exception("The action returned null"));
140 141 } catch (Exception err) {
141 142 return Promise.Reject(err);
142 143 }
143 144 }
144 145
145 146 public static void NoWait(IPromise promise) {
146 147 }
147 148
148 149 public static void NoWait(Task promise) {
149 150 }
150 151
151 152 public static void NoWait<T>(Task<T> promise) {
152 153 }
153 154
155 public static void Noop() {
156 }
157
158 public static void Noop(CancellationToken ct) {
159 ct.ThrowIfCancellationRequested();
160 }
161
162 public static Task CreateTask() {
163 return new Task(Noop);
164 }
165
166 public static Task CreateTask(CancellationToken ct) {
167 return new Task(Noop, ct);
168 }
169
154 170 [DebuggerStepThrough]
155 171 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
156 172 ArgumentNotNull(action, "action");
157 173
158 174 try {
159 175 return action() ?? Promise.Reject<T>(new Exception("The action returned null"));
160 176 } catch (Exception err) {
161 177 return Promise.Reject<T>(err);
162 178 }
163 179 }
164 180
165 #if NET_4_5
166 public static void NoWait(Task t) {
167 }
168 #endif
169
170 181 }
171 182 }
1 NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now