ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

WSL 容器 SDK(Microsoft.WSL.Containers)SessionSettings 完全指南:会话配置、校验规则与源码级原理

WSL 容器 SDK(Microsoft.WSL.Containers)SessionSettings 完全指南:会话配置、校验规则与源码级原理 WSL 容器 SDKMicrosoft.WSL.ContainersSessionSettings 完全指南会话配置、校验规则与源码级原理【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSLSessionSettings 是 WSLWindows Subsystem for Linux容器 SDKWinRT 命名空间Microsoft.WSL.Containers底层为 WSLC/WSL Container 引擎中用于描述一个容器会话Session资源配置的配置类。本文以 sessionsettings.md 为骨架结合仓库内 WinRT 投影实现 SessionSettings.cpp、接口定义 wslcsdk.idl 与 C API 头文件 wslcsdk.h系统讲解该类的构造约束、全部属性及其校验规则、底层桥接机制并给出可直接运行的完整实战示例。读完本文你将掌握如何正确创建、配置并校验一个 WSLC 会话理解“设置对象一旦物化底层 C 结构后即不可变”的语义并能独立编写基于 Session 的容器编排程序。一、SessionSettings 在 WSLC SDK 中的定位WSLC SDK 的 C 投影暴露在命名空间winrt::Microsoft::WSL::Containers下整个对象模型分为几组见 cpp API 索引设置类Settings ClassesSessionSettings、ContainerSettings、ProcessSettings、VhdOptions核心类Core ClassesSession、Container、Process数据类、枚举、委托与事件如ImageInfo、ImageProgress、ContainerState、SessionTerminationHandler等。其中SessionSettings是会话的“入口配置”它决定了会话的名称、存储位置、CPU/内存配额、超时时间、VHD 盘要求以及是否启用 GPU。只有先把SessionSettings配好才能构造 Session 并Start()一个 WSLC 容器会话。在 wslcsdk.idl 中该类型被声明为runtimeclass SessionSettings { SessionSettings(String name, String storagePath); String Name; String StoragePath; Windows.Foundation.IReferenceUInt32 CpuCount; Windows.Foundation.IReferenceUInt32 MemorySizeInMB; Windows.Foundation.IReferenceWindows.Foundation.TimeSpan Timeout; VhdOptions VhdRequirements; Boolean EnableGpu; };注意CpuCount、MemorySizeInMB、Timeout都被声明为Windows.Foundation.IReferenceT可空引用类型这意味着它们是可选配置——不赋值时底层保持nullptr交给 WSLC 服务端使用默认值而Name、StoragePath、EnableGpu是强类型必填/默认值属性。二、构造函数会话名称与存储路径SessionSettings的构造函数签名如下SessionSettings(hstring name, hstring storagePath);两个参数都必须非空empty 即抛异常name要创建的会话名称storagePath会话存储session storage写入的路径。如果该路径不存在会被自动创建。在 SessionSettings.cpp 中构造函数直接执行了校验SessionSettings::SessionSettings(hstring const name, hstring const storagePath) : m_name(name), m_storagePath(storagePath) { if (name.empty()) { throw winrt::hresult_invalid_argument(LSession name cannot be empty); } if (storagePath.empty()) { throw winrt::hresult_invalid_argument(LStorage path cannot be empty); } }命名规则的三个关键事实名称兼具展示与标识双重身份会话名称既作为显示名称也作为机器级machine-wide的键用于标识会话。重名冲突如果已存在同名会话创建会失败并返回ERROR_ALREADY_EXISTS对应 Win32 错误码 183。机器级可见性安全警示以下信息对机器上的所有用户可见会话的名称the sessions name创建该会话的用户的 SID创建该会话的进程的 PID因此官方文档明确警告不要在会话名称中放入凭据credentials或其他敏感信息。这一点在 C API 的错误码体系中也有呼应——wslcsdk.idl 定义了Error::InvalidSessionName 0x80040608与Error::SessionReserved 0x80040607会话名称的合法性由底层服务统一校验。三、属性全景与校验规则SessionSettings共暴露 7 个可读写属性。每个 setter 在 SessionSettings.cpp 中都有对应的参数校验下表是完整清单属性类型必填/可选setter 校验规则违规即抛hresult_invalid_argumentName()hstring必填不能为空StoragePath()hstring必填不能为空CpuCount()IReferenceuint32_t可选拒绝0MemorySizeInMB()IReferenceuint32_t可选拒绝0Timeout()IReferenceTimeSpan可选不能为 0、不能为负、换算为毫秒后必须能放进uint32_tVhdRequirements()VhdOptions可选拒绝nullptr抛E_POINTEREnableGpu()bool默认 false无下面逐条结合源码展开。3.1 Name 与 StoragePathsetter 同样执行非空校验并额外增加了“初始化后不可改”的保护void SessionSettings::Name(hstring const value) { if (m_sessionSettings) { throw hresult_illegal_state_change(LCannot change session name after session has been initialized); } if (value.empty()) { throw winrt::hresult_invalid_argument(LSession name cannot be empty); } m_name value; }StoragePath的 setter 逻辑完全对称SessionSettings.cpp。这里出现的m_sessionSettings成员就是物化后的底层 C 结构指针std::unique_ptrWslcSessionSettings见 SessionSettings.h。3.2 CpuCount 与 MemorySizeInMB二者都是IReferenceuint32_t0被显式拒绝void SessionSettings::CpuCount(IReferenceuint32_t const value) { if (m_sessionSettings) { throw hresult_illegal_state_change(LCannot change CPU count after session has been initialized); } if (value value.Value() 0) { throw hresult_invalid_argument(LCPU count cannot be 0); } m_cpuCount value; }注意这里使用的是value 短路判断只有当调用方确实传入了值时才校验是否为 0传入nullptr表示不设置走服务端默认。MemorySizeInMB以MB 为单位实现完全一致SessionSettings.cpp例如4096表示 4 GB。3.3 Timeout三层校验Timeout是校验最复杂的属性共三层不能为TimeSpan::zero()换算成毫秒后不能为负换算成毫秒后必须能放进uint32_t即不超过std::numeric_limitsuint32_t::max()。源码实现SessionSettings.cppvoid SessionSettings::Timeout(IReferenceTimeSpan const value) { if (m_sessionSettings) { throw hresult_illegal_state_change(LCannot change timeout after session has been initialized); } if (value) { if (value.Value() TimeSpan::zero()) { throw hresult_invalid_argument(LTimeout cannot be 0); } // The C API takes the timeout in milliseconds as a uint32_t, // so we need to validate that the value is within range. auto timeoutMS std::chrono::duration_caststd::chrono::milliseconds(value.Value()).count(); if (timeoutMS std::numeric_limitsuint32_t::max()) { throw hresult_invalid_argument(LTimeout exceeds the allowed limit); } if (timeoutMS 0) { throw hresult_invalid_argument(LTimeout cannot be negative); } } m_timeout value; }这套校验与底层 C API 严格对齐WslcSetSessionSettingsTimeout接收的是uint32_t timeoutMS毫秒因此 WinRT 层必须在把TimeSpan传给 C 层之前完成范围检查见 wslcsdk.h。3.4 VhdRequirementsVHD 盘要求VhdRequirements的类型是VhdOptionssetter 拒绝nullptr并抛E_POINTER而非E_INVALIDARGvoid SessionSettings::VhdRequirements(VhdOptions const value) { if (m_sessionSettings) { throw hresult_illegal_state_change(LCannot change VHD requirements after session has been initialized); } if (!value) { throw winrt::hresult_error(E_POINTER, LVHD requirements cannot be null); } m_vhdRequirements value; }VhdOptions的完整定义见 VhdOptions.cpp 与 wslcsdk.idl构造签名为VhdOptions(String name, UInt64 size, VhdType type);nameVHD 名称size期望大小字节不能为 0用于创建/扩容create/expandtypeVhdType::Dynamic动态扩展或VhdType::Fixed固定大小OwnerIReferenceVhdOwneruid/gid仅命名卷named volumes支持在SessionSettings.VhdRequirements上设置Owner会在属性设置阶段直接失败E_INVALIDARG。这一限制在底层 C 结构 wslcsdk.h 中有明确注释WslcVhdRequirements中的flags、uid、gid字段“only honored by WslcCreateSessionVhdVolume”而WslcSetSessionSettingsVhd会拒绝非NONE的 flags返回E_INVALIDARGname字段则被WslcSetSessionSettingsVhd忽略。3.5 EnableGpu通过功能标志实现EnableGpu在实现上并不单独存储一个 bool而是维护一个 32 位功能标志位掩码m_featureFlags通过WI_IsFlagSet/WI_UpdateFlag读写SessionSettings.cppbool SessionSettings::EnableGpu() { return WI_IsFlagSet(m_featureFlags, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU); } void SessionSettings::EnableGpu(bool value) { if (m_sessionSettings) { throw hresult_illegal_state_change(LCannot change GPU setting after session has been initialized); } WI_UpdateFlag(m_featureFlags, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, value); }对应的标志位定义在 wslcsdk.htypedef enum WslcSessionFeatureFlags { WSLC_SESSION_FEATURE_FLAG_NONE 0x00000000, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU 0x00000004 } WslcSessionFeatureFlags;m_featureFlags的初始值是WSLC_SESSION_FEATURE_FLAG_NONE即 0等价于 GPU 关闭成员定义见 SessionSettings.h。四、不可变语义物化Materialization机制设置类的索引页 settings-classes/index.md 明确指出Settings objects become effectively immutable after the wrapper materializes the underlying C struct. 一旦包装器物化底层 C 结构设置对象就变得事实上不可变。这个机制在SessionSettings::ToStructPointer()SessionSettings.cpp中实现WslcSessionSettings* SessionSettings::ToStructPointer() { if (m_sessionSettings) { return m_sessionSettings.get(); // 已物化直接返回 } m_sessionSettings std::make_uniqueWslcSessionSettings(); winrt::check_hresult(WslcInitSessionSettings(m_name.c_str(), m_storagePath.c_str(), m_sessionSettings.get())); if (m_cpuCount) { winrt::check_hresult(WslcSetSessionSettingsCpuCount(m_sessionSettings.get(), m_cpuCount.Value())); } if (m_memorySizeInMB) { winrt::check_hresult(WslcSetSessionSettingsMemory(m_sessionSettings.get(), m_memorySizeInMB.Value())); } if (m_timeout) { auto timeoutMS std::chrono::duration_caststd::chrono::milliseconds(m_timeout.Value()).count(); winrt::check_hresult(WslcSetSessionSettingsTimeout(m_sessionSettings.get(), static_castuint32_t(timeoutMS))); } if (m_vhdRequirements) { winrt::check_hresult(WslcSetSessionSettingsVhd(m_sessionSettings.get(), GetStructPointer(m_vhdRequirements))); } winrt::check_hresult(WslcSetSessionSettingsFeatureFlags(m_sessionSettings.get(), m_featureFlags)); return m_sessionSettings.get(); }要点惰性物化lazy materialization只有首次调用ToStructPointer()时才分配WslcSessionSettings并调用 C API 的WslcInitSessionSettings一次性写入物化之后所有 setter 都会抛hresult_illegal_state_change例如 “Cannot change CPU count after session has been initialized”保证底层 C 结构一旦生成就不再被改写按需下发只有显式设置过的可选属性非nullptr才会调用对应的WslcSetSessionSettings*系列函数Timeout在此处完成TimeSpan→uint32_t毫秒的最终转换底层 C API 全集见 wslcsdk.hSTDAPI WslcInitSessionSettings(_In_ PCWSTR name, _In_ PCWSTR storagePath, _Out_ WslcSessionSettings* sessionSettings); STDAPI WslcCreateSession(_In_ WslcSessionSettings* sessionSettings, _Out_ WslcSession* session, _Outptr_opt_result_z_ PWSTR* errorMessage); STDAPI WslcSetSessionSettingsCpuCount(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t cpuCount); STDAPI WslcSetSessionSettingsMemory(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t memoryMB); STDAPI WslcSetSessionSettingsTimeout(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t timeoutMS); STDAPI WslcSetSessionSettingsVhd(_In_ WslcSessionSettings* sessionSettings, _In_opt_ const WslcVhdRequirements* vhdRequirements); STDAPI WslcSetSessionSettingsFeatureFlags(_In_ WslcSessionSettings* sessionSettings, _In_ WslcSessionFeatureFlags flags);底层WslcSessionSettings是一个不透明结构opaque struct内部为BYTE _opaque[WSLC_SESSION_OPTIONS_SIZE]应用层无法直接窥探或修改其内容只能通过上述 setter 函数写入wslcsdk.h。五、官方示例属性的设置与读取原文档给出的完整示例覆盖了所有属性的“写”与“读”SessionSettings settings{ Ldemo, LC:\\WSLC\\demo }; settings.Name(Ldemo); settings.StoragePath(LC:\\WSLC\\demo); settings.CpuCount(winrt::box_valueuint32_t(4).aswinrt::Windows::Foundation::IReferenceuint32_t()); settings.MemorySizeInMB(winrt::box_valueuint32_t(4096).aswinrt::Windows::Foundation::IReferenceuint32_t()); settings.Timeout(winrt::box_value(winrt::Windows::Foundation::TimeSpan{ std::chrono::minutes(5) }) .aswinrt::Windows::Foundation::IReferencewinrt::Windows::Foundation::TimeSpan()); settings.EnableGpu(true); auto name settings.Name(); auto path settings.StoragePath(); auto cpu settings.CpuCount(); auto memory settings.MemorySizeInMB(); auto timeout settings.Timeout(); auto enableGpu settings.EnableGpu();解读与实操提示构造即校验Ldemo与LC:\\WSLC\\demo都非空构造合法若 storagePath 目录不存在底层会在创建会话时自动创建box_valueasIReferenceT这是给 WinRTIReferenceT属性赋值时的惯用包装手法——先用winrt::box_value装箱再as到对应的可空引用类型CpuCount(4)、MemorySizeInMB(4096)也可以直接传入整数字面量C/WinRT 会隐式转换上面的写法是更显式的等价形式Timeout用std::chrono表达std::chrono::minutes(5)表示 5 分钟换算后为 300000 毫秒落在uint32_t范围内校验通过读取返回值getter 返回的值与设置值一一对应未设置的属性将返回nullptr如示例中未设置的VhdRequirements可在读取后判空处理。六、实战从 SessionSettings 到完整会话生命周期SessionSettings单独存在没有意义它的消费方是Session类session.md。Session的构造函数直接接收SessionSettings拒绝nullptr之后通过Start()启动会话。以下代码来自仓库的 end-to-end-example.md完整演示了“检查前置条件 → 打印 SDK 版本 → 创建会话4 CPU / 4 GB→ 拉取 alpine 镜像 → 配置 init 进程 → 创建并启动容器 → 等待退出 → 清理”的全流程其中第 1 步正是SessionSettings的典型用法#include cstdio #include string #include chrono #include winrt/Microsoft.WSL.Containers.h #include winrt/Windows.Foundation.h #include winrt/Windows.Foundation.Collections.h using namespace winrt; using namespace winrt::Microsoft::WSL::Containers; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Foundation::Collections; using namespace std::chrono_literals; int main() { init_apartment(); // 0. Check prerequisites auto missing WslcService::GetMissingComponents(); if (missing ! static_castComponent(0)) { printf(WSL components are missing. Run: wsl --install\n); return 1; } auto ver WslcService::GetVersion(); printf(WSL version: %u.%u.%u\n, ver.Major(), ver.Minor(), ver.Revision()); // 1. Create a session SessionSettings sessionSettings{ LMyApp, LC:\\WslcData }; sessionSettings.CpuCount(4); sessionSettings.MemorySizeInMB(4096); Session session{ sessionSettings }; session.Start(); // 2. Pull an image PullImageOptions pullOpts{ Ldocker.io/library/alpine:latest }; auto pullOp session.PullImageAsync(pullOpts); co_await pullOp; // 3. Configure an init process ProcessSettings initProcSettings; initProcSettings.OutputMode(ProcessOutputMode::Event); auto argv single_threaded_vectorhstring(); argv.Append(L/bin/echo); argv.Append(LHello from WSL Container!); initProcSettings.CommandLine(argv); // 4. Configure and create a container ContainerSettings containerSettings{ Lalpine:latest }; containerSettings.Name(Lhello-container); containerSettings.InitProcess(initProcSettings); auto container session.CreateContainer(containerSettings); // 5. Subscribe to init process events before starting auto initProcess container.InitProcess(); auto exitedEvent handle{ CreateEvent(nullptr, TRUE, FALSE, nullptr) }; int32_t initExitCode -1; initProcess.OutputReceived([](auto const data) { std::string text(data.begin(), data.end()); printf(%s, text.c_str()); }); initProcess.Exited( { initExitCode exitCode; SetEvent(exitedEvent.get()); }); // 6. Start the container container.Start(); // 7. Wait for the init process to exit (30-second timeout) WaitForSingleObject(exitedEvent.get(), 30000); printf(Process exited with code: %d\n, initExitCode); // 8. Clean up if (container.State() ContainerState::Running) { container.Stop(Signal::SIGTERM, 10s); } container.Delete(DeleteContainerOption::None); session.Terminate(); return 0; }关于Session的几个行为要点session.md与SessionSettings的使用强相关Start()是一次性的one-shot重复调用会抛异常调用前会先完成SessionSettings的物化与 C 结构下发多数方法内部会先EnsureStarted()因此SessionSettings的配置必须在Start()之前定稿——这也正是设置对象“物化后不可变”语义存在的根本原因会话终止时会触发Terminated事件进程崩溃会触发ProcessCrashed示例中通过session.Terminate()显式收尾。七、常见错误与排查速查结合 Error 枚举 与 setter 校验常见的失败场景如下场景失败表现解决办法name或storagePath传空串构造/setter 抛hresult_invalid_argument传入非空字符串机器上已存在同名会话创建会话返回ERROR_ALREADY_EXISTS更换会话名或先终止旧会话CpuCount/MemorySizeInMB传 0setter 抛hresult_invalid_argument传入 ≥1 的值或不设置走默认Timeout为 0 / 负 / 超uint32_t毫秒上限setter 抛hresult_invalid_argument使用正的、合理范围内的TimeSpanVhdRequirements传nullptrsetter 抛E_POINTER先构造VhdOptions在会话初始化后再改任何属性setter 抛hresult_illegal_state_change在Session.Start()/ 物化之前完成全部配置会话名含敏感信息凭据等无运行时错误但所有用户可见遵守安全规范避免在名称中放敏感数据结语SessionSettings是 WSLC 容器会话的“总配置面板”名称与存储路径奠定会话的身份和落盘位置CPU/内存/超时/VHD/GPU 决定会话的运行能力而“物化后不可变”的语义保证了配置在交给Session之后的一贯性。理解它的构造约束、属性校验与底层 C 桥接WslcInitSessionSettings 系列 setter是安全、正确地使用 WSL 容器 SDK 的第一步。进一步阅读可参考 Session 文档、settings-classes 索引 以及 完整的端到端示例。【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表