Allow getting contract for previously initialized hostpolicy (dotnet/core-setup#6343)
authorElinor Fung <47805090+elinor-fung@users.noreply.github.com>
Tue, 7 May 2019 22:47:06 +0000 (15:47 -0700)
committerGitHub <noreply@github.com>
Tue, 7 May 2019 22:47:06 +0000 (15:47 -0700)
This enables getting runtime properties for the active context created
through non-context-based entry points.

Commit migrated from https://github.com/dotnet/core-setup/commit/5c4ca8ac2deb15ca57c37c5a8e9a6cec8a10944f

docs/installer/design-docs/hosting-layer-apis.md
src/installer/corehost/cli/corehost_context_contract.h
src/installer/corehost/cli/fxr/fx_muxer.cpp
src/installer/corehost/cli/fxr/host_context.h
src/installer/corehost/cli/fxr/hostfxr.cpp
src/installer/corehost/cli/hostpolicy/hostpolicy.cpp
src/installer/test/HostActivationTests/NativeHosting/HostContext.cs

index 5ef43ab..6c97158 100644 (file)
@@ -336,7 +336,6 @@ typedef void* context_handle;
 struct corehost_context_contract
 {
     size_t version;
-    context_handle instance;
     int (*get_property_value)(
         const char_t *key,
         const char_t **value);
@@ -349,11 +348,9 @@ struct corehost_context_contract
         const char_t **values);
     int (*load_runtime)();
     int (*run_app)(
-        const context_handle instance,
         const int argc,
         const char_t* argv[]);
     int (*get_runtime_delegate)(
-        const context_handle instance,
         coreclr_delegate_type type,
         void** delegate);
 };
@@ -361,7 +358,6 @@ struct corehost_context_contract
 
 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.
   * `key` - key of the property to get.
   * `value` - pointer to a buffer with the retrieved property value.
@@ -384,13 +380,15 @@ enum intialization_options_t
 {
     none = 0x0,
     wait_for_initialized = 0x1,
+    get_contract = 0x2,
 };
 
 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).
+Initialize hostpolicy. This calculates everything required to start or attach to CoreCLR (but does not actually do so).
 * `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.
+  * `get_contract` - get the contract for already initialized hostpolicy
+* `context_contract` - if initialization is successful, this is populated with the contract for operating on the initialized hostpolicy.
index 789c290..be5071e 100644 (file)
@@ -12,6 +12,7 @@ enum intialization_options_t : int32_t
 {
     none = 0x0,
     wait_for_initialized = 0x1,  // Wait until initialization through a different request is completed
+    get_contract = 0x2,          // Get the contract for the initialized hostpolicy
 };
 
 enum class coreclr_delegate_type
index 6caa853..e31a3b0 100644 (file)
@@ -1069,6 +1069,37 @@ int fx_muxer_t::get_runtime_delegate(host_context_t *context, coreclr_delegate_t
 const host_context_t* fx_muxer_t::get_active_host_context()
 {
     std::lock_guard<std::mutex> lock{ g_context_lock };
+    if (g_active_host_context == nullptr)
+        return nullptr;
+
+    if (g_active_host_context->type == host_context_type::active)
+        return g_active_host_context.get();
+
+    if (g_active_host_context->type != host_context_type::empty)
+        return nullptr;
+
+    // Try to populate the contract for the 'empty' active context (i.e. created through non-context-based APIs)
+    const hostpolicy_contract_t &hostpolicy_contract = g_active_host_context->hostpolicy_contract;
+    if (hostpolicy_contract.initialize == nullptr)
+    {
+        trace::warning(_X("Getting the contract for the initialized hostpolicy is only supprted for .NET Core 3.0 or a higher version."));
+        return nullptr;
+    }
+
+    corehost_context_contract hostpolicy_context_contract;
+    {
+        propagate_error_writer_t propagate_error_writer_to_corehost(hostpolicy_contract.set_error_writer);
+        int rc = hostpolicy_contract.initialize(nullptr, intialization_options_t::get_contract, &hostpolicy_context_contract);
+        if (rc != StatusCode::Success)
+        {
+            trace::error(_X("Failed to get contract for existing initialized hostpolicy: 0x%x"), rc);
+            return nullptr;
+        }
+    }
+
+    // Set the hostpolicy context contract on the active host context and mark it as active
+    g_active_host_context->hostpolicy_context_contract = hostpolicy_context_contract;
+    g_active_host_context->type = host_context_type::active;
     return g_active_host_context.get();
 }
 
index 42a562f..21f6d71 100644 (file)
@@ -41,7 +41,7 @@ public:
 
     host_context_type type;
     const hostpolicy_contract_t hostpolicy_contract;
-    const corehost_context_contract hostpolicy_context_contract;
+    corehost_context_contract hostpolicy_context_contract;
 
     // Whether or not the context was initialized for an app. argv will be empty for non-app contexts.
     bool is_app;
index 40df51d..0f5d757 100644 (file)
@@ -669,7 +669,7 @@ SHARED_API int32_t __cdecl hostfxr_get_runtime_property_value(
     if (host_context_handle == nullptr)
     {
         const host_context_t *context_maybe = fx_muxer_t::get_active_host_context();
-        if (context_maybe == nullptr || context_maybe->type != host_context_type::active)
+        if (context_maybe == nullptr)
         {
             trace::error(_X("Hosting components context has not been initialized. Cannot get runtime properties."));
             return StatusCode::HostInvalidState;
@@ -786,7 +786,7 @@ SHARED_API int32_t __cdecl hostfxr_get_runtime_properties(
     if (host_context_handle == nullptr)
     {
         const host_context_t *context_maybe = fx_muxer_t::get_active_host_context();
-        if (context_maybe == nullptr || context_maybe->type != host_context_type::active)
+        if (context_maybe == nullptr)
         {
             trace::error(_X("Hosting components context has not been initialized. Cannot get runtime properties."));
             return StatusCode::HostInvalidState;
index 053bf11..017909e 100644 (file)
@@ -605,7 +605,22 @@ SHARED_API int __cdecl corehost_initialize(const corehost_initialize_request_t *
         return StatusCode::InvalidArgFailure;
 
     bool wait_for_initialized = (options & intialization_options_t::wait_for_initialized) != 0;
+    bool get_contract = (options & intialization_options_t::get_contract) != 0;
+    if (wait_for_initialized && get_contract)
+    {
+        trace::error(_X("Specifying both initialization options for wait_for_initialized and get_contract is not allowed"));
+        return StatusCode::InvalidArgFailure;
+    }
 
+    if (get_contract)
+    {
+        if (init_request != nullptr)
+        {
+            trace::error(_X("Initialization request is expected to be null when getting the already initialized contract"));
+            return StatusCode::InvalidArgFailure;
+        }
+    }
+    else
     {
         std::unique_lock<std::mutex> lock { g_context_lock };
         bool already_initializing = g_context_initializing.load();
@@ -665,6 +680,17 @@ SHARED_API int __cdecl corehost_initialize(const corehost_initialize_request_t *
 
         rc = StatusCode::Success_HostAlreadyInitialized;
     }
+    else if (get_contract)
+    {
+        const hostpolicy_context_t *context = get_hostpolicy_context(/*require_runtime*/ true);
+        if (context == nullptr)
+        {
+            trace::error(_X("Option to get the contract for the initialized hostpolicy was set, but hostpolicy has not been initialized"));
+            return StatusCode::HostInvalidState;
+        }
+
+        rc = StatusCode::Success;
+    }
     else
     {
         rc = create_hostpolicy_context(g_init, args, g_init.host_mode != host_mode_t::libhost);
index 7308f40..6a44fce 100644 (file)
@@ -186,8 +186,8 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting
         [InlineData(Scenario.NonContextMixed, CheckProperties.Set)]
         [InlineData(Scenario.NonContextMixed, CheckProperties.Remove)]
         [InlineData(Scenario.NonContextMixed, CheckProperties.GetAll)]
-        // [InlineData(Scenario.NonContextMixed, CheckProperties.GetActive)]        // TODO: https://github.com/dotnet/core-setup/issues/6197
-        // [InlineData(Scenario.NonContextMixed, CheckProperties.GetAllActive)]     // TODO: https://github.com/dotnet/core-setup/issues/6197
+        [InlineData(Scenario.NonContextMixed, CheckProperties.GetActive)]
+        [InlineData(Scenario.NonContextMixed, CheckProperties.GetAllActive)]
         public void RunApp_GetDelegate(string scenario, string checkProperties)
         {
             if (scenario != Scenario.Mixed && scenario != Scenario.NonContextMixed)