Refactor the Unix hosting API #1234

Closed
janvorli opened this Issue Jul 13, 2015 · 22 comments

Projects

None yet

7 participants

@janvorli
Member

The current hosting API that exposes a single ExecuteAssembly function was created for the need of the corerun / coreconsole. It turns out that there are more complex hosting scenarios that require additional functionality.
Based on the github discussions, we will create a new hosting API that would contain the following functions:

HRESULT InitializeCoreCLR(
            LPCSTR exePath,
            LPCSTR appDomainFriendlyName,
            int propertyCount,
            LPCSTR* propertyKeys,
            LPCSTR* propertyValues,
            void** hostHandle,
            DWORD* domainId);

HRESULT ShutdownCoreCLR(
            void* hostHandle,
            DWORD domainId);

HRESULT CreateDelegate(
            void* hostHandle,
            DWORD domainId,
            LPCSTR entryPointAssemblyName,
            LPCSTR entryPointTypeName,
            LPCSTR entryPointMethodName,
            void** delegate);

HRESULT ExecuteAssembly(
            void* hostHandle,
            DWORD domainId,
            int argc,
            LPCSTR* argv,
            LPCSTR managedAssemblyPath,
            DWORD* exitCode);

The hosting application would first call InitializeCoreCLR. If it succeeds, it will fill in two output parameters, the hostHandle and domainId.
Then it can either call the ExecuteAssembly or the CreateDelegate. The CreateDelegate can be called multiple times and the returned delegate can be called as many times as needed.
Finally, at the hosting application shutdown, the ShutdownCoreCLR will be called.

@janvorli janvorli self-assigned this Jul 13, 2015
@Marqin
Contributor
Marqin commented Jul 13, 2015

👍

And ExecuteAssembly can only be run once?

@janvorli
Member

In fact, it can be run multiple times too, I was just not sure yet if it can have some unexpected consequences and such scenario was not between the ones discussed, so I didn't want to explicitly subscribe to supporting it.
@jkotas, do you see any problem executing an assembly multiple times or executing multiple assemblies one after another in the same host / domain?

@jkotas
Member
jkotas commented Jul 14, 2015

There are no problems in the runtime itself.

To make it work well, programs have to be friendly for this mode of execution. They have to avoid polluting process global settings. (There are no universal rules on what qualifies as bad change to process global settings. It varies from app model to app model.)

@janvorli
Member

Based on the PR feedback in the change #1245, I've modified the function names and signatures to be more in line with the Unix conventions and use only standard C types:

int coreclr_initialize(
            const char* exePath,
            const char* appDomainFriendlyName,
            int propertyCount,
            const char** propertyKeys,
            const char** propertyValues,
            void** hostHandle,
            unsigned int* domainId);

int coreclr_shutdown(
            void* hostHandle,
            unsigned int domainId);

int coreclr_create_delegate(
            void* hostHandle,
            unsigned int domainId,
            const char* entryPointAssemblyName,
            const char* entryPointTypeName,
            const char* entryPointMethodName,
            void** delegate);

int coreclr_execute_assembly(
            void* hostHandle,
            unsigned int domainId,
            int argc,
            const char** argv,
            const char* managedAssemblyPath,
            unsigned int* exitCode);
@janvorli
Member
@ghuntley
Member

/cc @kangaroo @janhenke @jasonwilliams200OK @josteink

@Marqin
Contributor
Marqin commented Jul 16, 2015

What would happen if I forgot to run coreclr_shutdown? It will be closed on hoster app close, or it could get reparented to init process and sit in system until shutdown?

Is it something crucial? Or it just frees memory?

@kangaroo
Contributor

I wonder if we shouldn't also extend to have functions for creating objects of an arbitrary type?

That is, right now how would I create a delegate (and call it) that was:

void SomeMethod (HttpWebRequest req);
@janvorli
Member

@Marqin - I don't have a deep knowledge of all the intimate details of what's going on during the shutdown. From a brief look at the sources know it frees some resources, stops the finalizer thread and does more.
@jkotas, are there some more details worth adding?
Regarding your other question:

or it could get reparented to init process and sit in system until shutdown?

Could you please explain what you mean by get reparented to init process?

@janvorli
Member

@kangaroo Even if we provided a way to create an object, how would you access its fields / methods from the native code?

@benpye
Contributor
benpye commented Jul 16, 2015

Could we expose this API on Windows too so a cross platform application could host the CLR with the same API across the board?

@janvorli
Member

That's an interesting idea. I don't see a technical reason why it would not work.
@jkotas, what do you think?

@jkotas
Member
jkotas commented Jul 16, 2015

@Marqin coreclr_shutdown will stop threads running managed code, prevent new threads from entering managed code, and attempt to run finalizers for all finalizable objects on the managed heap.

Forgetting to call coreclr_shutdown should not directly affect what will happen with the hoster app on close.

It may affect it indirectly - e.g. the hoster app can be coded to close gracefully only if all finalizers have run.

@jkotas
Member
jkotas commented Jul 16, 2015

@janvorli @benpye I agree that exposing same APIs on Windows is a good idea.

@janvorli
Member

What about the naming of the functions? Should we expose them named by windows conventions on Windows? Or should we keep the unix style names? Or should we expose both?

@masonwheeler

Might as well do both, to keep everyone happy. A stub function that simply forwards calls is cheap, afterall.

@jkotas
Member
jkotas commented Jul 16, 2015

I would do the unix style names only. The existing Windows-specific COM interfaces are still going to be there for Windows.

@masonwheeler

@jkotas Fair enough...

@Marqin
Contributor
Marqin commented Jul 16, 2015

Could you please explain what you mean by get reparented to init process?

@janvorli in Unix-like system when you kill parent process, then child process get's "orphaned" and is attached as child of init process ( sysv, systemd etc. [ pid 1 ] ) and it can run there ( that's how daemons work ). It's easy to try yourself, open your shell:

nano
echo "My PID is $$"

and then in another shell:

kill -SIGKILL PID_of_first_shell
ps -o ppid -p `pgrep nano` # or just use "pstree" if you have it

and you will see your nano is now child of init. Here is some example in C.

@kangaroo
Contributor
@kangaroo Even if we provided a way to create an object, how would you access its fields / methods from the native code?

With additional APIs for field enumeration and get/set? :)

There are a lot of people that used the mono APIs in scripting use cases that provided this type of functionality. It does present a GC problem though.

@benpye
Contributor
benpye commented Jul 16, 2015

Whilst that would certainly be nice, is the functionality provided by reverse P/Invoke not sufficient? You can certainly write methods in managed code that can marshal data back to native code when you call them, this has the nice advantage that, once you have the runtime hosted, you're interop is more or less compatible with Mono and .NET.

@janvorli
Member

Implemented by #1245

@janvorli janvorli closed this Jul 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment