SteveSandersonMS / DotNetIsolator

A library for running isolated .NET runtimes inside .NET
MIT License
599 stars 39 forks source link

cant resolve internal call to "System.Threading.ThreadPool::QueueCallback" #1

Open dkattan opened 1 year ago

dkattan commented 1 year ago

Full disclosure I 100% know that what I'm trying to do is bananas, especially given the infancy of this project and do not expect any assistance.

However, I figured I'd post it anyway in the offchance that this is known issue related to wasm's threading capabilities or perhaps something really stupid that I'm overlooking,

Code

using DotNetIsolator;
using System.Management.Automation;
using System.Runtime.InteropServices;

// Set up an isolated runtime
using var host = new IsolatedRuntimeHost().WithBinDirectoryAssemblyLoader();
using var runtime = new IsolatedRuntime(host);

// Output: I'm running on X64
var action = () =>
{
    // Output: I'm running on Wasm
    Console.WriteLine($"I'm running on {RuntimeInformation.OSArchitecture}");
    var result = PowerShell.Create().AddScript("'Hello, World'").Invoke();
    foreach (var item in result)
    {
        Console.WriteLine(item.ToString());
    }
    Thread.Sleep(5000);
};
action();
runtime.Invoke(action);

Console Output

I'm running on X64
Hello, World
I'm running on Wasm
[wasm_trace_logger] cant resolve internal call to "System.Threading.ThreadPool::QueueCallback" (tested without signature also)

Your mono runtime and class libraries are out of sync.
The out of sync library is: System.Private.CoreLib.dll

When you update one from git you need to update, compile and install
the other too.
Do not report this as a bug unless you're sure you have updated correctly:
you probably have a broken mono install.
If you see other errors or faults after this message they are probably related
and you need to fix your mono install first.

Exception details

DotNetIsolator.IsolatedException
  HResult=0x80131500
  Message=System.TypeInitializationException: TypeInitialization_Type, Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry
 ---> System.TypeInitializationException: TypeInitialization_Type, Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration
 ---> System.TypeInitializationException: TypeInitialization_Type, Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics.SelfDiagnosticsInitializer
 ---> System.Threading.Tasks.TaskSchedulerException: TaskSchedulerException_ctor_DefaultMessage
 ---> System.MissingMethodException:  assembly:<unknown assembly> type:<unknown type> member:(null)
   at System.Threading.ThreadPool.RequestWorkerThread()
   at System.Threading.ThreadPoolWorkQueue.Enqueue(Object callback, Boolean forceGlobal)
   at System.Threading.ThreadPool.UnsafeQueueUserWorkItemInternal(Object callBack, Boolean preferLocal)
   at System.Threading.Tasks.ThreadPoolTaskScheduler.QueueTask(Task task)
   at System.Threading.Tasks.TaskScheduler.InternalQueueTask(Task task)
   at System.Threading.Tasks.Task.ScheduleAndStart(Boolean needsProtection)
   Exception_EndOfInnerExceptionStack
   at System.Threading.Tasks.Task.ScheduleAndStart(Boolean needsProtection)
   at System.Threading.Tasks.Task`1[[System.Threading.Tasks.Task, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].StartNew(Task parent, Func`1 function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler)
   at System.Threading.Tasks.TaskFactory`1[[System.Threading.Tasks.Task, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].StartNew(Func`1 function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
   at System.Threading.Tasks.Task.Run(Func`1 function, CancellationToken cancellationToken)
   at Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics.SelfDiagnosticsConfigRefresher..ctor()
   at Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics.SelfDiagnosticsInitializer..ctor()
   at Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics.SelfDiagnosticsInitializer..cctor()
   Exception_EndOfInnerExceptionStack
   at Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration..cctor()
   Exception_EndOfInnerExceptionStack
   at Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry..cctor()
   Exception_EndOfInnerExceptionStack
   at System.Management.Automation.PowerShell..ctor(PSCommand command, Collection`1 extraCommands, Object rsConnection)
   at System.Management.Automation.PowerShell.Create()
   at Program.<>c.<<Main>$>b__0_0()
  Source=DotNetIsolator
  StackTrace:
   at DotNetIsolator.IsolatedRuntime.InvokeDotNetMethod[TRes](Int32 monoMethodPtr, IsolatedObject instance, ReadOnlySpan`1 argAddresses)
   at DotNetIsolator.IsolatedMethod.Invoke[TRes](IsolatedObject instance)
   at DotNetIsolator.IsolatedMethod.InvokeVoid(IsolatedObject instance)
   at DotNetIsolator.IsolatedRuntime.Invoke(Action value)
   at Program.<Main>$(String[] args) in C:\Users\DKattan\source\repos\TestPowerShell73Dependency2\TestPowerShell73Dependency2\Program.cs:line 23

.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <PropertyGroup>

      <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DotNetIsolator" Version="0.1.0-preview.10024" />
    <PackageReference Include="Microsoft.PowerShell.Commands.Diagnostics" Version="7.3.3" />
    <PackageReference Include="Microsoft.PowerShell.Commands.Management" Version="7.3.3" />
    <PackageReference Include="Microsoft.PowerShell.Commands.Utility" Version="7.3.3" />
    <PackageReference Include="Microsoft.PowerShell.ConsoleHost" Version="7.3.3" />
    <PackageReference Include="Microsoft.WSMan.Management" Version="7.3.3" />
    <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="8.0.0-preview.2.23128.3" />
    <PackageReference Include="System.Management.Automation" Version="7.3.3">
      <PrivateAssets>contentfiles;analyzers</PrivateAssets>
      <GeneratePathProperty>True</GeneratePathProperty>
    </PackageReference>
  </ItemGroup>
  <ItemGroup>
    <ModuleFiles Include="$(TargetDir)runtimes\win\**\*.dll" />
  </ItemGroup>
  <Target Name="PublishModule" AfterTargets="PostBuildEvent">
    <Copy SourceFiles="@(ModuleFiles)" DestinationFolder="$(TargetDir)" />
  </Target>
</Project>

global.json

{
  "sdk": {
    "version": "7.0.200"
  }
}

The PowerShell related nuget packages are also using .net 7.0.2

I tried upgrading to .net8 with the PowerShell 7.4 preview but there is a known issue with the depenencies right now preventing the usage of Microsoft.PowerShell.Commands.Utility from being imported (it is referencing an unreleased nuget package).

SteveSandersonMS commented 1 year ago

Thanks for letting me know. I think there are two issues here:

  1. QueueUserCallback not being implemented. I started on supporting it in this branch but there are some robustness issues. I'd rather not merge a partially-working solution as that would be even more confusing. So I'll get back to that whenever I can, but don't know when that will be.
  1. Even with this implemented, the PowerShell libraries might not just work on WebAssembly. There's a long thread about this at https://github.com/PowerShell/PowerShell/issues/13755.

I'll leave this issue open to track the QueueUserCallback requirement.

fMichaleczek commented 1 year ago

@SteveSandersonMS I worked on PowerShell and WASM. PowerShell need PR to handle WASM, and need two threads at minimum for handling the execution of async methods in the interpreter. I'm waiting for dotnet team to finish the WASM Multithread model. It was added with some raw api at the end of the net7.0 timeline. Their agenda is to use/debug these api to bring multithread to Blazor Wasm.

I was thinking WASI multithread for was never done (because no model) https://bytecodealliance.org/articles/wasi-threads

CalebSerafin commented 1 year ago

For one of my projects, I created a temporary workaround due to the lack of threading. By using a custom TaskSchedular, the host thread can repeatability invoke it to process the Task message queue. A custom Delay was implemented in the same fashion, relying on the host to periodically invoke a refresh function that checks the delay list. You can see the host implementation here https://github.com/CalebSerafin/IsolatedCodeHosting/blob/10f0190f44d5dae82b9c59b6d5e2051eeb1775ca/HostForWasmConsole/AsyncIsolateWorker.cs. And wasm app implementation here https://github.com/CalebSerafin/IsolatedCodeHosting/blob/10f0190f44d5dae82b9c59b6d5e2051eeb1775ca/WasmConsoleApp/AsyncHelpers.cs Note, it is anything but tested or optimised, but hopefully should be a good starting point.

dkattan commented 1 year ago

For one of my projects, I created a temporary workaround due to the lack of threading. By using a custom TaskSchedular, the host thread can repeatability invoke it to process the Task message queue. A custom Delay was implemented in the same fashion, relying on the host to periodically invoke a refresh function that checks the delay list. You can see the host implementation here https://github.com/CalebSerafin/IsolatedCodeHosting/blob/10f0190f44d5dae82b9c59b6d5e2051eeb1775ca/HostForWasmConsole/AsyncIsolateWorker.cs. And wasm app implementation here https://github.com/CalebSerafin/IsolatedCodeHosting/blob/10f0190f44d5dae82b9c59b6d5e2051eeb1775ca/WasmConsoleApp/AsyncHelpers.cs Note, it is anything but tested or optimised, but hopefully should be a good starting point.

Great timing! I picked back up on this yesterday and hooked my test project to the branch you created here and started debugging this morning. The error I’m getting appears to be related to function mapping/lookup. I’ll hopefully get to dig more into it later today/tomorrow but I was hypothesizing that it could be that maybe we aren’t considering generic arguments Task in the key for the function lookup table.