Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f0eaff8
Native hosting - add host context-based entry points
elinor-fung Apr 15, 2019
9cc62b8
Update native host test exe to use host context entry points
elinor-fung Apr 15, 2019
d0f9054
Allow getting properties of active context without context handle
elinor-fung Apr 18, 2019
43b8ea9
Check for initializing / already initialized context when running with
elinor-fung Apr 18, 2019
5df4088
Use specific error code for getting runtime property that doesn't exist
elinor-fung Apr 22, 2019
478e2cd
Update COM-activation.md
elinor-fung Apr 22, 2019
30f5772
PR feedback
elinor-fung Apr 22, 2019
418b185
Make native host test exe get properties of active context
elinor-fung Apr 22, 2019
0912eeb
Add coreclr to hostpolicy context instead of tracking a separate global
elinor-fung Apr 24, 2019
b94665b
Add functions for getting context from handle
elinor-fung Apr 24, 2019
377a626
Rename context instance -> handle. Add helper for tracing hostfxr entry.
elinor-fung Apr 24, 2019
93b2ac9
Separate helper function to create/initialize first vs secondary context
elinor-fung Apr 24, 2019
859e960
Remove exposed concept of context from hostpolicy
elinor-fung Apr 25, 2019
3f9f772
Split getting init info for secondary scenario into separate function
elinor-fung Apr 26, 2019
550d090
Add initialization option to block waiting for a different initializa…
elinor-fung Apr 27, 2019
bc5d799
Fix missed cases of handling initialize failure/abort
elinor-fung Apr 29, 2019
0100d5b
PR feedback
elinor-fung Apr 29, 2019
72b24f7
Add struct for corehost_initialize (instead of full host interface)
elinor-fung Apr 29, 2019
14bd34f
Add basic test using context-based entry points and mock coreclr
elinor-fung Apr 30, 2019
f7d4fd4
Merge branch 'master' into hostContext
elinor-fung Apr 30, 2019
a9cacdf
Fix unix build
elinor-fung Apr 30, 2019
a431efa
PR feedback
elinor-fung Apr 30, 2019
bf32916
Fix test output messages
elinor-fung May 1, 2019
cbdf212
Rename g_context_cv -> g_context_initializing_cv
elinor-fung May 1, 2019
4758989
Block initialization for self-contained components
elinor-fung May 2, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Documentation/design-docs/COM-activation.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@ When `DllGetClassObject()` is called in a COM activation scenario, the following
* If a [`.runtimeconfig.json`](https://github.com/dotnet/cli/blob/master/Documentation/specs/runtime-configuration-file.md) file exists adjacent to the target managed assembly (`<assembly>.runtimeconfig.json`), that file is used to describe the target framework and CLR configuration. The documentation for the `.runtimeconfig.json` format defines under what circumstances this file may be optional.
1) The `DllGetClassObject()` function verifies the `CLSID` mapping has a mapping for the `CLSID`.
* If the `CLSID` is unknown in the mapping the traditional `CLASS_E_CLASSNOTAVAILABLE` is returned.
1) The shim attempts to load the latest version of the `hostfxr` library and retrieves the `hostfxr_get_com_activation_delegate()` export.
1) The shim attempts to load the latest version of the `hostfxr` library and retrieves the `hostfxr_initialize_for_runtime_config()` and `hostfxr_get_runtime_delegate()` exports.
1) The target assembly name is computed by stripping off the `.comhost.dll` prefix and replacing it with `.dll`. Using the name of the target assembly, the path to the `.runtimeconfig.json` file is then computed.
1) The `hostfxr_get_com_activation_delegate()` export is called.
1) The `hostfxr_initialize_for_runtime_config()` export is called.
1) Based on the `.runtimeconfig.json` the [framework](https://docs.microsoft.com/dotnet/core/packages#frameworks) to use can be determined and the appropriate `hostpolicy` library path is computed.
1) The `hostpolicy` library is loaded and various exports are retrieved.
* If a `hostpolicy` instance is already loaded, the one presently loaded is re-used.
* **Prior to 3.0 GA** No validation is done to determine if the loaded `hostpolicy` can satisfy the current assembly's `.runtimeconfig.json`.
* **At 3.0 GA** If a CLR is active within the process, the requested CLR version will be validated against that CLR. If version satisfiability fails, activation will fail.
1) The `corehost_load()` export is called to initialize `hostpolicy`.
- Prior to .NET Core 3.0, during application activation the `corehost_load()` export would always initialize `hostpolicy` regardless if initialization had already been performed. For .NET Core 3.0, calling the function again will not re-initialize `hostpolicy`, but simply return.
1) The `corehost_get_com_activation_delegate()` export from `hostpolicy` is called.
1) The `corehost_get_com_activation_delegate()` export determines if the associated `coreclr` library has been loaded and if so, uses the existing activated CLR instance. If a CLR instance is not available, `hostpolicy` will load `coreclr` and activate a new CLR instance.
1) The `hostfxr_get_runtime_delegate()` export is called
1) The `hostfxr_get_runtime_delegate()` export calls into `hostpolicy` and determines if the associated `coreclr` library has been loaded and if so, uses the existing activated CLR instance. If a CLR instance is not available, `hostpolicy` will load `coreclr` and activate a new CLR instance.
* **Prior to 3.0 GA** No validation is done to determine if the current running coreclr instance can satisfy the current assembly's `.runtimeconfig.json`.
* **At 3.0 GA** If a CLR is active within the process, the requested CLR version will be validated against that CLR. If version satisfiability fails, activation will fail.
1) A request to the CLR is made to create a managed delegate to a static "activation" method. The delegate is returned to the shim to attempt activation of the requested class.
Expand Down
158 changes: 127 additions & 31 deletions Documentation/design-docs/hosting-layer-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ int hostfxr_main(const int argc, const char_t *argv[])
Run an application.
* `argc` / `argv` - command-line arguments

This function does not return until the application completes execution.
This function does not return until the application completes execution. It will shutdown CoreCLR after the application executes.

If the application is successfully executed, this value will return the exit code of the application. Otherwise, it will return an error code indicating the failure.

### .NET Core 2.0+

Expand Down Expand Up @@ -51,7 +53,9 @@ Run an application.
* `dotnet_root` - path to the .NET Core installation root
* `app_path` - path to the application to run

This function does not return until the application completes execution.
This function does not return until the application completes execution. It will shutdown CoreCLR after the application executes.

If the application is successfully executed, this value will return the exit code of the application. Otherwise, it will return an error code indicating the failure.

``` C
enum hostfxr_resolve_sdk2_flags_t
Expand Down Expand Up @@ -138,6 +142,112 @@ The error writer is registered per-thread. On each thread, only one callback can
If `hostfxr` invokes functions in `hostpolicy` as part of its operation, the error writer will be propagated to `hostpolicy` for the duration of the call. This means that errors from both `hostfxr` and `hostpolicy` will be reported through the same error writer.


``` C
int hostfxr_initialize_for_app(
int argc,
const char_t *argv[],
const char_t *app_path,
const hostfxr_initialize_parameters *parameters,
hostfxr_handle * host_context_handle
);
```
Initialize the hosting components for running a managed application.
* `argc` / `argv` - command-line arguments
* `app_path` - path to the application to run
* `parameters` - optional additional parameters
* `host_context_handle` - if initialization is successful, this receives an opaque value which identifies the initialized host context.

See [Native hosting](native-hosting.md#initialize-host-context)

``` C
int hostfxr_initialize_for_runtime_config(
const char_t *runtime_config_path,
const hostfxr_initialize_parameters *parameters,
hostfxr_handle *host_context_handle
);
```
Initialize the hosting components for a runtime configuration (`.runtimeconfig.json`).
* `runtime_config_path` - path to the `.runtimeconfig.json` file to process
* `parameters` - optional additional parameters
* `host_context_handle` - if initialization is successful, this receives an opaque value which identifies the initialized host context.

See [Native hosting](native-hosting.md#initialize-host-context)

``` C
int hostfxr_get_runtime_property_value(
const hostfxr_handle host_context_handle,
const char_t *name,
const char_t **value);
```

Get the value of a runtime property specified by its name.
* `host_context_handle` - initialized host context. If set to `nullptr` the function will operate on the first host context in the process.
* `name` - name of the runtime property to get
* `value` - returns a pointer to a buffer with the property value

See [Native hosting](native-hosting.md#runtime-properties)

``` C
int hostfxr_set_runtime_property_value(
const hostfxr_handle host_context_handle,
const char_t *name,
const char_t *value);
```

Set the value of a property.
* `host_context_handle` - initialized host context
* `name` - name of the runtime property to set
* `value` - value of the property to set. If the property already has a value in the host context, this function will overwrite it. When set to `nullptr` and if the property already has a value then the property is removed.

See [Native hosting](native-hosting.md#runtime-properties)

``` C
int hostfxr_get_runtime_properties(
const hostfxr_handle host_context_handle,
size_t * count,
const char_t **keys,
const char_t **values);
```
Get all runtime properties for the specified host context.
* `host_context_handle` - initialized host context. If set to `nullptr` the function will operate on the first host context in the process.
* `count` - in/out parameter which must not be `nullptr`. On input it specifies the size of the the `keys` and `values` buffers. On output it contains the number of entries used from `keys` and `values` buffers - the number of properties returned.
* `keys` - buffer which acts as an array of pointers to buffers with keys for the runtime properties.
* `values` - buffer which acts as an array of pointer to buffers with values for the runtime properties.

If `count` is less than the minimum required buffer size or `keys` or `values` is `nullptr`, this function will return `HostApiBufferTooSmall` and `keys` and `values` will be unchanged.

See [Native hosting](native-hosting.md#runtime-properties)

``` C
int hostfxr_run_app(const hostfxr_handle host_context_handle);
```
Run the application specified by `hostfxr_initialize_for_app`.
* `host_context_handle` - handle to the initialized host context.

This function does not return until the application completes execution. It will shutdown CoreCLR after the application executes.

If the application is successfully executed, this value will return the exit code of the application. Otherwise, it will return an error code indicating the failure.

See [Native hosting](native-hosting.md#runtime-properties)

``` C
int hostfxr_get_runtime_delegate(const hostfxr_handle host_context_handle, hostfxr_delegate_type type, void ** delegate);
```
Start the runtime and get a function pointer to specified functionality of the runtime.
* `host_context_handle` - initialized host context
* `type` - type of runtime functionality requested
* `delegate` - on success, this is populated with the native function pointer to the requested runtime functionality

See [Native hosting](native-hosting.md#getting-a-delegate-for-runtime-functionality)

``` C
int hostfxr_close(const hostfxr_handle host_context_handle);
```
Close a host context.
* `host_context_handle` - initialized host context to close.

See [Native hosting](native-hosting.md#cleanup)

## Host Policy

All exported functions and function pointers in the `hostpolicy` library use the `__cdecl` calling convention on the x86 platform.
Expand All @@ -162,6 +272,8 @@ Run an application.

This function does not return until the application completes execution. It will shutdown CoreCLR after the application executes.

If the application is successfully executed, this value will return the exit code of the application. Otherwise, it will return an error code indicating the failure.

``` C
int corehost_unload()
```
Expand All @@ -188,14 +300,6 @@ If `buffer_size` is less than the minimum required buffer size, this function wi

### .NET Core 3.0+

``` C
int corehost_get_coreclr_delegate(coreclr_delegate_type type, void **delegate)
```

Get a delegate for CoreCLR functionality
* `type` - requested type of runtime functionality
* `delegate` - function pointer to the requested runtime functionality

``` C
typedef void(*corehost_resolve_component_dependencies_result_fn)(
const char_t *assembly_paths,
Expand Down Expand Up @@ -226,14 +330,6 @@ The return value is the previouly registered callback (which is now unregistered

The error writer is registered per-thread. On each thread, only one callback can be registered. Subsequent registrations overwrite the previous ones.

### [Proposed] .NET Core 3.0+

#### Removal

`corehost_get_coreclr_delegate` will be removed and the equivalent functionality provided through the proposed additions below. Since this function is new in 3.0, it should not be required for backwards compatibility.

#### Addition

``` C
typedef void* context_handle;

Expand All @@ -242,18 +338,16 @@ struct corehost_context_contract
size_t version;
context_handle instance;
int (*get_property_value)(
context_handle instance,
const char_t *key,
const char_t **value);
int (*set_property_value)(
context_handle instance,
const char_t *key,
const char_t *value);
int (*get_properties)(
context_handle instance,
size_t *count,
const char_t **keys,
const char_t **values);
int (*load_runtime)();
int (*run_app)(
const context_handle instance,
const int argc,
Expand All @@ -265,7 +359,7 @@ struct corehost_context_contract
};
```

Contract for performing operations on an initialized host context.
Contract for performing operations on an initialized hostpolicy.
* `version` - version of the struct.
* `instance` - opaque handle to the `corehost_context_contract` state.
* `get_property_value` - function pointer for getting a property on the host context.
Expand All @@ -278,23 +372,25 @@ Contract for performing operations on an initialized host context.
* `count` - size of `keys` and `values`. If the size is too small, it will be populated with the required size. Otherwise, it will be populated with the size used.
* `keys` - buffer to populate with the property keys.
* `values` - buffer to populate with the property values.
* `load_runtime` - function pointer for loading CoreCLR
* `run_app` - function pointer for running an application.
* `argc` / `argv` - command-line arguments.
* `get_runtime_delegate` - function pointer for getting a delegate for CoreCLR functionality
* `type` - requested type of runtime functionality
* `delegate` - function pointer to the requested runtime functionality

``` C
int corehost_initialize_context(const host_interface_t *init, corehost_context_contract *context_contract)
enum intialization_options_t
{
none = 0x0,
wait_for_initialized = 0x1,
};

int corehost_initialize(const corehost_initialize_request_t *init_request, int32_t options, corehost_context_contract *context_contract)
```

Initializes the host context. This calculates everything required to start CoreCLR (but does not actually do so).
* `init` - struct defining how the host context should be initialized. If the host context is already initialized, this function will check if `init` is compatible with the active context.
* `init_request` - struct containing information about the initialization request. If hostpolicy is not yet initialized, this is expected to be nullptr. If hostpolicy is already initialized, this should not be nullptr and this function will use the struct to check for compatibility with the way in which hostpolicy was previously initialized.
* `options` - initialization options
* `wait_for_initialized` - wait until initialization through a different request is completed
* `context_contract` - if initialization is successful, this is populated with the contract for operating on the initialized host context.

``` C
int corehost_close_context(corehost_context_contract *context_contract)
```

Closes the host context.
* `context_contract` - contract of the context to close.
18 changes: 10 additions & 8 deletions src/corehost/cli/comhost/comhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,23 @@ namespace
{
return load_fxr_and_get_delegate(
hostfxr_delegate_type::com_activation,
[](const pal::string_t& host_path, pal::string_t* app_path_out)
[app_path](const pal::string_t& host_path, pal::string_t* config_path_out)
{
pal::string_t app_path_local{ host_path };

// Strip the comhost suffix to get the 'app'
size_t idx = app_path_local.rfind(_X(".comhost.dll"));
// Strip the comhost suffix to get the 'app' and config
size_t idx = host_path.rfind(_X(".comhost.dll"));
assert(idx != pal::string_t::npos);

pal::string_t app_path_local{ host_path };
app_path_local.replace(app_path_local.begin() + idx, app_path_local.end(), _X(".dll"));
*app_path = std::move(app_path_local);

*app_path_out = std::move(app_path_local);
pal::string_t config_path_local { host_path };
config_path_local.replace(config_path_local.begin() + idx, config_path_local.end(), _X(".runtimeconfig.json"));
*config_path_out = std::move(config_path_local);

return StatusCode::Success;
},
delegate,
app_path
delegate
);
}

Expand Down
66 changes: 66 additions & 0 deletions src/corehost/cli/corehost_context_contract.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
Comment thread
vitek-karas marked this conversation as resolved.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef __COREHOST_CONTEXT_CONTRACT_H__
#define __COREHOST_CONTEXT_CONTRACT_H__

#include "host_interface.h"
#include <pal.h>

enum intialization_options_t : int32_t
{
none = 0x0,
wait_for_initialized = 0x1, // Wait until initialization through a different request is completed
};

enum class coreclr_delegate_type
{
invalid,
com_activation,
load_in_memory_assembly,
winrt_activation
};

#pragma pack(push, _HOST_INTERFACE_PACK)
struct corehost_initialize_request_t
{
size_t version;
strarr_t config_keys;
strarr_t config_values;
};
static_assert(offsetof(corehost_initialize_request_t, version) == 0 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_initialize_request_t, config_keys) == 1 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_initialize_request_t, config_values) == 3 * sizeof(size_t), "Struct offset breaks backwards compatibility");

struct corehost_context_contract
Comment thread
elinor-fung marked this conversation as resolved.
{
size_t version;
int (__cdecl *get_property_value)(
const pal::char_t* key,
/*out*/ const pal::char_t** value);
int (__cdecl *set_property_value)(
const pal::char_t* key,
const pal::char_t* value);
int (__cdecl *get_properties)(
/*inout*/ size_t *count,
/*out*/ const pal::char_t** keys,
/*out*/ const pal::char_t** values);
int (__cdecl *load_runtime)();
int (__cdecl *run_app)(
const int argc,
const pal::char_t* argv[]);
int (__cdecl *get_runtime_delegate)(
coreclr_delegate_type type,
/*out*/ void** delegate);
};
static_assert(offsetof(corehost_context_contract, version) == 0 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, get_property_value) == 1 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, set_property_value) == 2 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, get_properties) == 3 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, load_runtime) == 4 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, run_app) == 5 * sizeof(size_t), "Struct offset breaks backwards compatibility");
static_assert(offsetof(corehost_context_contract, get_runtime_delegate) == 6 * sizeof(size_t), "Struct offset breaks backwards compatibility");
#pragma pack(pop)

#endif // __COREHOST_CONTEXT_CONTRACT_H__
3 changes: 3 additions & 0 deletions src/corehost/cli/fxr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ set(SOURCES
./fx_resolver.cpp
./fx_resolver.messages.cpp
./framework_info.cpp
./host_context.cpp
./hostpolicy_resolver.cpp
./sdk_info.cpp
./sdk_resolver.cpp
)

set(HEADERS
../corehost_context_contract.h
../deps_format.h
../deps_entry.h
../host_startup_info.h
Expand All @@ -52,6 +54,7 @@ set(HEADERS
./fx_muxer.h
./fx_resolver.h
./framework_info.h
./host_context.h
./hostpolicy_resolver.h
./sdk_info.h
./sdk_resolver.h
Expand Down
2 changes: 1 addition & 1 deletion src/corehost/cli/fxr/corehost_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,4 @@ const host_interface_t& corehost_init_t::get_host_init_data()
hi.host_info_app_path = m_host_info_app_path.c_str();

return hi;
}
}
Loading