From d19d31786860a109da9fb637d6a08ccb8660aa0a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 5 Aug 2024 17:46:29 +0200 Subject: [PATCH 01/13] - rebase - generate with 0.2.1 --- .../tests/WasmTestRunner/WasmTestRunner.cs | 36 ++++- .../WasmTestRunner/WasmTestRunner.csproj | 8 +- .../Http/WasiHttpHandler/WasiHttpHandler.cs | 11 +- .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Threading/Thread.Unix.cs | 4 +- .../System/Threading/Wasi/WasiEventLoop.cs | 59 +++++--- ...asi.clocks.v0_2_1.MonotonicClockInterop.cs | 81 ++++++++++ .../Wasi/generate-wasi-poll-bindings.sh | 1 + src/libraries/tests.proj | 1 + .../System.Private.CoreLib.csproj | 1 + .../src/ILLink/ILLink.Descriptors.WASI.xml | 10 ++ .../Threading/TimerQueue.Browser.Mono.cs | 3 + .../System/Threading/TimerQueue.Wasi.Mono.cs | 143 ++++++++++++++++-- src/mono/sample/wasi/http-p2/Program.cs | 40 +++-- .../wasi/Wasi.Build.Tests/BuildTestBase.cs | 8 +- src/mono/wasi/Wasi.Build.Tests/HttpTests.cs | 69 +++++++++ .../Wasi.Build.Tests/WasiTemplateTests.cs | 2 +- src/mono/wasi/testassets/Http.cs | 51 +++++++ 18 files changed, 468 insertions(+), 61 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop.cs create mode 100644 src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml create mode 100644 src/mono/wasi/Wasi.Build.Tests/HttpTests.cs create mode 100644 src/mono/wasi/testassets/Http.cs diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 98798cba791a7c..10ff7c5a90dfee 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -3,16 +3,50 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.XHarness.TestRunners.Common; using Microsoft.DotNet.XHarness.TestRunners.Xunit; +using System.Runtime.CompilerServices; public class WasmTestRunner : WasmApplicationEntryPoint { protected int MaxParallelThreadsFromArg { get; set; } protected override int? MaxParallelThreads => RunInParallel ? MaxParallelThreadsFromArg : base.MaxParallelThreads; - public static async Task Main(string[] args) +#if TARGET_WASI + public static int Main(string[] args) + { + var task = MainAsync(args); + while (!task.IsCompleted) + { + DispatchWasiEventLoop(); + } + var exception = task.Exception; + if (exception is not null) + { + throw exception; + } + + return task.Result; + } + + internal static void DispatchWasiEventLoop() + { + CallDispatchWasiEventLoop((Thread)null!); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] + static extern void CallDispatchWasiEventLoop(Thread t); + } + +#else + public static Task Main(string[] args) + { + return MainAsync(args); + } +#endif + + public static async Task MainAsync(string[] args) { if (args.Length == 0) { diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj index 2f60f08a55c44a..0175da89d58ce2 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj @@ -2,7 +2,13 @@ Exe enable - $(NetCoreAppCurrent) + $(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent) + + + + $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) + $(DefineConstants);TARGET_BROWSER + $(DefineConstants);TARGET_WASI diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs index ee45aebef883e4..f9333bf1c4f2c9 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs @@ -466,11 +466,16 @@ private static class WasiEventLoop internal static Task RegisterWasiPollable(IPoll.Pollable pollable) { var handle = pollable.Handle; + + // this will effectively neutralize Dispose() of the Pollable() + // because in the CoreLib we create another instance, which will dispose it pollable.Handle = 0; - return CallRegisterWasiPollable((Thread)null!, handle); + GC.SuppressFinalize(pollable); + + return CallRegisterWasiPollableHandle((Thread)null!, handle); - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollable")] - static extern Task CallRegisterWasiPollable(Thread t, int handle); + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollableHandle")] + static extern Task CallRegisterWasiPollableHandle(Thread t, int handle); } } diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index e9a354d8fcc8aa..b8987a495de3be 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2804,6 +2804,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs index 2535f8a4139668..22be1b9b0e8768 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs @@ -12,9 +12,9 @@ public sealed partial class Thread { // these methods are temporarily accessed via UnsafeAccessor from generated code until we have it in public API, probably in WASI preview3 and promises #if TARGET_WASI - internal static System.Threading.Tasks.Task RegisterWasiPollable(int handle) + internal static System.Threading.Tasks.Task RegisterWasiPollableHandle(int handle) { - return WasiEventLoop.RegisterWasiPollable(handle); + return WasiEventLoop.RegisterWasiPollableHandle(handle); } internal static void DispatchWasiEventLoop() diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index b4e1fda158c6ff..379c5c001c08a6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -9,43 +9,64 @@ namespace System.Threading { internal static class WasiEventLoop { - private static List<(IPoll.Pollable, TaskCompletionSource)> pollables = new(); + private static List> s_pollables = new(); - internal static Task RegisterWasiPollable(int handle) + internal static Task RegisterWasiPollableHandle(int handle) { - var source = new TaskCompletionSource(TaskCreationOptions.AttachedToParent); - pollables.Add((new IPoll.Pollable(new IPoll.Pollable.THandle(handle)), source)); - return source.Task; + // note that this is duplicate of the original Pollable + // the original should be neutralized without disposing the handle + var pollableCpy = new IPoll.Pollable(new IPoll.Pollable.THandle(handle)); + return RegisterWasiPollable(pollableCpy); + } + + internal static Task RegisterWasiPollable(IPoll.Pollable pollable) + { + var tcs = new TaskCompletionSource(pollable); + var weakRef = new WeakReference(tcs); + s_pollables.Add(weakRef); + return tcs.Task; } internal static void DispatchWasiEventLoop() { ThreadPoolWorkQueue.Dispatch(); - if (WasiEventLoop.pollables.Count > 0) + if (s_pollables.Count > 0) { - var pollables = WasiEventLoop.pollables; - WasiEventLoop.pollables = new(); - var arguments = new List(); - var sources = new List(); - foreach ((var pollable, var source) in pollables) + var pollables = s_pollables; + s_pollables = new List>(pollables.Count); + var arguments = new List(pollables.Count); + var indexes = new List(pollables.Count); + for (var i = 0; i < pollables.Count; i++) { - arguments.Add(pollable); - sources.Add(source); + var weakRef = pollables[i]; + if (weakRef.TryGetTarget(out TaskCompletionSource? tcs)) + { + var pollable = (IPoll.Pollable)tcs!.Task.AsyncState!; + arguments.Add(pollable); + indexes.Add(i); + } } - var results = PollInterop.Poll(arguments); + + // this is blocking until at least one pollable resolves + var readyIndexes = PollInterop.Poll(arguments); + var ready = new bool[arguments.Count]; - foreach (var result in results) + foreach (int readyIndex in readyIndexes) { - ready[result] = true; - arguments[(int)result].Dispose(); - sources[(int)result].SetResult(); + ready[readyIndex] = true; + arguments[readyIndex].Dispose(); + var weakRef = pollables[indexes[readyIndex]]; + if (weakRef.TryGetTarget(out TaskCompletionSource? tcs)) + { + tcs!.SetResult(); + } } for (var i = 0; i < arguments.Count; ++i) { if (!ready[i]) { - WasiEventLoop.pollables.Add((arguments[i], sources[i])); + s_pollables.Add(pollables[indexes[i]]); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop.cs new file mode 100644 index 00000000000000..1a0ef026540eb5 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiPollWorld.wit.imports.wasi.clocks.v0_2_1.MonotonicClockInterop.cs @@ -0,0 +1,81 @@ +// Generated by `wit-bindgen` 0.29.0. DO NOT EDIT! +// +#nullable enable + +using System; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Runtime.InteropServices; +using System.Text; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace WasiPollWorld.wit.imports.wasi.clocks.v0_2_1 +{ + internal static class MonotonicClockInterop { + + internal static class NowWasmInterop + { + [DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "now"), WasmImportLinkage] + internal static extern long wasmImportNow(); + + } + + internal static unsafe ulong Now() + { + var result = NowWasmInterop.wasmImportNow(); + return unchecked((ulong)(result)); + + //TODO: free alloc handle (interopString) if exists + } + + internal static class ResolutionWasmInterop + { + [DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "resolution"), WasmImportLinkage] + internal static extern long wasmImportResolution(); + + } + + internal static unsafe ulong Resolution() + { + var result = ResolutionWasmInterop.wasmImportResolution(); + return unchecked((ulong)(result)); + + //TODO: free alloc handle (interopString) if exists + } + + internal static class SubscribeInstantWasmInterop + { + [DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "subscribe-instant"), WasmImportLinkage] + internal static extern int wasmImportSubscribeInstant(long p0); + + } + + internal static unsafe global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable SubscribeInstant(ulong when) + { + var result = SubscribeInstantWasmInterop.wasmImportSubscribeInstant(unchecked((long)(when))); + 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)); + return resource; + + //TODO: free alloc handle (interopString) if exists + } + + internal static class SubscribeDurationWasmInterop + { + [DllImport("wasi:clocks/monotonic-clock@0.2.1", EntryPoint = "subscribe-duration"), WasmImportLinkage] + internal static extern int wasmImportSubscribeDuration(long p0); + + } + + internal static unsafe global::WasiPollWorld.wit.imports.wasi.io.v0_2_1.IPoll.Pollable SubscribeDuration(ulong when) + { + var result = SubscribeDurationWasmInterop.wasmImportSubscribeDuration(unchecked((long)(when))); + 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)); + return resource; + + //TODO: free alloc handle (interopString) if exists + } + + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/generate-wasi-poll-bindings.sh b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/generate-wasi-poll-bindings.sh index bbc088167661e7..fd20df8e9df20f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/generate-wasi-poll-bindings.sh +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/generate-wasi-poll-bindings.sh @@ -17,6 +17,7 @@ tar xzf v0.2.1.tar.gz cat >wasi-http-0.2.1/wit/world.wit < + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 16a66d28788be6..c57983d44dbcb4 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -134,6 +134,7 @@ + diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml new file mode 100644 index 00000000000000..f5e626c35dc6d7 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs index dce59b97046fd7..47795f22067067 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Browser.Mono.cs @@ -9,6 +9,9 @@ namespace System.Threading { +#if FEATURE_WASM_MANAGED_THREADS +#error when compiled with FEATURE_WASM_MANAGED_THREADS, we use TimerQueue.Portable.cs +#endif // // Browser-specific implementation of Timer // Based on TimerQueue.Portable.cs diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs index 309f9df6c31b18..119ba0a17738ad 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs @@ -3,30 +3,155 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; +using System.Threading.Tasks; +using WasiPollWorld.wit.imports.wasi.clocks.v0_2_0; namespace System.Threading { +#if FEATURE_WASM_MANAGED_THREADS +#error when compiled with FEATURE_WASM_MANAGED_THREADS, we will use TimerQueue.Portable.cs +#endif // - // Wasi-specific implementation of Timer + // Wasi implementation of Timer, single-threaded, on top of pollable and wasi:clocks // Based on TimerQueue.Portable.cs // Not thread safe // - internal partial class TimerQueue + internal sealed partial class TimerQueue { private static long TickCount64 => Environment.TickCount64; + private static List? s_scheduledTimers; + private static List? s_scheduledTimersToFire; + private static long s_shortestDueTimeMs = long.MaxValue; + // this means that it's in the s_scheduledTimers collection, not that it's the one which would run on the next TimeoutCallback + private bool _isScheduled; + private long _scheduledDueTimeMs; private TimerQueue(int _) { - throw new PlatformNotSupportedException(); } -#pragma warning disable CA1822 // Mark members as static + + private static void TimerHandler(object _) + { + try + { + s_shortestDueTimeMs = long.MaxValue; + + long currentTimeMs = TickCount64; + SetNextTimer(PumpTimerQueue(currentTimeMs), currentTimeMs); + } + catch (Exception e) + { + Environment.FailFast("TimerQueue.TimerHandler failed", e); + } + } + + // this is called with shortest of timers scheduled on the particular TimerQueue private bool SetTimer(uint actualDuration) { - throw new PlatformNotSupportedException(); + Debug.Assert((int)actualDuration >= 0); + long currentTimeMs = TickCount64; + if (!_isScheduled) + { + s_scheduledTimers ??= new List(Instances.Length); + s_scheduledTimersToFire ??= new List(Instances.Length); + s_scheduledTimers.Add(this); + _isScheduled = true; + } + + _scheduledDueTimeMs = currentTimeMs + (int)actualDuration; + + SetNextTimer(ShortestDueTime(), currentTimeMs); + + return true; + } + + // shortest time of all TimerQueues + private static unsafe void SetNextTimer(long shortestDueTimeMs, long currentTimeMs) + { + if (shortestDueTimeMs == long.MaxValue) + { + return; + } + + // this also covers s_shortestDueTimeMs = long.MaxValue when none is scheduled + if (s_shortestDueTimeMs > shortestDueTimeMs) + { + s_shortestDueTimeMs = shortestDueTimeMs; + ulong shortestWaitMs = (ulong)Math.Max((long)(shortestDueTimeMs - currentTimeMs), 0); + + // `SubscribeDuration` expects nanoseconds: + var pollable = MonotonicClockInterop.SubscribeDuration(shortestWaitMs * 1000 * 1000); + Task task = WasiEventLoop.RegisterWasiPollable(pollable); + task.ContinueWith(TimerHandler, TaskScheduler.Default); + } + } + + private static long ShortestDueTime() + { + if (s_scheduledTimers == null) + { + return long.MaxValue; + } + + long shortestDueTimeMs = long.MaxValue; + var timers = s_scheduledTimers!; + for (int i = timers.Count - 1; i >= 0; --i) + { + TimerQueue timer = timers[i]; + if (timer._scheduledDueTimeMs < shortestDueTimeMs) + { + shortestDueTimeMs = timer._scheduledDueTimeMs; + } + } + + return shortestDueTimeMs; + } + + private static long PumpTimerQueue(long currentTimeMs) + { + if (s_scheduledTimersToFire == null) + { + return ShortestDueTime(); + } + + List timersToFire = s_scheduledTimersToFire!; + List timers; + timers = s_scheduledTimers!; + long shortestDueTimeMs = long.MaxValue; + for (int i = timers.Count - 1; i >= 0; --i) + { + TimerQueue timer = timers[i]; + long waitDurationMs = timer._scheduledDueTimeMs - currentTimeMs; + if (waitDurationMs <= 0) + { + timer._isScheduled = false; + timersToFire.Add(timer); + + int lastIndex = timers.Count - 1; + if (i != lastIndex) + { + timers[i] = timers[lastIndex]; + } + timers.RemoveAt(lastIndex); + continue; + } + + if (timer._scheduledDueTimeMs < shortestDueTimeMs) + { + shortestDueTimeMs = timer._scheduledDueTimeMs; + } + } + + if (timersToFire.Count > 0) + { + foreach (TimerQueue timerToFire in timersToFire) + { + timerToFire.FireNextTimers(); + } + timersToFire.Clear(); + } + + return shortestDueTimeMs; } -#pragma warning restore CA1822 } } diff --git a/src/mono/sample/wasi/http-p2/Program.cs b/src/mono/sample/wasi/http-p2/Program.cs index f2687d511fc151..44e7bd5ce82efa 100644 --- a/src/mono/sample/wasi/http-p2/Program.cs +++ b/src/mono/sample/wasi/http-p2/Program.cs @@ -8,25 +8,10 @@ using System.Threading; using System.Runtime.CompilerServices; -public class Test +// keep in sync with src\mono\wasi\testassets\Http.cs +public static class WasiMainWrapper { - public static int Main(string[] args) - { - var task = Work(); - while (!task.IsCompleted) - { - WasiEventLoop.DispatchWasiEventLoop(); - } - var exception = task.Exception; - if (exception is not null) - { - throw exception; - } - - return 0; - } - - public static async Task Work() + public static async Task MainAsync() { using HttpClient client = new(); client.Timeout = Timeout.InfiniteTimeSpan; @@ -42,16 +27,25 @@ public static async Task Work() Console.WriteLine("GET "+query); Console.WriteLine(); Console.WriteLine(json); + + return 0; } - private static class WasiEventLoop + public static int Main(string[] args) { - internal static void DispatchWasiEventLoop() + var task = MainAsync(); + while (!task.IsCompleted) { CallDispatchWasiEventLoop((Thread)null!); - - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] - static extern void CallDispatchWasiEventLoop(Thread t); } + var exception = task.Exception; + if (exception is not null) + { + throw exception; + } + return task.Result; + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] + static extern void CallDispatchWasiEventLoop(Thread t); } } diff --git a/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs b/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs index ae3fab94bbdc88..62f23c2648899c 100644 --- a/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs @@ -693,10 +693,14 @@ public static int Main() .MultiplyWithSingleArgs(true, false) /*aot*/ .UnwrapItemsAsArrays(); - protected CommandResult RunWithoutBuild(string config, string id) + protected CommandResult RunWithoutBuild(string config, string id, bool enableHttp = false) { // wasmtime --wasi http is necessary because the default dotnet.wasm (without native rebuild depends on wasi:http world) - string runArgs = $"run --no-build -c {config} --forward-exit-code --extra-host-arg=--wasi --extra-host-arg=http"; + string runArgs = $"run --no-build -c {config} --forward-exit-code"; + if (enableHttp) + { + runArgs += " --extra-host-arg=--wasi --extra-host-arg=http"; + } runArgs += " x y z"; int expectedExitCode = 42; CommandResult res = new RunCommand(s_buildEnv, _testOutput, label: id) diff --git a/src/mono/wasi/Wasi.Build.Tests/HttpTests.cs b/src/mono/wasi/Wasi.Build.Tests/HttpTests.cs new file mode 100644 index 00000000000000..1b977ef9e39f25 --- /dev/null +++ b/src/mono/wasi/Wasi.Build.Tests/HttpTests.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; +using Wasm.Build.Tests; + +#nullable enable + +namespace Wasi.Build.Tests; + +public class HttpTests : BuildTestBase +{ + public HttpTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + [Theory] + [MemberData(nameof(TestDataForConsolePublishAndRun))] + public void HttpBuildThenRunThenPublish(string config, bool singleFileBundle, bool aot) + { + string id = $"{config}_{GetRandomId()}"; + string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); + string projectName = Path.GetFileNameWithoutExtension(projectFile); + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Http.cs"), Path.Combine(_projectDir!, "Program.cs"), true); + + var buildArgs = new BuildArgs(projectName, config, aot, id, null); + buildArgs = ExpandBuildArgs(buildArgs); + + string extraProperties = "true"; + if (aot) + extraProperties += "true<_WasmDevel>false"; + if (singleFileBundle) + extraProperties += "true"; + if (!string.IsNullOrEmpty(extraProperties)) + AddItemsPropertiesToProject(projectFile, extraProperties); + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + DotnetWasmFromRuntimePack: true, + CreateProject: false, + Publish: false, + TargetFramework: BuildTestBase.DefaultTargetFramework)); + RunWithoutBuild(config, id, true); + + if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product)) + throw new XunitException($"Test bug: could not get the build product in the cache"); + + File.Move(product!.LogFile, Path.ChangeExtension(product.LogFile!, ".first.binlog")); + + _testOutput.WriteLine($"{Environment.NewLine}Publishing with no changes ..{Environment.NewLine}"); + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + DotnetWasmFromRuntimePack: true, + CreateProject: false, + Publish: true, + TargetFramework: BuildTestBase.DefaultTargetFramework, + UseCache: false, + ExpectSuccess: !(config == "Debug" && aot))); + } + +} diff --git a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs index 5a909d54b13744..9d7a769594aa4d 100644 --- a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs @@ -80,7 +80,7 @@ public void ConsoleBuildThenRunThenPublish(string config, bool singleFileBundle, CreateProject: false, Publish: false, TargetFramework: BuildTestBase.DefaultTargetFramework)); - RunWithoutBuild(config, id); + RunWithoutBuild(config, id, true); if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product)) throw new XunitException($"Test bug: could not get the build product in the cache"); diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs new file mode 100644 index 00000000000000..a155abdde07bdd --- /dev/null +++ b/src/mono/wasi/testassets/Http.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Net.Http.Headers; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; +using System.Runtime.CompilerServices; + +// keep in sync with src\mono\sample\wasi\http-p2\Program.cs +public static class WasiMainWrapper +{ + public static async Task MainAsync() + { + using HttpClient client = new(); + client.Timeout = Timeout.InfiniteTimeSpan; + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); + client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); + + var query="https://api.github.com/orgs/dotnet/repos?per_page=1"; + var json = await client.GetStringAsync(query); + + Console.WriteLine(); + Console.WriteLine("GET "+query); + Console.WriteLine(); + Console.WriteLine(json); + + return 42; + } + + public static int Main(string[] args) + { + var task = MainAsync(); + while (!task.IsCompleted) + { + CallDispatchWasiEventLoop((Thread)null!); + } + var exception = task.Exception; + if (exception is not null) + { + throw exception; + } + return task.Result; + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] + static extern void CallDispatchWasiEventLoop(Thread t); + } +} From 42173132077277317efcfd198eff373ff350e3b8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 5 Aug 2024 18:23:20 +0200 Subject: [PATCH 02/13] fix --- .../src/System/Threading/TimerQueue.Wasi.Mono.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs index 119ba0a17738ad..20c017cce1fe17 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/TimerQueue.Wasi.Mono.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; -using WasiPollWorld.wit.imports.wasi.clocks.v0_2_0; +using WasiPollWorld.wit.imports.wasi.clocks.v0_2_1; namespace System.Threading { From 1872580c33882603427f9e1e868b001eac2e45f5 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 10:03:29 +0200 Subject: [PATCH 03/13] feedback --- src/mono/mono.proj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 88ae8c08861970..9db5cccf9ee0b6 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -347,8 +347,9 @@ JS_ENGINES = [NODE_JS] Condition="'$(ActualWasiSdkVersion)' != '$(ExpectedWasiSdkVersion)'" /> From d3586a5a88eb7490e3a866f2091dff672f362975 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 10:41:41 +0200 Subject: [PATCH 04/13] fix WBT --- src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs | 2 +- src/mono/wasi/testassets/Http.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs index 9d7a769594aa4d..e1887ab525f086 100644 --- a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs @@ -50,7 +50,7 @@ public void ConsoleBuildAndRunAOT(string config, bool singleFileBundle) CreateProject: false, Publish: false, TargetFramework: BuildTestBase.DefaultTargetFramework)); - RunWithoutBuild(config, id); + RunWithoutBuild(config, id, true); } [Theory] diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index a155abdde07bdd..36fc6f6c3ca0eb 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -18,11 +18,12 @@ public static async Task MainAsync() client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); - client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); + client.DefaultRequestHeaders.Add("User-Agent", ".NET WASI unit test"); var query="https://api.github.com/orgs/dotnet/repos?per_page=1"; var json = await client.GetStringAsync(query); + Console.WriteLine("Hello, Wasi Console!"); Console.WriteLine(); Console.WriteLine("GET "+query); Console.WriteLine(); From b9f424336ac3c71817cfa9e7e5d6e3daff8eb9fb Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 12:09:59 +0200 Subject: [PATCH 05/13] UnsafeAccessor + feedback --- .../tests/WasmTestRunner/WasmTestRunner.cs | 8 ++--- .../Http/WasiHttpHandler/WasiHttpHandler.cs | 29 +++++++++---------- .../System.Private.CoreLib.csproj | 1 - .../src/ILLink/ILLink.Descriptors.WASI.xml | 10 ------- src/mono/mono.proj | 7 +++-- src/mono/sample/wasi/http-p2/Program.cs | 5 ++-- src/mono/wasi/testassets/Http.cs | 10 +++++-- 7 files changed, 32 insertions(+), 38 deletions(-) delete mode 100644 src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 10ff7c5a90dfee..19a9ab3704d58a 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -31,14 +31,14 @@ public static int Main(string[] args) return task.Result; } - internal static void DispatchWasiEventLoop() + private static void DispatchWasiEventLoop() { CallDispatchWasiEventLoop((Thread)null!); - - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] - static extern void CallDispatchWasiEventLoop(Thread t); } + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] + private static extern void CallDispatchWasiEventLoop(Thread t); + #else public static Task Main(string[] args) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs index f9333bf1c4f2c9..dcccb989910960 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/WasiHttpHandler/WasiHttpHandler.cs @@ -314,7 +314,7 @@ ITypes.OutgoingRequest request } else { - await WasiEventLoop.RegisterWasiPollable(future.Subscribe()).ConfigureAwait(false); + await RegisterWasiPollable(future.Subscribe()).ConfigureAwait(false); } } } @@ -461,24 +461,22 @@ private static async Task SendContentAsync(HttpContent? content, Stream stream) } } - private static class WasiEventLoop + private static Task RegisterWasiPollable(IPoll.Pollable pollable) { - internal static Task RegisterWasiPollable(IPoll.Pollable pollable) - { - var handle = pollable.Handle; + var handle = pollable.Handle; - // this will effectively neutralize Dispose() of the Pollable() - // because in the CoreLib we create another instance, which will dispose it - pollable.Handle = 0; - GC.SuppressFinalize(pollable); + // this will effectively neutralize Dispose() of the Pollable() + // because in the CoreLib we create another instance, which will dispose it + pollable.Handle = 0; + GC.SuppressFinalize(pollable); - return CallRegisterWasiPollableHandle((Thread)null!, handle); + return CallRegisterWasiPollableHandle((Thread)null!, handle); - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollableHandle")] - static extern Task CallRegisterWasiPollableHandle(Thread t, int handle); - } } + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollableHandle")] + private static extern Task CallRegisterWasiPollableHandle(Thread t, int handle); + private sealed class InputStream : Stream { private ITypes.IncomingBody body; @@ -564,8 +562,7 @@ CancellationToken cancellationToken var buffer = result; if (buffer.Length == 0) { - await WasiEventLoop - .RegisterWasiPollable(stream.Subscribe()) + await RegisterWasiPollable(stream.Subscribe()) .ConfigureAwait(false); } else @@ -702,7 +699,7 @@ CancellationToken cancellationToken var count = (int)stream.CheckWrite(); if (count == 0) { - await WasiEventLoop.RegisterWasiPollable(stream.Subscribe()).ConfigureAwait(false); + await RegisterWasiPollable(stream.Subscribe()).ConfigureAwait(false); } else if (offset == limit) { diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index c57983d44dbcb4..16a66d28788be6 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -134,7 +134,6 @@ - diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml deleted file mode 100644 index f5e626c35dc6d7..00000000000000 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 9db5cccf9ee0b6..b45f8150d251a2 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -346,12 +346,15 @@ JS_ENGINES = [NODE_JS] - - + MainAsync() { + Console.WriteLine("Hello, Wasi Console!"); + for (int i = 0; i < args.Length; i ++) + Console.WriteLine($"args[{i}] = {args[i]}"); + using HttpClient client = new(); client.Timeout = Timeout.InfiniteTimeSpan; client.DefaultRequestHeaders.Accept.Clear(); @@ -23,7 +27,6 @@ public static async Task MainAsync() var query="https://api.github.com/orgs/dotnet/repos?per_page=1"; var json = await client.GetStringAsync(query); - Console.WriteLine("Hello, Wasi Console!"); Console.WriteLine(); Console.WriteLine("GET "+query); Console.WriteLine(); @@ -46,7 +49,8 @@ public static int Main(string[] args) } return task.Result; - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] - static extern void CallDispatchWasiEventLoop(Thread t); } + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] + private static extern void CallDispatchWasiEventLoop(Thread t); } From 3129ac49fee6c14625909bf8f4352af0dbd49890 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 13:37:24 +0200 Subject: [PATCH 06/13] fix --- src/mono/sample/wasi/http-p2/Program.cs | 4 ++-- src/mono/wasi/testassets/Http.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/sample/wasi/http-p2/Program.cs b/src/mono/sample/wasi/http-p2/Program.cs index 78d36a00a718e1..55684b44c2f6e5 100644 --- a/src/mono/sample/wasi/http-p2/Program.cs +++ b/src/mono/sample/wasi/http-p2/Program.cs @@ -11,7 +11,7 @@ // keep in sync with src\mono\wasi\testassets\Http.cs public static class WasiMainWrapper { - public static async Task MainAsync() + public static async Task MainAsync(string[] args) { using HttpClient client = new(); client.Timeout = Timeout.InfiniteTimeSpan; @@ -33,7 +33,7 @@ public static async Task MainAsync() public static int Main(string[] args) { - var task = MainAsync(); + var task = MainAsync(args); while (!task.IsCompleted) { CallDispatchWasiEventLoop((Thread)null!); diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index dabd648c968869..da28bba60e18cc 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -11,7 +11,7 @@ // keep in sync with src\mono\sample\wasi\http-p2\Program.cs public static class WasiMainWrapper { - public static async Task MainAsync() + public static async Task MainAsync(string[] args) { Console.WriteLine("Hello, Wasi Console!"); for (int i = 0; i < args.Length; i ++) @@ -37,7 +37,7 @@ public static async Task MainAsync() public static int Main(string[] args) { - var task = MainAsync(); + var task = MainAsync(args); while (!task.IsCompleted) { CallDispatchWasiEventLoop((Thread)null!); From 31006e499248f9e34ba6adbab0cb736bed12dcad Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 15:12:09 +0200 Subject: [PATCH 07/13] didn't work after all --- .../System.Private.CoreLib.csproj | 1 + .../src/ILLink/ILLink.Descriptors.WASI.xml | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 16a66d28788be6..c57983d44dbcb4 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -134,6 +134,7 @@ + diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml new file mode 100644 index 00000000000000..f5e626c35dc6d7 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.WASI.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file From 3ca5606d90a5a14f6633ddf265b8d599eeec576e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 6 Aug 2024 17:25:28 +0200 Subject: [PATCH 08/13] - itemize ILLinkDescriptorsLibraryBuildXml - use ILLinkDescriptorsLibraryBuildXml instaed of ILLinkDescriptorsXmls --- eng/illink.targets | 7 ++++--- .../src/System.Private.CoreLib.Shared.projitems | 4 +--- .../System.Private.CoreLib/System.Private.CoreLib.csproj | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eng/illink.targets b/eng/illink.targets index 0f0c3cab3c45d7..5304ecd8d1eb34 100644 --- a/eng/illink.targets +++ b/eng/illink.targets @@ -20,8 +20,6 @@ $(IntermediateOutputPath) $(ILLinkDirectory)ILLink.Descriptors.xml - - $(ILLinkDirectory)ILLink.Descriptors.LibraryBuild.xml $(IntermediateOutputPath)ILLink.Descriptors.xml $(IntermediateOutputPath)ILLink.Substitutions.xml @@ -41,6 +39,9 @@ + + @@ -210,7 +211,7 @@ $(ILLinkArgs) -b true $(ILLinkArgs) --preserve-symbol-paths - $(ILLinkArgs) -x "$(ILLinkDescriptorsLibraryBuildXml)" + $(ILLinkArgs) -x "@(ILLinkDescriptorsLibraryBuildXml->'%(FullPath)', '" -x "')" $(ILLinkArgs) --substitutions "$(ILLinkSubstitutionsLibraryBuildXml)" $(ILLinkArgs) --link-attributes "@(ILLinkSuppressionsLibraryBuildXml->'%(FullPath)', '" --link-attributes "')" - + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs index 22be1b9b0e8768..359c889c975b87 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs @@ -5,6 +5,7 @@ using System.Runtime; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; +using System.Threading.Tasks; namespace System.Threading { @@ -17,10 +18,21 @@ internal static System.Threading.Tasks.Task RegisterWasiPollableHandle(int handl return WasiEventLoop.RegisterWasiPollableHandle(handle); } - internal static void DispatchWasiEventLoop() + internal static int PollWasiEventLoopUntilResolved(Task mainTask) { - WasiEventLoop.DispatchWasiEventLoop(); + while (!mainTask.IsCompleted) + { + WasiEventLoop.DispatchWasiEventLoop(); + } + var exception = mainTask.Exception; + if (exception is not null) + { + throw exception; + } + + return mainTask.Result; } + #endif // the closest analog to Sleep(0) on Unix is sched_yield diff --git a/src/mono/sample/wasi/http-p2/Program.cs b/src/mono/sample/wasi/http-p2/Program.cs index 55684b44c2f6e5..95fb1447cc5e2a 100644 --- a/src/mono/sample/wasi/http-p2/Program.cs +++ b/src/mono/sample/wasi/http-p2/Program.cs @@ -33,20 +33,10 @@ public static async Task MainAsync(string[] args) public static int Main(string[] args) { - var task = MainAsync(args); - while (!task.IsCompleted) - { - CallDispatchWasiEventLoop((Thread)null!); - } - var exception = task.Exception; - if (exception is not null) - { - throw exception; - } - return task.Result; + return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] + static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] - private static extern void CallDispatchWasiEventLoop(Thread t); } diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index da28bba60e18cc..cc335962d85dec 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -37,20 +37,9 @@ public static async Task MainAsync(string[] args) public static int Main(string[] args) { - var task = MainAsync(args); - while (!task.IsCompleted) - { - CallDispatchWasiEventLoop((Thread)null!); - } - var exception = task.Exception; - if (exception is not null) - { - throw exception; - } - return task.Result; + return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] + private static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } - - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "DispatchWasiEventLoop")] - private static extern void CallDispatchWasiEventLoop(Thread t); } From 00eab2f24174ddfe278e4816d40e68f06f6bd4a0 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 7 Aug 2024 11:21:30 +0200 Subject: [PATCH 11/13] Update src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek FiĊĦera --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index fc4367ce02cce0..032299180e78d9 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -65,7 +65,7 @@ - + From 186d55df32dc1b2247582ab0858c16176d0ed183 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 7 Aug 2024 11:26:07 +0200 Subject: [PATCH 12/13] feedback --- src/mono/sample/wasi/http-p2/Program.cs | 6 ++---- src/mono/wasi/testassets/Http.cs | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/mono/sample/wasi/http-p2/Program.cs b/src/mono/sample/wasi/http-p2/Program.cs index 95fb1447cc5e2a..98df1a50a0537c 100644 --- a/src/mono/sample/wasi/http-p2/Program.cs +++ b/src/mono/sample/wasi/http-p2/Program.cs @@ -16,11 +16,9 @@ public static async Task MainAsync(string[] args) using HttpClient client = new(); client.Timeout = Timeout.InfiniteTimeSpan; client.DefaultRequestHeaders.Accept.Clear(); - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); - client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); + client.DefaultRequestHeaders.Add("User-Agent", "dotnet WASI unit test"); - var query="https://api.github.com/orgs/dotnet/repos?per_page=1"; + var query="https://corefx-net-http11.azurewebsites.net/Echo.ashx"; var json = await client.GetStringAsync(query); Console.WriteLine(); diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index cc335962d85dec..8a5effa56e86a8 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -20,11 +20,9 @@ public static async Task MainAsync(string[] args) using HttpClient client = new(); client.Timeout = Timeout.InfiniteTimeSpan; client.DefaultRequestHeaders.Accept.Clear(); - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); - client.DefaultRequestHeaders.Add("User-Agent", ".NET WASI unit test"); + client.DefaultRequestHeaders.Add("User-Agent", "dotnet WASI unit test"); - var query="https://api.github.com/orgs/dotnet/repos?per_page=1"; + var query="https://corefx-net-http11.azurewebsites.net/Echo.ashx"; var json = await client.GetStringAsync(query); Console.WriteLine(); From 7b2d74e8c0f8ad10413c2fe3a7b31099c9b1f4ba Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 7 Aug 2024 13:50:55 +0200 Subject: [PATCH 13/13] fix --- src/mono/wasi/testassets/Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasi/testassets/Http.cs b/src/mono/wasi/testassets/Http.cs index 8a5effa56e86a8..d8043bf017ca7e 100644 --- a/src/mono/wasi/testassets/Http.cs +++ b/src/mono/wasi/testassets/Http.cs @@ -38,6 +38,6 @@ public static int Main(string[] args) return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] - private static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); + static extern int PollWasiEventLoopUntilResolved(Thread t, Task mainTask); } }