Skip to content

Conversation

@benhillis
Copy link
Member

This change adds additional debug-only tracing to help diagnose HCS / HNS issues.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances diagnostic capabilities for HCS/HNS operations by adding debug-only tracing and improving error messages. The changes include adding WSL_LOG_DEBUG calls to key functions, optimizing static data caching with std::call_once, and improving error message formatting.

Key changes:

  • Added WSL_LOG_DEBUG tracing to 11 HCS/HNS API wrapper functions for better diagnostics
  • Refactored GetProcessorFeatures() and GetSchemaVersion() to use static caching with std::call_once for thread-safe one-time initialization
  • Improved error messages by standardizing format specifiers to %ls and splitting long error messages into separate log calls

@benhillis
Copy link
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Dec 23, 2025

@benhillis I've opened a new pull request, #13973, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits December 23, 2025 14:35
…#13973)

* Initial plan

* Fix code review issues: assign g_schemaVersion and correct ExecutionContext

Co-authored-by: benhillis <[email protected]>

* Complete code review fixes

Co-authored-by: benhillis <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: benhillis <[email protected]>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 2 changed files in this pull request and generated 4 comments.

ExecutionContext context(Context::HCS);
static std::vector<std::string> g_processorFeatures;
static std::once_flag flag;
std::call_once(flag, [&]() {
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda in std::call_once captures by reference ([&]) but doesn't use any variables from the enclosing scope. This should use an empty capture list ([]) or [=] to avoid potential issues. The lambda only modifies the static variable g_processorFeatures which is safe to access without capturing.

Suggested change
std::call_once(flag, [&]() {
std::call_once(flag, []() {

Copilot uses AI. Check for mistakes.
if (version.Major >= majorVersion)
static std::pair<uint32_t, uint32_t> g_schemaVersion{};
static std::once_flag flag;
std::call_once(flag, [&]() {
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lambda in std::call_once captures by reference ([&]) but doesn't use any variables from the enclosing scope. This should use an empty capture list ([]) or [=] to avoid potential issues. The lambda only modifies the static variable g_schemaVersion which is safe to access without capturing.

Suggested change
std::call_once(flag, [&]() {
std::call_once(flag, []() {

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +123
static std::vector<std::string> g_processorFeatures;
static std::once_flag flag;
std::call_once(flag, [&]() {
ExecutionContext context(Context::HCS);

wil::unique_cotaskmem_string result;
THROW_IF_FAILED(::HcsGetServiceProperties(c_processorCapabilitiesQuery, &result));
wil::unique_cotaskmem_string result;
THROW_IF_FAILED(::HcsGetServiceProperties(c_processorCapabilitiesQuery, &result));

const auto properties = wsl::shared::FromJson<ServicePropertiesResponse<PropertyResponse<ProcessorCapabilitiesInfo>>>(result.get());
const auto properties =
wsl::shared::FromJson<ServicePropertiesResponse<PropertyResponse<ProcessorCapabilitiesInfo>>>(result.get());

const auto& response = properties.PropertyResponses.at(c_processorCapabilities);
if (response.Error)
{
THROW_HR_MSG(static_cast<HRESULT>(response.Error->Error), "%hs", response.Error->ErrorMessage.c_str());
}
const auto& response = properties.PropertyResponses.at(c_processorCapabilities);
if (response.Error)
{
THROW_HR_MSG(static_cast<HRESULT>(response.Error->Error), "%hs", response.Error->ErrorMessage.c_str());
}

g_processorFeatures = std::move(response.Response.ProcessorFeatures);
});

return response.Response.ProcessorFeatures;
return g_processorFeatures;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns a copy of g_processorFeatures by value, but if an exception is thrown during the std::call_once initialization, the static vector will remain in an uninitialized state. Subsequent calls will return the empty vector instead of retrying the initialization. Consider storing an optional or using a different pattern to handle initialization failures.

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +189
static std::pair<uint32_t, uint32_t> g_schemaVersion{};
static std::once_flag flag;
std::call_once(flag, [&]() {
ExecutionContext context(Context::HCS);

PropertyQuery query;
query.PropertyTypes.emplace_back(PropertyType::Basic);
wil::unique_cotaskmem_string result;
THROW_IF_FAILED(::HcsGetServiceProperties(wsl::shared::ToJsonW(query).c_str(), &result));

const auto properties = wsl::shared::FromJson<ServiceProperties<BasicInformation>>(result.get());
THROW_HR_IF_MSG(E_UNEXPECTED, properties.Properties.empty(), "%ls", result.get());

uint32_t majorVersion = 0;
uint32_t minorVersion = 0;
for (const auto& version : properties.Properties[0].SupportedSchemaVersions)
{
if ((version.Major > majorVersion) || (version.Minor > minorVersion))
if (version.Major >= majorVersion)
{
majorVersion = version.Major;
minorVersion = version.Minor;
if ((version.Major > majorVersion) || (version.Minor > minorVersion))
{
majorVersion = version.Major;
minorVersion = version.Minor;
}
}
}
}

return {majorVersion, minorVersion};
g_schemaVersion = {majorVersion, minorVersion};
});

return g_schemaVersion;
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function returns g_schemaVersion by value, but if an exception is thrown during the std::call_once initialization, the static pair will remain in its default-initialized state (0, 0). Subsequent calls will return (0, 0) instead of retrying the initialization. Consider storing an optional or using a different pattern to handle initialization failures.

Copilot uses AI. Check for mistakes.
@benhillis
Copy link
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Dec 24, 2025

@benhillis I've opened a new pull request, #13977, to work on those changes. Once the pull request is ready, I'll request review from you.

THROW_HR_MSG(static_cast<HRESULT>(response.Error->Error), "%hs", response.Error->ErrorMessage.c_str());
}

g_processorFeatures = std::move(response.Response.ProcessorFeatures);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this doesn't actually move the structure since response is a const reference

Comment on lines 101 to 102
std::vector<std::string> wsl::windows::common::hcs::GetProcessorFeatures()
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we're keeping a static copy, we could return a const reference to avoid copying the vector every call


wsl::shared::hns::HNSEndpoint wsl::windows::common::hcs::GetEndpointProperties(HCN_ENDPOINT Endpoint)
{
WSL_LOG_DEBUG("HcsGetEndpointProperties");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'm not sure how much we want to log this since it doesn't carry any specific information, and the below logline will display the full failure context

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Same for below calls)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is on debug builds it will give a better idea of the sequence of calls, not sure what fails.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im playing with this a bit more, will adjust.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants