These changes allow for passing `nullptr` for the handle parameter of the `hostfxr_get_runtime_delegate` function. This allows in-process callers who do not have the real host context handle to invoke this function and get a runtime delegate for the primary runtime instance. Calling hostfxr_get_runtime_delegate without the handle will only work if there is an active host context, otherwise it will return StatusCode::HostInvalidState.
public const string Mixed = "mixed";
public const string NonContextMixedAppHost = "non_context_mixed_apphost";
public const string NonContextMixedDotnet = "non_context_mixed_dotnet";
+ public const string GetRuntimeDelegateForActiveContext = "get_runtime_delegate_for_active_context";
}
public class CheckProperties
propertyValidation.ValidateSecondaryContext(result, SharedTestState.SecondaryConfigPropertyName, SharedTestState.SecondaryConfigPropertyValue);
}
+ [Fact]
+ public void GetDelegate_ActiveContext()
+ {
+ string newPropertyName = "HOST_TEST_PROPERTY";
+ string[] args =
+ {
+ HostContextArg,
+ Scenario.GetRuntimeDelegateForActiveContext,
+ CheckProperties.None,
+ sharedState.HostFxrPath,
+ sharedState.RuntimeConfigPath,
+ SharedTestState.ConfigPropertyName,
+ newPropertyName
+ };
+ CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot)
+ .Execute();
+
+ result.Should().Pass()
+ .And.InitializeContextForConfig(sharedState.RuntimeConfigPath)
+ .And.CreateDelegateMock_COM()
+ .And.CreateDelegateMock_InMemoryAssembly();
+
+ CheckPropertiesValidation propertyValidation = new CheckPropertiesValidation(CheckProperties.None, LogPrefix.Config, SharedTestState.ConfigPropertyName, SharedTestState.ConfigPropertyValue);
+ propertyValidation.ValidateActiveContext(result, newPropertyName);
+ }
+
[Theory]
[InlineData(Scenario.Mixed, CheckProperties.None)]
[InlineData(Scenario.Mixed, CheckProperties.Get)]
return rc;
}
-namespace
+int fx_muxer_t::load_runtime(host_context_t *context)
{
- int load_runtime(host_context_t *context)
- {
- assert(context->type == host_context_type::initialized || context->type == host_context_type::active);
- if (context->type == host_context_type::active)
- return StatusCode::Success;
-
- const corehost_context_contract &contract = context->hostpolicy_context_contract;
- int rc = contract.load_runtime();
+ assert(context->type == host_context_type::initialized || context->type == host_context_type::active);
+ if (context->type == host_context_type::active)
+ return StatusCode::Success;
- // Mark the context as active or invalid
- context->type = rc == StatusCode::Success ? host_context_type::active : host_context_type::invalid;
+ const corehost_context_contract &contract = context->hostpolicy_context_contract;
+ int rc = contract.load_runtime();
- {
- std::lock_guard<std::mutex> lock{ g_context_lock };
- assert(g_active_host_context == nullptr);
- g_active_host_context.reset(context);
- g_context_initializing.store(false);
- }
+ // Mark the context as active or invalid
+ context->type = rc == StatusCode::Success ? host_context_type::active : host_context_type::invalid;
- g_context_initializing_cv.notify_all();
- return rc;
+ {
+ std::lock_guard<std::mutex> lock{ g_context_lock };
+ assert(g_active_host_context == nullptr);
+ g_active_host_context.reset(context);
+ g_context_initializing.store(false);
}
+
+ g_context_initializing_cv.notify_all();
+ return rc;
}
int fx_muxer_t::run_app(host_context_t *context)
{
propagate_error_writer_t propagate_error_writer_to_corehost(context->hostpolicy_contract.set_error_writer);
- int rc = load_runtime(context);
+ int rc = fx_muxer_t::load_runtime(context);
if (rc != StatusCode::Success)
return rc;
}
}
-int fx_muxer_t::get_runtime_delegate(host_context_t *context, coreclr_delegate_type type, void **delegate)
+int fx_muxer_t::get_runtime_delegate(const host_context_t *context, coreclr_delegate_type type, void **delegate)
{
switch (type)
{
{
propagate_error_writer_t propagate_error_writer_to_corehost(context->hostpolicy_contract.set_error_writer);
- if (context->type != host_context_type::secondary)
- {
- int rc = load_runtime(context);
- if (rc != StatusCode::Success)
- return rc;
- }
-
return contract.get_runtime_delegate(type, delegate);
}
}
hostfxr_handle *host_context_handle);
static int run_app(host_context_t *context);
static int get_runtime_delegate(
- host_context_t *context,
+ const host_context_t *context,
coreclr_delegate_type delegate_type,
void** delegate);
static const host_context_t* get_active_host_context();
static int close_host_context(host_context_t *context);
+ static int load_runtime(host_context_t *context);
private:
static int handle_exec_host_command(
const pal::string_t& host_command,
*delegate = nullptr;
- host_context_t *context = host_context_t::from_handle(host_context_handle);
- if (context == nullptr)
- return StatusCode::InvalidArgFailure;
-
coreclr_delegate_type delegate_type = hostfxr_delegate_to_coreclr_delegate(type);
if (delegate_type == coreclr_delegate_type::invalid)
return StatusCode::InvalidArgFailure;
+ const host_context_t *context;
+ if (host_context_handle == nullptr)
+ {
+ context = fx_muxer_t::get_active_host_context();
+ if (context == nullptr)
+ {
+ trace::error(_X("Hosting components context has not been initialized. Cannot get runtime properties."));
+ return StatusCode::HostInvalidState;
+ }
+ }
+ else
+ {
+ host_context_t *context_from_handle = host_context_t::from_handle(host_context_handle);
+ if (context_from_handle == nullptr)
+ return StatusCode::InvalidArgFailure;
+
+ if (context_from_handle->type != host_context_type::secondary)
+ {
+ int rc = fx_muxer_t::load_runtime(context_from_handle);
+ if (rc != StatusCode::Success)
+ return rc;
+ }
+
+ context = context_from_handle;
+ }
+
return fx_muxer_t::get_runtime_delegate(context, delegate_type, delegate);
}
return success && rcClose == StatusCode::Success;
}
+
+ bool get_runtime_delegate_for_active_context_test(
+ const hostfxr_exports &hostfxr,
+ const pal::char_t *config_path,
+ hostfxr_delegate_type delegate_type1,
+ hostfxr_delegate_type delegate_type2,
+ const pal::char_t *log_prefix,
+ pal::stringstream_t &test_output)
+ {
+ hostfxr_handle handle;
+ if (!init_for_config(hostfxr, config_path, &handle, log_prefix, test_output))
+ return false;
+
+ void *delegate1 = nullptr;
+ // Check that using get_runtime_delegate with the active host context will fail
+ // due to the runtime not being loaded yet.
+ bool success = get_runtime_delegate(hostfxr, nullptr, delegate_type1, &delegate1, log_prefix, test_output);
+ if (success)
+ {
+ test_output << log_prefix << _X("get_runtime_delegate with active context succeeded unexpectedly.") << std::endl;
+ return false;
+ }
+ if (nullptr != delegate1)
+ {
+ test_output << log_prefix << _X("Unexpectedly got a runtime delegate when get_runtime_delegate failed.") << std::endl;
+ return false;
+ }
+
+ // Successfully get first delegate with a defined handle.
+ success = get_runtime_delegate(hostfxr, handle, delegate_type1, &delegate1, log_prefix, test_output);
+
+ // Testing that using the active host context works for get_runtime_delegate
+ // by passing nullptr for handle parameter. The runtime must be loaded for this to succeed;
+ // the first successful call to get_runtime_delegate with a defined handle ensures that it is loaded.
+ void *delegate2;
+ success &= get_runtime_delegate(hostfxr, nullptr, delegate_type2, &delegate2, log_prefix, test_output);
+
+ int rcClose = hostfxr.close(handle);
+ if (rcClose != StatusCode::Success)
+ test_output << log_prefix << _X("hostfxr_close failed: ") << std::hex << std::showbase << rcClose << std::endl;
+
+ return success && rcClose == StatusCode::Success;
+ }
}
host_context_test::check_properties host_context_test::check_properties_from_string(const pal::char_t *str)
return app_get_function_pointer_test(hostfxr, argc, argv, config_log_prefix, test_output);
}
+
+bool host_context_test::get_runtime_delegate_for_active_context(
+ const pal::string_t &hostfxr_path,
+ const pal::char_t *config_path,
+ pal::stringstream_t &test_output)
+{
+ hostfxr_exports hostfxr{ hostfxr_path };
+
+ return get_runtime_delegate_for_active_context_test(hostfxr, config_path, first_delegate_type, secondary_delegate_type, config_log_prefix, test_output);
+}
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output);
+ bool get_runtime_delegate_for_active_context(
+ const pal::string_t &hostfxr_path,
+ const pal::char_t *config_path,
+ pal::stringstream_t &test_output);
}
bool launch_as_if_dotnet = pal::strcmp(scenario, _X("non_context_mixed_dotnet")) == 0;
success = host_context_test::non_context_mixed(check_properties, hostfxr_path, app_or_config_path, config_path, remaining_argc, remaining_argv, launch_as_if_dotnet, test_output);
}
+ else if (pal::strcmp(scenario, _X("get_runtime_delegate_for_active_context")) == 0)
+ {
+ success = host_context_test::get_runtime_delegate_for_active_context(hostfxr_path, app_or_config_path, test_output);
+ }
else
{
std::cerr << "Invalid scenario" << std::endl;