##// END OF EJS Templates
minor fixes
cin -
r260:547a2fc0d93e v3.0.6 v3
parent child
Show More
@@ -0,0 +1,35
1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using Implab.Components;
5
6 namespace Implab.Test {
7 public class MockPollComponent : PollingComponent {
8
9 public Func<CancellationToken,Task> PollWorker { get; set;}
10
11 public Func<CancellationToken, Task> StartWorker { get; set; }
12
13 public Func<CancellationToken, Task> StopWorker { get; set; }
14
15 public MockPollComponent(bool initialized) : base(initialized) {
16 }
17
18 protected async override Task Poll(CancellationToken ct) {
19 if(PollWorker!= null)
20 await PollWorker.Invoke(ct);
21 }
22
23 protected async override Task StopInternalAsync(CancellationToken ct) {
24 if (StopWorker != null)
25 await StopWorker.Invoke(ct);
26 }
27
28 protected async override Task StartInternalAsync(CancellationToken ct) {
29 if (StartWorker != null)
30 await StartWorker.Invoke(ct);
31 }
32
33
34 }
35 } No newline at end of file
@@ -1,69 +1,20
1 <?xml version="1.0" encoding="utf-8"?>
1 <Project Sdk="Microsoft.NET.Sdk">
2 <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
3 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
4 <PropertyGroup>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.6-api/</FrameworkPathOverride>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7 <ProjectGuid>{100DFEB0-75BE-436F-ADDF-1F46EF433F46}</ProjectGuid>
8 <OutputType>Exe</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>Implab.Playground</RootNamespace>
11 <AssemblyName>Implab.Playground</AssemblyName>
12 <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
13 <FileAlignment>512</FileAlignment>
14 <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
15 <TargetFrameworkProfile />
16 </PropertyGroup>
5 </PropertyGroup>
17 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
6
18 <PlatformTarget>AnyCPU</PlatformTarget>
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
19 <DebugSymbols>true</DebugSymbols>
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
20 <DebugType>full</DebugType>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
26 </PropertyGroup>
9 </PropertyGroup>
27 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
10
28 <PlatformTarget>AnyCPU</PlatformTarget>
11 <PropertyGroup>
29 <DebugType>pdbonly</DebugType>
12 <OutputType>Exe</OutputType>
30 <Optimize>true</Optimize>
13 <IsPackable>false</IsPackable>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>true</Prefer32Bit>
36 <DebugSymbols>true</DebugSymbols>
37 </PropertyGroup>
14 </PropertyGroup>
38 <ItemGroup>
15
39 <Reference Include="System" />
40 <Reference Include="System.Core" />
41 <Reference Include="System.Xml.Linq" />
42 <Reference Include="System.Data.DataSetExtensions" />
43 <Reference Include="Microsoft.CSharp" />
44 <Reference Include="System.Data" />
45 <Reference Include="System.Net.Http" />
46 <Reference Include="System.Xml" />
47 </ItemGroup>
48 <ItemGroup>
16 <ItemGroup>
49 <Compile Include="Program.cs" />
17 <ProjectReference Include="../Implab/Implab.csproj"/>
50 <Compile Include="Properties\AssemblyInfo.cs" />
51 </ItemGroup>
52 <ItemGroup>
53 <None Include="App.config" />
54 </ItemGroup>
18 </ItemGroup>
55 <ItemGroup>
19
56 <ProjectReference Include="..\Implab\Implab.csproj">
20 </Project>
57 <Project>{f550f1f8-8746-4ad0-9614-855f4c4b7f05}</Project>
58 <Name>Implab</Name>
59 </ProjectReference>
60 </ItemGroup>
61 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
62 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
63 Other similar extension points exist, see Microsoft.Common.targets.
64 <Target Name="BeforeBuild">
65 </Target>
66 <Target Name="AfterBuild">
67 </Target>
68 -->
69 </Project> No newline at end of file
@@ -1,55 +1,54
1 using Implab.Diagnostics;
1 using Implab.Diagnostics;
2 using Implab.Formats.Json;
2 using Implab.Formats.Json;
3 using Implab.Parallels;
3 using Implab.Parallels;
4 using Implab.Xml;
4 using Implab.Xml;
5 using System;
5 using System;
6 using System.Collections.Concurrent;
6 using System.Collections.Concurrent;
7 using System.Collections.Generic;
7 using System.Collections.Generic;
8 using System.IO;
8 using System.IO;
9 using System.Linq;
9 using System.Linq;
10 using System.Text;
10 using System.Text;
11 using System.Threading;
11 using System.Threading;
12 using System.Threading.Tasks;
12 using System.Threading.Tasks;
13 using System.Xml;
13 using System.Xml;
14 using System.Xml.Serialization;
14 using System.Xml.Serialization;
15
15
16 namespace Implab.Playground {
16 namespace Implab.Playground {
17 using System.Diagnostics;
17 using System.Diagnostics;
18 using System.Runtime.Remoting.Messaging;
19 using static Trace<Program>;
18 using static Trace<Program>;
20
19
21 public class Program {
20 public class Program {
22
21
23 static void Main(string[] args) {
22 static void Main(string[] args) {
24 var listener = new SimpleTraceListener(Console.Out);
23 var listener = new SimpleTraceListener(Console.Out);
25
24
26 var source = Trace<Program>.TraceSource;
25 var source = Trace<Program>.TraceSource;
27 source.Switch.Level = SourceLevels.All;
26 source.Switch.Level = SourceLevels.All;
28
27
29 source.Listeners.Add(listener);
28 source.Listeners.Add(listener);
30
29
31 var t = Environment.TickCount;
30 var t = Environment.TickCount;
32
31
33 Main().Wait();
32 Main().Wait();
34
33
35 Console.WriteLine($"Done: {Environment.TickCount - t} ms");
34 Console.WriteLine($"Done: {Environment.TickCount - t} ms");
36 Console.ReadKey();
35 Console.ReadKey();
37 }
36 }
38
37
39 static async Task Main() {
38 static async Task Main() {
40 using (LogicalOperation(nameof(Main))) {
39 using (LogicalOperation(nameof(Main))) {
41 Log("Start");
40 Log("Start");
42 await SomeAsync();
41 await SomeAsync();
43 Log("End");
42 Log("End");
44 }
43 }
45 }
44 }
46
45
47 static async Task SomeAsync() {
46 static async Task SomeAsync() {
48 using (LogicalOperation(nameof(SomeAsync))) {
47 using (LogicalOperation(nameof(SomeAsync))) {
49 Log("Do prepare");
48 Log("Do prepare");
50 await Task.Yield();
49 await Task.Yield();
51 Log("Yield");
50 Log("Yield");
52 }
51 }
53 }
52 }
54 }
53 }
55 }
54 }
@@ -1,17 +1,23
1 <Project Sdk="Microsoft.NET.Sdk">
1 <Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <TargetFrameworks>netcoreapp2.0</TargetFrameworks>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 </PropertyGroup>
6
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
9 </PropertyGroup>
2
10
3 <PropertyGroup>
11 <PropertyGroup>
4 <TargetFramework>netcoreapp2.1</TargetFramework>
5
6 <IsPackable>false</IsPackable>
12 <IsPackable>false</IsPackable>
7 </PropertyGroup>
13 </PropertyGroup>
8
14
9 <ItemGroup>
15 <ItemGroup>
10 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
16 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
11 <PackageReference Include="xunit" Version="2.3.1" />
17 <PackageReference Include="xunit" Version="2.3.1" />
12 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
18 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
13 <ProjectReference Include="../Implab/Implab.csproj"/>
19 <ProjectReference Include="../Implab/Implab.csproj"/>
14 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
20 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
15 </ItemGroup>
21 </ItemGroup>
16
22
17 </Project>
23 </Project>
@@ -1,42 +1,30
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4 using Implab.Components;
4 using Implab.Components;
5 using Xunit;
5 using Xunit;
6
6
7 namespace Implab.Test
7 namespace Implab.Test {
8 {
9 class TimeLog : PollingComponent {
10 public TimeLog() : base(true) {
11 }
12
8
13 protected override Task Poll(CancellationToken ct) {
9 public class RunnableComponentTests {
14 Console.WriteLine("Poll");
15 return Task.CompletedTask;
16 }
17 }
18
19 public class UnitTest1
20 {
21 [Fact]
10 [Fact]
22 public async Task Test1()
11 public async Task Test1() {
23 {
24
12
25 using(var tl = new TimeLog()) {
13 using (var m = new MockPollComponent(true)) {
26 tl.StateChanged += (self, args) => Console.WriteLine("{0}", args.State);
14 m.StartWorker = async (ct) => await Task.Yield();
27 tl.Delay = 1000;
15 m.StopWorker = async (ct) => await Task.Yield();
28 tl.Interval = 500;
29
16
17 Assert.Equal(ExecutionState.Ready, m.State);
18 Assert.NotNull(m.Completion);
30
19
31 tl.Start(CancellationToken.None);
20 m.Start(CancellationToken.None);
32 await tl.Completion;
21 await m.Completion;
22 Assert.Equal(ExecutionState.Running, m.State);
33
23
34 await Task.Delay(2000);
24 m.Stop(CancellationToken.None);
35
25 await m.Completion;
36 tl.Stop(CancellationToken.None);
26 Assert.Equal(ExecutionState.Stopped, m.State);
37 await tl.Completion;
38 await Task.Delay(3000);
39 }
27 }
40 }
28 }
41 }
29 }
42 }
30 }
@@ -1,89 +1,93
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4
4
5 namespace Implab.Components {
5 namespace Implab.Components {
6 public abstract class PollingComponent : RunnableComponent {
6 public abstract class PollingComponent : RunnableComponent {
7
7
8 readonly Timer m_timer;
8 readonly Timer m_timer;
9
9
10 readonly CancellationTokenSource m_cancellation = new CancellationTokenSource();
10 readonly CancellationTokenSource m_cancellation = new CancellationTokenSource();
11
11
12 Task m_pending;
12 Task m_pending;
13 Task m_poll;
13 Task m_poll;
14
14
15 /// <summary>
15 /// <summary>
16 /// Poll interval in milliseconds.
16 /// Poll interval in milliseconds.
17 /// </summary>
17 /// </summary>
18 /// <returns></returns>
18 /// <returns></returns>
19 public int Interval { get; set; }
19 public int Interval { get; set; }
20
20
21 /// <summary>
21 /// <summary>
22 /// Delay to the first poll after start in milliseconds
22 /// Delay to the first poll after start in milliseconds
23 /// </summary>
23 /// </summary>
24 /// <returns></returns>
24 /// <returns></returns>
25 public int Delay { get; set; }
25 public int Delay { get; set; }
26
26
27 /// <summary>
27 /// <summary>
28 /// Indicates how to handle unhandled exceptions in <see cref="Poll()"/> method.
28 /// Indicates how to handle unhandled exceptions in <see cref="Poll()"/> method.
29 /// </summary>
29 /// </summary>
30 /// <returns></returns>
30 /// <returns></returns>
31 public bool FailOnError { get; set; }
31 public bool FailOnError { get; set; }
32
32
33 /// <summary>
33 /// <summary>
34 /// Event for the unhandled exceptions in <see cref="Poll()"/> method.
34 /// Event for the unhandled exceptions in <see cref="Poll()"/> method.
35 /// </summary>
35 /// </summary>
36 public event EventHandler<UnhandledExceptionEventArgs> UnhandledException;
36 public event EventHandler<UnhandledExceptionEventArgs> UnhandledException;
37
37
38 protected PollingComponent(bool initialized) : base(initialized) {
38 protected PollingComponent(bool initialized) : base(initialized) {
39 m_timer = new Timer(OnTimer);
39 m_timer = new Timer(OnTimer);
40 }
40 }
41
41
42 protected override void RunInternal() {
42 protected override void RunInternal() {
43 ScheduleNextPoll(Delay);
43 ScheduleNextPoll(Delay);
44 }
44 }
45
45
46
46
47 protected override async Task StopInternalAsync(CancellationToken ct) {
47 protected override async Task StopInternalAsync(CancellationToken ct) {
48 // component in Stopping state, no new polls will be scheduled
48 // component in Stopping state, no new polls will be scheduled
49 m_cancellation.Cancel();
49 m_cancellation.Cancel();
50 try {
50 try {
51 // await for pending poll
51 // await for pending poll
52 await m_poll;
52 await m_poll;
53 } catch (OperationCanceledException e) {
53 } catch (OperationCanceledException) {
54 // OK
54 // OK
55 }
55 }
56 }
56 }
57
57
58 protected abstract Task Poll(CancellationToken ct);
58 protected abstract Task Poll(CancellationToken ct);
59
59
60 void ScheduleNextPoll(int timeout) {
60 void ScheduleNextPoll(int timeout) {
61 lock (SynchronizationObject) {
61 lock (SynchronizationObject) {
62 if (State == ExecutionState.Running) {
62 if (State == ExecutionState.Running) {
63 m_pending = Safe.CreateTask(m_cancellation.Token);
63 m_pending = Safe.CreateTask(m_cancellation.Token);
64 m_poll = m_pending.Then(() => Poll(m_cancellation.Token));
64 m_poll = m_pending.Then(() => Poll(m_cancellation.Token));
65 m_timer.Change(timeout, Timeout.Infinite);
65 m_timer.Change(timeout, Timeout.Infinite);
66 }
66 }
67 }
67 }
68 }
68 }
69
69
70 async void OnTimer(object state) {
70 async void OnTimer(object state) {
71 try {
71 try {
72 m_pending.Start();
72 m_pending.Start();
73 await m_poll;
73 await m_poll;
74 ScheduleNextPoll(Interval);
74 } catch (Exception e) {
75 } catch (Exception e) {
75 UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false));
76 UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false));
77
76 if (FailOnError)
78 if (FailOnError)
77 Fail(e);
79 Fail(e);
80 else
81 ScheduleNextPoll(Interval);
78 }
82 }
79 ScheduleNextPoll(Interval);
83
80 }
84 }
81
85
82 protected override void Dispose(bool disposing) {
86 protected override void Dispose(bool disposing) {
83 if (disposing)
87 if (disposing)
84 Safe.Dispose(m_timer, m_cancellation);
88 Safe.Dispose(m_timer, m_cancellation);
85 base.Dispose(disposing);
89 base.Dispose(disposing);
86 }
90 }
87
91
88 }
92 }
89 } No newline at end of file
93 }
@@ -1,331 +1,332
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.Threading;
3 using System.Threading;
4 using System.Threading.Tasks;
4 using System.Threading.Tasks;
5
5
6 namespace Implab.Components {
6 namespace Implab.Components {
7 /// <summary>
7 /// <summary>
8 /// Base class for implementing components which support start and stop operations,
8 /// Base class for implementing components which support start and stop operations,
9 /// such components may represent running services.
9 /// such components may represent running services.
10 /// </summary>
10 /// </summary>
11 /// <remarks>
11 /// <remarks>
12 /// This class provides a basic lifecycle from the creation to the
12 /// This class provides a basic lifecycle from the creation to the
13 /// termination of the component.
13 /// termination of the component.
14 /// </remarks>
14 /// </remarks>
15 public abstract class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable {
15 public abstract class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable {
16
16
17 /// <summary>
17 /// <summary>
18 /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task,
18 /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task,
19 /// when the task completes the associated token source will be disposed.
19 /// when the task completes the associated token source will be disposed.
20 /// </summary>
20 /// </summary>
21 class AsyncOperationDescriptor {
21 class AsyncOperationDescriptor {
22
22
23 public static AsyncOperationDescriptor None { get; } = new AsyncOperationDescriptor();
23 public static AsyncOperationDescriptor None { get; } = new AsyncOperationDescriptor();
24
24
25 readonly CancellationTokenSource m_cts;
25 readonly CancellationTokenSource m_cts;
26
26
27 bool m_done;
27 bool m_done;
28
28
29 public CancellationToken Token {
29 public CancellationToken Token {
30 get { return m_cts == null ? CancellationToken.None : m_cts.Token; }
30 get { return m_cts == null ? CancellationToken.None : m_cts.Token; }
31 }
31 }
32
32
33 public Task Task { get; private set; }
33 public Task Task { get; private set; }
34
34
35 private AsyncOperationDescriptor(Task task, CancellationTokenSource cts) {
35 private AsyncOperationDescriptor(Task task, CancellationTokenSource cts) {
36 m_cts = cts;
36 m_cts = cts;
37 Task = Chain(task);
37 Task = Chain(task);
38 }
38 }
39
39
40 private AsyncOperationDescriptor() {
40 private AsyncOperationDescriptor() {
41 Task = Task.CompletedTask;
41 Task = Task.CompletedTask;
42 }
42 }
43
43
44 public void Cancel() {
44 public void Cancel() {
45 if (m_cts != null) {
45 if (m_cts != null) {
46 lock (m_cts) {
46 lock (m_cts) {
47 if (!m_done)
47 if (!m_done)
48 m_cts.Cancel();
48 m_cts.Cancel();
49 }
49 }
50 }
50 }
51 }
51 }
52
52
53 void Done() {
53 void Done() {
54 if (m_cts != null) {
54 if (m_cts != null) {
55 lock (m_cts) {
55 lock (m_cts) {
56 m_done = true;
56 m_done = true;
57 m_cts.Dispose();
57 m_cts.Dispose();
58 }
58 }
59 } else {
59 } else {
60 m_done = true;
60 m_done = true;
61 }
61 }
62 }
62 }
63
63
64 async Task Chain(Task other) {
64 async Task Chain(Task other) {
65 try {
65 try {
66 await other;
66 await other;
67 } finally {
67 } finally {
68 Done();
68 Done();
69 }
69 }
70 }
70 }
71
71
72 public static AsyncOperationDescriptor Create(Func<CancellationToken, Task> factory, CancellationToken ct) {
72 public static AsyncOperationDescriptor Create(Func<CancellationToken, Task> factory, CancellationToken ct) {
73 var cts = ct.CanBeCanceled ?
73 var cts = ct.CanBeCanceled ?
74 CancellationTokenSource.CreateLinkedTokenSource(ct) :
74 CancellationTokenSource.CreateLinkedTokenSource(ct) :
75 new CancellationTokenSource();
75 new CancellationTokenSource();
76
76
77 return new AsyncOperationDescriptor(factory(cts.Token), cts);
77 return new AsyncOperationDescriptor(factory(cts.Token), cts);
78 }
78 }
79
79
80 }
80 }
81
81
82 // this lock is used to synchronize state flow of the component during
82 // this lock is used to synchronize state flow of the component during
83 // processing calls from a client and internal processes.
83 // processing calls from a client and internal processes.
84 readonly object m_lock = new object();
84 readonly object m_lock = new object();
85
85
86 // current operation cookie, used to check wheather a call to
86 // current operation cookie, used to check wheather a call to
87 // MoveSuccess/MoveFailed method belongs to the current
87 // MoveSuccess/MoveFailed method belongs to the current
88 // operation, if cookies didn't match ignore completion result.
88 // operation, if cookies didn't match ignore completion result.
89 object m_cookie;
89 object m_cookie;
90
90
91 // AsyncOperationDscriptor aggregates a task and it's cancellation token
91 // AsyncOperationDscriptor aggregates a task and it's cancellation token
92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
93
93
94 ExecutionState m_state;
94 ExecutionState m_state;
95
95
96 /// <summary>
96 /// <summary>
97 /// Объект синхронизации используется для обеспечения совместного доступа
97 /// Объект синхронизации используется для обеспечения совместного доступа
98 /// клиента компоненты и процессов, протекающих внутри компоненты, к общему
98 /// клиента компоненты и процессов, протекающих внутри компоненты, к общему
99 /// состоянию, т.е.true таким свойствам, как <see cref="State"/>,
99 /// состоянию, т.е.true таким свойствам, как <see cref="State"/>,
100 /// <see cref="LastError"/>. Обработчики события <see cref="StateChanged"/>
100 /// <see cref="LastError"/>. Обработчики события <see cref="StateChanged"/>
101 /// вызываются уже с установленной блокировкой, поэтому дополнительная
101 /// вызываются уже с установленной блокировкой, поэтому дополнительная
102 /// синхронизация не требуется.
102 /// синхронизация не требуется.
103 /// </summary>
103 /// </summary>
104 public object SynchronizationObject { get { return m_lock; } }
104 public object SynchronizationObject { get { return m_lock; } }
105
105
106 protected RunnableComponent(bool initialized) {
106 protected RunnableComponent(bool initialized) {
107 State = initialized ? ExecutionState.Ready : ExecutionState.Created;
107 State = initialized ? ExecutionState.Ready : ExecutionState.Created;
108 }
108 }
109
109
110 public Task Completion {
110 public Task Completion {
111 get { return m_current.Task; }
111 get { return m_current.Task; }
112 }
112 }
113
113
114 public ExecutionState State {
114 public ExecutionState State {
115 get { return m_state; }
115 get { return m_state; }
116 private set {
116 private set {
117 if (m_state != value) {
117 if (m_state != value) {
118 m_state = value;
118 m_state = value;
119 StateChanged.DispatchEvent(this, new StateChangeEventArgs {
119 StateChanged.DispatchEvent(this, new StateChangeEventArgs {
120 State = value,
120 State = value,
121 LastError = LastError
121 LastError = LastError
122 });
122 });
123 }
123 }
124 }
124 }
125 }
125 }
126
126
127 public Exception LastError { get; private set; }
127 public Exception LastError { get; private set; }
128
128
129 /// <summary>
129 /// <summary>
130 /// Событие изменения состояния компоненты.see Обработчики данного события
130 /// Событие изменения состояния компоненты.see Обработчики данного события
131 /// вызываются внутри блокировки <see cref="SynchronizationObject"/> и должны
131 /// вызываются внутри блокировки <see cref="SynchronizationObject"/> и должны
132 /// выполняться максимально быстро.
132 /// выполняться максимально быстро.
133 /// </summary>
133 /// </summary>
134 public event EventHandler<StateChangeEventArgs> StateChanged;
134 public event EventHandler<StateChangeEventArgs> StateChanged;
135
135
136 /// <summary>
136 /// <summary>
137 /// Releases all resources used by the current component regardless of its
137 /// Releases all resources used by the current component regardless of its
138 /// execution state.
138 /// execution state.
139 /// </summary>
139 /// </summary>
140 /// <remarks>
140 /// <remarks>
141 /// Calling to this method may result unexpedted results if the component
141 /// Calling to this method may result unexpedted results if the component
142 /// isn't in the stopped state. Call this method after the component is
142 /// isn't in the stopped state. Call this method after the component is
143 /// stopped if needed or if the component is in the failed state.
143 /// stopped if needed or if the component is in the failed state.
144 /// </remarks>
144 /// </remarks>
145 public void Dispose() {
145 public void Dispose() {
146 bool dispose = false;
146 bool dispose = false;
147 lock (SynchronizationObject) {
147 lock (SynchronizationObject) {
148 if (m_state != ExecutionState.Disposed) {
148 if (m_state != ExecutionState.Disposed) {
149 dispose = true;
149 dispose = true;
150 m_state = ExecutionState.Disposed;
150 m_state = ExecutionState.Disposed;
151 m_cookie = new object();
151 m_cookie = new object();
152 }
152 }
153 }
153 }
154 if (dispose) {
154 if (dispose) {
155 Dispose(true);
155 Dispose(true);
156 GC.SuppressFinalize(this);
156 GC.SuppressFinalize(this);
157 }
157 }
158 }
158 }
159
159
160 ~RunnableComponent() {
160 ~RunnableComponent() {
161 Dispose(false);
161 Dispose(false);
162 }
162 }
163
163
164 /// <summary>
164 /// <summary>
165 /// Releases all resources used by the current component regardless of its
165 /// Releases all resources used by the current component regardless of its
166 /// execution state.
166 /// execution state.
167 /// </summary>
167 /// </summary>
168 /// <param name="disposing">Indicates that the component is disposed
168 /// <param name="disposing">Indicates that the component is disposed
169 /// during a normal disposing or during GC.</param>
169 /// during a normal disposing or during GC.</param>
170 protected virtual void Dispose(bool disposing) {
170 protected virtual void Dispose(bool disposing) {
171 }
171 }
172
172
173 public void Initialize() {
173 public void Initialize() {
174 var cookie = new object();
174 var cookie = new object();
175 if (MoveInitialize(cookie))
175 if (MoveInitialize(cookie))
176 Safe.NoWait(ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie));
176 Safe.NoWait(ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie));
177 else
177 else
178 throw new InvalidOperationException();
178 throw new InvalidOperationException();
179 }
179 }
180
180
181 /// <summary>
181 /// <summary>
182 /// This method is used for initialization during a component creation.
182 /// This method is used for initialization during a component creation.
183 /// </summary>
183 /// </summary>
184 /// <param name="ct">A cancellation token for this operation</param>
184 /// <param name="ct">A cancellation token for this operation</param>
185 /// <remarks>
185 /// <remarks>
186 /// This method should be used for short and mostly syncronous operations,
186 /// This method should be used for short and mostly syncronous operations,
187 /// other operations which require time to run shoud be placed in
187 /// other operations which require time to run shoud be placed in
188 /// <see cref="StartInternalAsync(CancellationToken)"/> method.
188 /// <see cref="StartInternalAsync(CancellationToken)"/> method.
189 /// </remarks>
189 /// </remarks>
190 protected virtual Task InitializeInternalAsync(CancellationToken ct) {
190 protected virtual Task InitializeInternalAsync(CancellationToken ct) {
191 return Task.CompletedTask;
191 return Task.CompletedTask;
192 }
192 }
193
193
194 public void Start(CancellationToken ct) {
194 public void Start(CancellationToken ct) {
195 var cookie = new object();
195 var cookie = new object();
196 if (MoveStart(cookie))
196 if (MoveStart(cookie))
197 Safe.NoWait(ScheduleStartAndRun(ct, cookie));
197 Safe.NoWait(ScheduleStartAndRun(ct, cookie));
198 else
198 else
199 throw new InvalidOperationException();
199 throw new InvalidOperationException();
200 }
200 }
201
201
202 async Task ScheduleStartAndRun(CancellationToken ct, object cookie) {
202 async Task ScheduleStartAndRun(CancellationToken ct, object cookie) {
203 try {
203 try {
204 await ScheduleTask(StartInternalAsync, ct, cookie);
204 await ScheduleTask(StartInternalAsync, ct, cookie);
205 RunInternal();
205 RunInternal();
206 } catch (Exception err) {
206 } catch (Exception err) {
207 Fail(err);
207 Fail(err);
208 }
208 }
209 }
209 }
210
210
211 protected virtual Task StartInternalAsync(CancellationToken ct) {
211 protected virtual Task StartInternalAsync(CancellationToken ct) {
212 return Task.CompletedTask;
212 return Task.CompletedTask;
213 }
213 }
214
214
215 /// <summary>
215 /// <summary>
216 /// This method is called after the component is enetered running state,
216 /// This method is called after the component is enetered running state,
217 /// use this method to
217 /// use this method to
218 /// </summary>
218 /// </summary>
219 protected virtual void RunInternal() {
219 protected virtual void RunInternal() {
220
220
221 }
221 }
222
222
223 public void Stop(CancellationToken ct) {
223 public void Stop(CancellationToken ct) {
224 var cookie = new object();
224 var cookie = new object();
225 if (MoveStop(cookie))
225 if (MoveStop(cookie))
226 Safe.NoWait(ScheduleTask(StopAsync, ct, cookie));
226 Safe.NoWait(ScheduleTask(StopAsync, ct, cookie));
227 else
227 else
228 throw new InvalidOperationException();
228 throw new InvalidOperationException();
229 }
229 }
230
230
231 async Task StopAsync(CancellationToken ct) {
231 async Task StopAsync(CancellationToken ct) {
232 m_current.Cancel();
232 m_current.Cancel();
233 await Completion;
233 await Completion;
234
234
235 ct.ThrowIfCancellationRequested();
235 ct.ThrowIfCancellationRequested();
236
236
237 await StopInternalAsync(ct);
237 await StopInternalAsync(ct);
238 }
238 }
239
239
240 protected virtual Task StopInternalAsync(CancellationToken ct) {
240 protected virtual Task StopInternalAsync(CancellationToken ct) {
241 return Task.CompletedTask;
241 return Task.CompletedTask;
242 }
242 }
243
243
244 protected void Fail(Exception err) {
244 protected void Fail(Exception err) {
245 lock(m_lock) {
245 lock(m_lock) {
246 if (m_state != ExecutionState.Running)
246 if (m_state != ExecutionState.Running)
247 return;
247 return;
248 m_cookie = new object();
248 m_cookie = new object();
249 LastError = err;
249 LastError = err;
250 State = ExecutionState.Failed;
250 State = ExecutionState.Failed;
251 }
251 }
252 }
252 }
253
253
254
254
255 #region state management
255 #region state management
256
256
257 bool MoveInitialize(object cookie) {
257 bool MoveInitialize(object cookie) {
258 lock (m_lock) {
258 lock (m_lock) {
259 if (State != ExecutionState.Created)
259 if (State != ExecutionState.Created)
260 return false;
260 return false;
261 State = ExecutionState.Initializing;
261 State = ExecutionState.Initializing;
262 m_cookie = cookie;
262 m_cookie = cookie;
263 return true;
263 return true;
264 }
264 }
265 }
265 }
266
266
267 bool MoveStart(object cookie) {
267 bool MoveStart(object cookie) {
268 lock (m_lock) {
268 lock (m_lock) {
269 if (State != ExecutionState.Ready)
269 if (State != ExecutionState.Ready)
270 return false;
270 return false;
271 State = ExecutionState.Starting;
271 State = ExecutionState.Starting;
272 m_cookie = cookie;
272 m_cookie = cookie;
273 return true;
273 return true;
274 }
274 }
275 }
275 }
276
276
277 bool MoveStop(object cookie) {
277 bool MoveStop(object cookie) {
278 lock (m_lock) {
278 lock (m_lock) {
279 if (State != ExecutionState.Starting && State != ExecutionState.Running)
279 if (State != ExecutionState.Starting && State != ExecutionState.Running)
280 return false;
280 return false;
281 State = ExecutionState.Stopping;
281 State = ExecutionState.Stopping;
282 m_cookie = cookie;
282 m_cookie = cookie;
283 return true;
283 return true;
284 }
284 }
285 }
285 }
286
286
287 void MoveSuccess(object cookie) {
287 void MoveSuccess(object cookie) {
288 lock (m_lock) {
288 lock (m_lock) {
289 if (m_cookie != cookie)
289 if (m_cookie != cookie)
290 return;
290 return;
291 switch (State) {
291 switch (State) {
292 case ExecutionState.Initializing:
292 case ExecutionState.Initializing:
293 State = ExecutionState.Ready;
293 State = ExecutionState.Ready;
294 break;
294 break;
295 case ExecutionState.Starting:
295 case ExecutionState.Starting:
296 State = ExecutionState.Running;
296 State = ExecutionState.Running;
297 break;
297 break;
298 case ExecutionState.Stopping:
298 case ExecutionState.Stopping:
299 State = ExecutionState.Stopped;
299 State = ExecutionState.Stopped;
300 break;
300 break;
301 }
301 }
302 }
302 }
303 }
303 }
304
304
305 void MoveFailed(Exception err, object cookie) {
305 void MoveFailed(Exception err, object cookie) {
306 lock (m_lock) {
306 lock (m_lock) {
307 if (m_cookie != cookie)
307 if (m_cookie != cookie)
308 return;
308 return;
309 LastError = err;
309 LastError = err;
310 State = ExecutionState.Failed;
310 State = ExecutionState.Failed;
311 }
311 }
312 }
312 }
313
313
314 Task ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) {
314 Task ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) {
315
315
316 var op = AsyncOperationDescriptor.Create(async (x) => {
316 var op = AsyncOperationDescriptor.Create(async (x) => {
317 try {
317 try {
318 await next(x);
318 await next(x);
319 MoveSuccess(cookie);
319 MoveSuccess(cookie);
320 } catch (Exception e) {
320 } catch (Exception e) {
321 MoveFailed(e, cookie);
321 MoveFailed(e, cookie);
322 throw;
322 }
323 }
323 }, ct);
324 }, ct);
324
325
325 m_current = op;
326 m_current = op;
326 return op.Task;
327 return op.Task;
327 }
328 }
328
329
329 #endregion
330 #endregion
330 }
331 }
331 } No newline at end of file
332 }
@@ -1,64 +1,64
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4
4
5 namespace Implab {
5 namespace Implab {
6 /// <summary>
6 /// <summary>
7 /// This class is responsible for the promise resolution, dispatching and chaining
7 /// This class is responsible for the promise resolution, dispatching and chaining
8 /// </summary>
8 /// </summary>
9 public class Deferred : IResolvable {
9 public class Deferred : IResolvable {
10
10
11 readonly Promise m_promise;
11 readonly Promise m_promise;
12 internal Deferred() {
12 internal Deferred() {
13 m_promise = new Promise();
13 m_promise = new Promise();
14 }
14 }
15
15
16 internal Deferred(Promise promise, IDispatcher dispatcher) {
16 internal Deferred(Promise promise) {
17 Debug.Assert(promise != null);
17 Debug.Assert(promise != null);
18 m_promise = promise;
18 m_promise = promise;
19 }
19 }
20
20
21 public IPromise Promise {
21 public IPromise Promise {
22 get { return m_promise; }
22 get { return m_promise; }
23 }
23 }
24
24
25 public void Cancel() {
25 public void Cancel() {
26 Reject(new OperationCanceledException());
26 Reject(new OperationCanceledException());
27 }
27 }
28
28
29 public virtual void Reject(Exception error) {
29 public virtual void Reject(Exception error) {
30 if (error is PromiseTransientException)
30 if (error is PromiseTransientException)
31 error = ((PromiseTransientException)error).InnerException;
31 error = ((PromiseTransientException)error).InnerException;
32
32
33 m_promise.RejectPromise(error);
33 m_promise.RejectPromise(error);
34 }
34 }
35
35
36 public virtual void Resolve() {
36 public virtual void Resolve() {
37 m_promise.ResolvePromise();
37 m_promise.ResolvePromise();
38 }
38 }
39
39
40 public virtual void Resolve(IPromise thenable) {
40 public virtual void Resolve(IPromise thenable) {
41 if (thenable == null)
41 if (thenable == null)
42 Reject(new Exception("The promise or task are expected"));
42 Reject(new Exception("The promise or task are expected"));
43 if (thenable == m_promise)
43 if (thenable == m_promise)
44 Reject(new Exception("The promise cannot be resolved with oneself"));
44 Reject(new Exception("The promise cannot be resolved with oneself"));
45
45
46 try {
46 try {
47 thenable.Then(this);
47 thenable.Then(this);
48 } catch (Exception err) {
48 } catch (Exception err) {
49 Reject(err);
49 Reject(err);
50 }
50 }
51 }
51 }
52
52
53 public virtual void Resolve(Task thenable) {
53 public virtual void Resolve(Task thenable) {
54 if (thenable == null)
54 if (thenable == null)
55 Reject(new Exception("The promise or task are expected"));
55 Reject(new Exception("The promise or task are expected"));
56 try {
56 try {
57 thenable.Then(this);
57 thenable.Then(this);
58 } catch(Exception err) {
58 } catch(Exception err) {
59 Reject(err);
59 Reject(err);
60 }
60 }
61 }
61 }
62
62
63 }
63 }
64 } No newline at end of file
64 }
@@ -1,19 +1,22
1 <Project Sdk="Microsoft.NET.Sdk">
1 <Project Sdk="Microsoft.NET.Sdk">
2
2
3 <PropertyGroup>
3 <PropertyGroup>
4 <Authors>Sergey Smirnov</Authors>
4 <Authors>Sergey Smirnov</Authors>
5 <Title>Implab library</Title>
5 <Title>Implab library</Title>
6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
9 </Description>
9 </Description>
10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
11 <LicenseUrl>https://opensource.org/licenses/BSD-2-Clause</LicenseUrl>
11 <Version>3.0.6</Version>
12 <ProjectUrl>https://implab.org</ProjectUrl>
12 <PackageLicenseUrl>https://opensource.org/licenses/BSD-2-Clause</PackageLicenseUrl>
13 <PackageProjectUrl>https://implab.org</PackageProjectUrl>
13 <RepositoryUrl>https://hg.implab.org/pub/ImplabNet/</RepositoryUrl>
14 <RepositoryUrl>https://hg.implab.org/pub/ImplabNet/</RepositoryUrl>
15 <RepositoryType>mercurial</RepositoryType>
16 <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags>
14 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
17 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
15 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
18 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
16 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
19 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
17 </PropertyGroup>
20 </PropertyGroup>
18
21
19 </Project>
22 </Project>
@@ -1,208 +1,222
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Diagnostics;
3 using System.Diagnostics;
4 using System.Reflection;
4 using System.Reflection;
5 using System.Threading;
5 using System.Threading.Tasks;
6 using System.Threading.Tasks;
6 using Implab.Parallels;
7 using Implab.Parallels;
7
8
8 namespace Implab {
9 namespace Implab {
9 public class Promise : AbstractEvent<IResolvable>, IPromise {
10 public class Promise : AbstractEvent<IResolvable>, IPromise {
10 public static IDispatcher DefaultDispatcher {
11 public static IDispatcher DefaultDispatcher {
11 get {
12 get {
12 return ThreadPoolDispatcher.Instance;
13 return ThreadPoolDispatcher.Instance;
13 }
14 }
14 }
15 }
15
16
16 class ResolvableSignal : IResolvable {
17 class ResolvableSignal : IResolvable {
17 public Signal Signal { get; private set; }
18 public Signal Signal { get; private set; }
18 public ResolvableSignal() {
19 public ResolvableSignal() {
19 Signal = new Signal();
20 Signal = new Signal();
20 }
21 }
21
22
22
23
23 public void Reject(Exception error) {
24 public void Reject(Exception error) {
24 Signal.Set();
25 Signal.Set();
25 }
26 }
26
27
27 public void Resolve() {
28 public void Resolve() {
28 Signal.Set();
29 Signal.Set();
29 }
30 }
30 }
31 }
31
32
32 PromiseState m_state;
33 PromiseState m_state;
33
34
34 Exception m_error;
35 Exception m_error;
35
36
36 public bool IsRejected {
37 public bool IsRejected {
37 get {
38 get {
38 return m_state == PromiseState.Rejected;
39 return m_state == PromiseState.Rejected;
39 }
40 }
40 }
41 }
41
42
42 public bool IsFulfilled {
43 public bool IsFulfilled {
43 get {
44 get {
44 return m_state == PromiseState.Fulfilled;
45 return m_state == PromiseState.Fulfilled;
45 }
46 }
46 }
47 }
47
48
48 public Exception RejectReason {
49 public Exception RejectReason {
49 get {
50 get {
50 return m_error;
51 return m_error;
51 }
52 }
52 }
53 }
53
54
54 internal Promise() {
55 internal Promise() {
55
56
56 }
57 }
57
58
58 internal void ResolvePromise() {
59 internal void ResolvePromise() {
59 if (BeginTransit()) {
60 if (BeginTransit()) {
60 m_state = PromiseState.Fulfilled;
61 m_state = PromiseState.Fulfilled;
61 CompleteTransit();
62 CompleteTransit();
62 }
63 }
63 }
64 }
64
65
65 internal void RejectPromise(Exception reason) {
66 internal void RejectPromise(Exception reason) {
66 if (BeginTransit()) {
67 if (BeginTransit()) {
67 m_error = reason;
68 m_error = reason;
68 m_state = PromiseState.Rejected;
69 m_state = PromiseState.Rejected;
69 CompleteTransit();
70 CompleteTransit();
70 }
71 }
71 }
72 }
72
73
73
74
74 #region implemented abstract members of AbstractPromise
75 #region implemented abstract members of AbstractPromise
75
76
76 protected override void SignalHandler(IResolvable handler) {
77 protected override void SignalHandler(IResolvable handler) {
77 switch (m_state) {
78 switch (m_state) {
78 case PromiseState.Fulfilled:
79 case PromiseState.Fulfilled:
79 handler.Resolve();
80 handler.Resolve();
80 break;
81 break;
81 case PromiseState.Rejected:
82 case PromiseState.Rejected:
82 handler.Reject(RejectReason);
83 handler.Reject(RejectReason);
83 break;
84 break;
84 default:
85 default:
85 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
86 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
86 }
87 }
87 }
88 }
88
89
89 protected void WaitResult(int timeout) {
90 protected void WaitResult(int timeout) {
90 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
91 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
91 throw new TimeoutException();
92 throw new TimeoutException();
92 }
93 }
93
94
94 protected Signal GetFulfillSignal() {
95 protected Signal GetFulfillSignal() {
95 var next = new ResolvableSignal();
96 var next = new ResolvableSignal();
96 Then(next);
97 Then(next);
97 return next.Signal;
98 return next.Signal;
98 }
99 }
99
100
100 #endregion
101 #endregion
101
102
102
103
103 public Type ResultType {
104 public Type ResultType {
104 get {
105 get {
105 return typeof(void);
106 return typeof(void);
106 }
107 }
107 }
108 }
108
109
109
110
110 protected void Rethrow() {
111 protected void Rethrow() {
111 Debug.Assert(m_error != null);
112 Debug.Assert(m_error != null);
112 if (m_error is OperationCanceledException)
113 if (m_error is OperationCanceledException)
113 throw new OperationCanceledException("Operation cancelled", m_error);
114 throw new OperationCanceledException("Operation cancelled", m_error);
114 else
115 else
115 throw new TargetInvocationException(m_error);
116 throw new TargetInvocationException(m_error);
116 }
117 }
117
118
118 public void Then(IResolvable next) {
119 public void Then(IResolvable next) {
119 AddHandler(next);
120 AddHandler(next);
120 }
121 }
121
122
122 public IPromise<T> Cast<T>() {
123 public IPromise<T> Cast<T>() {
123 throw new InvalidCastException();
124 throw new InvalidCastException();
124 }
125 }
125
126
126 public void Join() {
127 public void Join() {
127 WaitResult(-1);
128 WaitResult(-1);
128 if (IsRejected)
129 if (IsRejected)
129 Rethrow();
130 Rethrow();
130 }
131 }
131
132
132 public void Join(int timeout) {
133 public void Join(int timeout) {
133 WaitResult(timeout);
134 WaitResult(timeout);
134 if (IsRejected)
135 if (IsRejected)
135 Rethrow();
136 Rethrow();
136 }
137 }
137
138
138 public static ResolvedPromise Resolve() {
139 public static ResolvedPromise Resolve() {
139 return new ResolvedPromise();
140 return new ResolvedPromise();
140 }
141 }
141
142
142 public static ResolvedPromise<T> Resolve<T>(T result) {
143 public static ResolvedPromise<T> Resolve<T>(T result) {
143 return new ResolvedPromise<T>(result);
144 return new ResolvedPromise<T>(result);
144 }
145 }
145
146
146 public static RejectedPromise Reject(Exception reason) {
147 public static RejectedPromise Reject(Exception reason) {
147 return new RejectedPromise(reason);
148 return new RejectedPromise(reason);
148 }
149 }
149
150
150 public static RejectedPromise<T> Reject<T>(Exception reason) {
151 public static RejectedPromise<T> Reject<T>(Exception reason) {
151 return new RejectedPromise<T>(reason);
152 return new RejectedPromise<T>(reason);
152 }
153 }
153
154
154 public static IPromise Create(PromiseExecutor executor) {
155 public static IPromise Create(PromiseExecutor executor) {
155 Safe.ArgumentNotNull(executor, nameof(executor));
156 return Create(executor, CancellationToken.None);
157 }
156
158
157 var p = new Promise();
159 public static IPromise Create(PromiseExecutor executor, CancellationToken ct) {
158 var d = new Deferred(p, DefaultDispatcher);
160 Safe.ArgumentNotNull(executor, nameof(executor));
159
161 if (!ct.CanBeCanceled)
162 return Create(executor);
163
164 var d = new Deferred();
165
166 ct.Register(d.Cancel);
167
160 try {
168 try {
161 executor(d);
169 if (!ct.IsCancellationRequested)
162 } catch (Exception e) {
170 executor(d);
171 } catch(Exception e) {
163 d.Reject(e);
172 d.Reject(e);
164 }
173 }
165
166 return d.Promise;
174 return d.Promise;
167 }
175 }
168
176
169 public static IPromise<T> Create<T>(PromiseExecutor<T> executor) {
177 public static IPromise<T> Create<T>(PromiseExecutor<T> executor) {
178 return Create(executor, CancellationToken.None);
179 }
180
181 public static IPromise<T> Create<T>(PromiseExecutor<T> executor, CancellationToken ct) {
170 Safe.ArgumentNotNull(executor, nameof(executor));
182 Safe.ArgumentNotNull(executor, nameof(executor));
171
183
172 var d = new Deferred<T>();
184 var d = new Deferred<T>();
173
185
186 ct.Register(d.Cancel);
187
174 try {
188 try {
175 executor(d);
189 if (!ct.IsCancellationRequested)
176 } catch (Exception e) {
190 executor(d);
191 } catch(Exception e) {
177 d.Reject(e);
192 d.Reject(e);
178 }
193 }
179
180 return d.Promise;
194 return d.Promise;
181 }
195 }
182
196
183 public static IPromise All(IEnumerable<IPromise> promises) {
197 public static IPromise All(IEnumerable<IPromise> promises) {
184 var d = new Deferred();
198 var d = new Deferred();
185 var all = new PromiseAll(d);
199 var all = new PromiseAll(d);
186 foreach (var promise in promises) {
200 foreach (var promise in promises) {
187 all.AddPromise(promise);
201 all.AddPromise(promise);
188 if (all.Done)
202 if (all.Done)
189 break;
203 break;
190 }
204 }
191 all.Complete();
205 all.Complete();
192 return all.ResultPromise;
206 return all.ResultPromise;
193 }
207 }
194
208
195 public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup = null, Action cancel = null) {
209 public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup = null, Action cancel = null) {
196 var d = new Deferred<T[]>();
210 var d = new Deferred<T[]>();
197 var all = new PromiseAll<T>(d, cleanup, cancel);
211 var all = new PromiseAll<T>(d, cleanup, cancel);
198 foreach (var promise in promises) {
212 foreach (var promise in promises) {
199 all.AddPromise(promise);
213 all.AddPromise(promise);
200 if (all.Done)
214 if (all.Done)
201 break;
215 break;
202 }
216 }
203 all.Complete();
217 all.Complete();
204 return all.ResultPromise;
218 return all.ResultPromise;
205 }
219 }
206 }
220 }
207 }
221 }
208
222
1 NO CONTENT: file was removed
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