agracio / edge-js

Run .NET and Node.js code in-process on Windows, macOS, and Linux
MIT License
623 stars 93 forks source link

Is it possible to run a .NET function from the main Node.js thread? #214

Closed garciadelcastillo closed 5 days ago

garciadelcastillo commented 1 month ago

Howdy!

And congrats for the project and thank you for maintaining it!

I am trying to call a .NET function from a dll that requires it to be ran on the main thread (reason is that it uses OpenGL and context rendering under the hood). Code looks roughly like this:

process.env.EDGE_USE_CORECLR = 1
const edge = require('edge-js');

const dll_path = './OpenGL-based-routines.dll'

const RenderTriangle = edge.func({
  assemblyFile: dll_path,
  typeName: 'Library.Core',
  methodName: 'RenderTriangle',
  sync: true
});

const triangleParams = {...};

const pixels = RenderTriangle(triangleParams, true);
console.log(pixels);

And the C# method looks like this:

public async Task<object> RenderTriangle(dynamic input)
{
    var pixels = Renderer.Triangle(inputs);  // this function uses OpenGL/GLFW
    return new { pixels };
}

And I get the error:

GLFW can only be called from the main thread!

Is there any way to use Edge-js in a way that the function gets called from the main thread, perhaps avoiding the Task API?

Thank you!

agracio commented 1 month ago

Hi, edge-js can only run Task methods in C#, quick search returns this suggestion from StackOverflow:

Task t = new Task(() =>
{
    ...
});
t.Start(TaskScheduler.FromCurrentSynchronizationContext());

EDIT:

From StackOverflow

Since version 3.3 at latest, GLFW does specify what is meant by "main thread": the thread that calls main(). GLFW apparently intending this to uniquely characterize a single thread despite the possibility of main() being re-entered, it seems to mean the thread in which the initial call to main() happens. And that's a pretty common usage of the term, even if not derived from the language spec.

If you can maintain reference to that thread you could use it inside public async Task<object> MyMethod(dynamic input)

garciadelcastillo commented 1 month ago

Thanks for the suggestion @agracio!

Spent the day yesterday trying versions of your suggestion, but couldn't quite figure out how to retrieve the main thread. The issue is that, in order to do it, some part of the C# code needs to be ran synchronously from the same thread that is running everything else, i.e. the Nodejs main thread, in order to be able to capture a reference to the SynchronizationContext, and then use such reference inside the surrogate task the way you suggested above. But since edge-js only fires Tasks, I can't figure out a way to do so from within a Task, which is by definition running on a different thread...

There is a section in the README where you describe how to run a Python script on the singleton V8 thread. It does sound like that's what I am trying to do, but for a .NET external dll. Do you think that could be possible?

Thanks!

agracio commented 1 month ago

There is a better explanation here: Sync Execution, as you can see it still uses Task<object>.

Let me try to create a quick example of I think the issue could be resolved using the 'EDIT' part of my comment.

Edit (again): maybe you have some quick example code for using GLFW since it is likely that my implementation of thread might not be applicable to GFLW case

garciadelcastillo commented 1 month ago

Absolutely, let me write a quick one and share here.

agracio commented 1 month ago

I am adding my implementation to quick start now

garciadelcastillo commented 1 month ago

Here you go: https://github.com/garciadelcastillo/edgejs-opengl

If you run the main script in the root, it should give you the non-main-thread error...

agracio commented 1 month ago

Thanks I will take a look at a look at it in a few hours

agracio commented 1 month ago

Removed all my previous comments it appears there is something else involved that needs to be investigated.

agracio commented 1 month ago

Unfortunately it looks like there is just no way to support GLFW using edge-js.

garciadelcastillo commented 1 month ago

Oh no! Well, thanks for trying anyway @agracio :)