Skip to content

Commit d19d317

Browse files
committed
- rebase
- generate with 0.2.1
1 parent ab03e0f commit d19d317

File tree

18 files changed

+468
-61
lines changed

18 files changed

+468
-61
lines changed

src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,50 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Threading;
67
using System.Threading.Tasks;
78
using Microsoft.DotNet.XHarness.TestRunners.Common;
89
using Microsoft.DotNet.XHarness.TestRunners.Xunit;
10+
using System.Runtime.CompilerServices;
911

1012
public class WasmTestRunner : WasmApplicationEntryPoint
1113
{
1214
protected int MaxParallelThreadsFromArg { get; set; }
1315
protected override int? MaxParallelThreads => RunInParallel ? MaxParallelThreadsFromArg : base.MaxParallelThreads;
1416

15-
public static async Task<int> Main(string[] args)
17+
#if TARGET_WASI
18+
public static int Main(string[] args)
19+
{
20+
var task = MainAsync(args);
21+
while (!task.IsCompleted)
22+
{
23+
DispatchWasiEventLoop();
24+
}
25+
var exception = task.Exception;
26+
if (exception is not null)
27+
{
28+
throw exception;
29+
}
30+
31+
return task.Result;
32+
}
33+
34+
internal static void DispatchWasiEventLoop()
35+
{
36+
CallDispatchWasiEventLoop((Thread)null!);
37+
38+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")]
39+
static extern void CallDispatchWasiEventLoop(Thread t);
40+
}
41+
42+
#else
43+
public static Task<int> Main(string[] args)
44+
{
45+
return MainAsync(args);
46+
}
47+
#endif
48+
49+
public static async Task<int> MainAsync(string[] args)
1650
{
1751
if (args.Length == 0)
1852
{

src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
<PropertyGroup>
33
<OutputType>Exe</OutputType>
44
<Nullable>enable</Nullable>
5-
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
5+
<TargetFrameworks>$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)</TargetFrameworks>
6+
</PropertyGroup>
7+
<!-- DesignTimeBuild requires all the TargetFramework Derived Properties to not be present in the first property group. -->
8+
<PropertyGroup>
9+
<TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
10+
<DefineConstants Condition="'$(TargetPlatformIdentifier)' == 'browser'">$(DefineConstants);TARGET_BROWSER</DefineConstants>
11+
<DefineConstants Condition="'$(TargetPlatformIdentifier)' == 'wasi'">$(DefineConstants);TARGET_WASI</DefineConstants>
612
</PropertyGroup>
713
<ItemGroup>
814
<Compile Include="WasmTestRunner.cs" />

src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,16 @@ private static class WasiEventLoop
466466
internal static Task RegisterWasiPollable(IPoll.Pollable pollable)
467467
{
468468
var handle = pollable.Handle;
469+
470+
// this will effectively neutralize Dispose() of the Pollable()
471+
// because in the CoreLib we create another instance, which will dispose it
469472
pollable.Handle = 0;
470-
return CallRegisterWasiPollable((Thread)null!, handle);
473+
GC.SuppressFinalize(pollable);
474+
475+
return CallRegisterWasiPollableHandle((Thread)null!, handle);
471476

472-
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollable")]
473-
static extern Task CallRegisterWasiPollable(Thread t, int handle);
477+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollableHandle")]
478+
static extern Task CallRegisterWasiPollableHandle(Thread t, int handle);
474479
}
475480
}
476481

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,7 @@
28042804
<ItemGroup Condition="'$(TargetsWasi)' == 'true'">
28052805
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiEventLoop.cs" />
28062806
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPoll.cs" />
2807+
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop.cs" />
28072808
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.cs" />
28082809
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Wasi\WasiPollWorld.wit.imports.wasi.io.v0_2_1.PollInterop.cs" />
28092810
</ItemGroup>

src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ public sealed partial class Thread
1212
{
1313
// these methods are temporarily accessed via UnsafeAccessor from generated code until we have it in public API, probably in WASI preview3 and promises
1414
#if TARGET_WASI
15-
internal static System.Threading.Tasks.Task RegisterWasiPollable(int handle)
15+
internal static System.Threading.Tasks.Task RegisterWasiPollableHandle(int handle)
1616
{
17-
return WasiEventLoop.RegisterWasiPollable(handle);
17+
return WasiEventLoop.RegisterWasiPollableHandle(handle);
1818
}
1919

2020
internal static void DispatchWasiEventLoop()

src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,64 @@ namespace System.Threading
99
{
1010
internal static class WasiEventLoop
1111
{
12-
private static List<(IPoll.Pollable, TaskCompletionSource)> pollables = new();
12+
private static List<WeakReference<TaskCompletionSource>> s_pollables = new();
1313

14-
internal static Task RegisterWasiPollable(int handle)
14+
internal static Task RegisterWasiPollableHandle(int handle)
1515
{
16-
var source = new TaskCompletionSource(TaskCreationOptions.AttachedToParent);
17-
pollables.Add((new IPoll.Pollable(new IPoll.Pollable.THandle(handle)), source));
18-
return source.Task;
16+
// note that this is duplicate of the original Pollable
17+
// the original should be neutralized without disposing the handle
18+
var pollableCpy = new IPoll.Pollable(new IPoll.Pollable.THandle(handle));
19+
return RegisterWasiPollable(pollableCpy);
20+
}
21+
22+
internal static Task RegisterWasiPollable(IPoll.Pollable pollable)
23+
{
24+
var tcs = new TaskCompletionSource(pollable);
25+
var weakRef = new WeakReference<TaskCompletionSource>(tcs);
26+
s_pollables.Add(weakRef);
27+
return tcs.Task;
1928
}
2029

2130
internal static void DispatchWasiEventLoop()
2231
{
2332
ThreadPoolWorkQueue.Dispatch();
2433

25-
if (WasiEventLoop.pollables.Count > 0)
34+
if (s_pollables.Count > 0)
2635
{
27-
var pollables = WasiEventLoop.pollables;
28-
WasiEventLoop.pollables = new();
29-
var arguments = new List<IPoll.Pollable>();
30-
var sources = new List<TaskCompletionSource>();
31-
foreach ((var pollable, var source) in pollables)
36+
var pollables = s_pollables;
37+
s_pollables = new List<WeakReference<TaskCompletionSource>>(pollables.Count);
38+
var arguments = new List<IPoll.Pollable>(pollables.Count);
39+
var indexes = new List<int>(pollables.Count);
40+
for (var i = 0; i < pollables.Count; i++)
3241
{
33-
arguments.Add(pollable);
34-
sources.Add(source);
42+
var weakRef = pollables[i];
43+
if (weakRef.TryGetTarget(out TaskCompletionSource? tcs))
44+
{
45+
var pollable = (IPoll.Pollable)tcs!.Task.AsyncState!;
46+
arguments.Add(pollable);
47+
indexes.Add(i);
48+
}
3549
}
36-
var results = PollInterop.Poll(arguments);
50+
51+
// this is blocking until at least one pollable resolves
52+
var readyIndexes = PollInterop.Poll(arguments);
53+
3754
var ready = new bool[arguments.Count];
38-
foreach (var result in results)
55+
foreach (int readyIndex in readyIndexes)
3956
{
40-
ready[result] = true;
41-
arguments[(int)result].Dispose();
42-
sources[(int)result].SetResult();
57+
ready[readyIndex] = true;
58+
arguments[readyIndex].Dispose();
59+
var weakRef = pollables[indexes[readyIndex]];
60+
if (weakRef.TryGetTarget(out TaskCompletionSource? tcs))
61+
{
62+
tcs!.SetResult();
63+
}
4364
}
4465
for (var i = 0; i < arguments.Count; ++i)
4566
{
4667
if (!ready[i])
4768
{
48-
WasiEventLoop.pollables.Add((arguments[i], sources[i]));
69+
s_pollables.Add(pollables[indexes[i]]);
4970
}
5071
}
5172
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Generated by `wit-bindgen` 0.29.0. DO NOT EDIT!
2+
// <auto-generated />
3+
#nullable enable
4+
5+
using System;
6+
using System.Runtime.CompilerServices;
7+
using System.Collections;
8+
using System.Runtime.InteropServices;
9+
using System.Text;
10+
using System.Collections.Generic;
11+
using System.Diagnostics;
12+
using System.Diagnostics.CodeAnalysis;
13+
14+
namespace WasiPollWorld.wit.imports.wasi.clocks.v0_2_1
15+
{
16+
internal static class MonotonicClockInterop {
17+
18+
internal static class NowWasmInterop
19+
{
20+
[DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "now"), WasmImportLinkage]
21+
internal static extern long wasmImportNow();
22+
23+
}
24+
25+
internal static unsafe ulong Now()
26+
{
27+
var result = NowWasmInterop.wasmImportNow();
28+
return unchecked((ulong)(result));
29+
30+
//TODO: free alloc handle (interopString) if exists
31+
}
32+
33+
internal static class ResolutionWasmInterop
34+
{
35+
[DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "resolution"), WasmImportLinkage]
36+
internal static extern long wasmImportResolution();
37+
38+
}
39+
40+
internal static unsafe ulong Resolution()
41+
{
42+
var result = ResolutionWasmInterop.wasmImportResolution();
43+
return unchecked((ulong)(result));
44+
45+
//TODO: free alloc handle (interopString) if exists
46+
}
47+
48+
internal static class SubscribeInstantWasmInterop
49+
{
50+
[DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "subscribe-instant"), WasmImportLinkage]
51+
internal static extern int wasmImportSubscribeInstant(long p0);
52+
53+
}
54+
55+
internal static unsafe global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable SubscribeInstant(ulong when)
56+
{
57+
var result = SubscribeInstantWasmInterop.wasmImportSubscribeInstant(unchecked((long)(when)));
58+
var resource = new global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable(new global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable.THandle(result));
59+
return resource;
60+
61+
//TODO: free alloc handle (interopString) if exists
62+
}
63+
64+
internal static class SubscribeDurationWasmInterop
65+
{
66+
[DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "subscribe-duration"), WasmImportLinkage]
67+
internal static extern int wasmImportSubscribeDuration(long p0);
68+
69+
}
70+
71+
internal static unsafe global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable SubscribeDuration(ulong when)
72+
{
73+
var result = SubscribeDurationWasmInterop.wasmImportSubscribeDuration(unchecked((long)(when)));
74+
var resource = new global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable(new global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable.THandle(result));
75+
return resource;
76+
77+
//TODO: free alloc handle (interopString) if exists
78+
}
79+
80+
}
81+
}

src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/generate-wasi-poll-bindings.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tar xzf v0.2.1.tar.gz
1717
cat >wasi-http-0.2.1/wit/world.wit <<EOF
1818
world wasi-poll {
1919
import wasi:io/poll@0.2.1;
20+
import wasi:clocks/monotonic-clock@0.2.1;
2021
}
2122
EOF
2223
wit-bindgen c-sharp -w wasi-poll -r native-aot --internal --skip-support-files wasi-http-0.2.1/wit

src/libraries/tests.proj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@
581581
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Buffers.Tests\System.Buffers.Tests.csproj" />
582582
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Globalization.Tests\Invariant\Invariant.Tests.csproj" />
583583
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Globalization.Tests\System.Globalization.Tests.csproj" />
584+
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Threading.Timer.Tests\System.Threading.Timer.Tests.csproj" />
584585
</ItemGroup>
585586

586587
<!-- wasi/aot smoke tests -->

src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
<ItemGroup>
135135
<ILLinkDescriptorsXmls Include="$(ILLinkDirectory)ILLink.Descriptors.xml" />
136136
<ILLinkDescriptorsXmls Include="$(ILLinkDirectory)ILLink.Descriptors.OSX.xml" Condition="'$(TargetsOSX)' == 'true' or '$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'" />
137+
<ILLinkDescriptorsXmls Include="$(ILLinkDirectory)ILLink.Descriptors.WASI.xml" Condition="'$(TargetsWASI)' == 'true'" />
137138
<ILLinkDescriptorsXmls Include="$(CoreLibSharedDir)ILLink\ILLink.Descriptors.Shared.xml" />
138139
<ILLinkDescriptorsXmls Condition="'$(FeaturePerfTracing)' == 'true'" Include="$(CoreLibSharedDir)ILLink\ILLink.Descriptors.EventSource.xml" />
139140

0 commit comments

Comments
 (0)