-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNativeExecutionLane.cs
More file actions
89 lines (77 loc) · 2.36 KB
/
Copy pathNativeExecutionLane.cs
File metadata and controls
89 lines (77 loc) · 2.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
namespace DotPython.Worker.Host;
[SuppressMessage(
"Design",
"CA1031:Do not catch general exception types",
Justification = "The owning native lane must transfer every operation failure to its awaiting worker request."
)]
internal sealed class NativeExecutionLane : IAsyncDisposable
{
private readonly BlockingCollection<IWorkItem> _queue = new(32);
private readonly Thread _thread;
private int _disposed;
internal NativeExecutionLane()
{
_thread = new Thread(Run)
{
IsBackground = true,
Name = "DotPython Stable-ABI worker lane",
};
_thread.Start();
}
internal Task<T> InvokeAsync<T>(Func<T> operation, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(operation);
ObjectDisposedException.ThrowIf(Volatile.Read(ref _disposed) != 0, this);
cancellationToken.ThrowIfCancellationRequested();
var work = new WorkItem<T>(operation, cancellationToken);
_queue.Add(work, cancellationToken);
return work.Completion;
}
public ValueTask DisposeAsync()
{
if (Interlocked.Exchange(ref _disposed, 1) == 0)
{
_queue.CompleteAdding();
_thread.Join();
_queue.Dispose();
}
return ValueTask.CompletedTask;
}
private void Run()
{
foreach (var work in _queue.GetConsumingEnumerable())
{
work.Execute();
}
}
private interface IWorkItem
{
void Execute();
}
private sealed class WorkItem<T>(Func<T> operation, CancellationToken cancellationToken)
: IWorkItem
{
private readonly TaskCompletionSource<T> _completion = new(
TaskCreationOptions.RunContinuationsAsynchronously
);
internal Task<T> Completion => _completion.Task;
public void Execute()
{
if (cancellationToken.IsCancellationRequested)
{
_completion.TrySetCanceled(cancellationToken);
return;
}
try
{
_completion.TrySetResult(operation());
}
catch (Exception exception)
{
_completion.TrySetException(exception);
}
}
}
}