WSL 容器 SDK(WSLC)C API 深入解析:WslcInitSessionSettings 会话初始化
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
本篇文章以 Windows Subsystem for Linux(WSL)容器 SDK(WSLC)C API 中的WslcInitSessionSettings函数为核心,系统讲解 WSLC 会话(Session)的初始化流程、参数语义、默认值与底层实现原理。你将掌握如何通过该 API 声明会话名称与存储路径、理解会话名称作为机器级键的约束与安全边界,并学会在真实代码(含官方 HelloWorld 示例与 SDK 测试用例)中正确使用该函数开启一个 WSL 容器会话的生命周期。
WslcInitSessionSettings 在 WSLC 会话模型中的位置
WSLC(WSL Container)SDK 允许 Windows 应用程序以编程方式创建、配置、启动和终止轻量级 WSL 容器与其中的 Linux 进程。整个模型以“会话(Session)”为顶层单元:会话是一组容器、进程与资源的承载边界,也是 SDK 各项操作(拉取镜像、创建容器、运行进程)的上下文。
WslcInitSessionSettings正是会话生命周期的第一个函数调用:它负责把调用者提供的会话名称与存储路径写入一个WslcSessionSettings结构体,为后续的WslcCreateSession(真正创建会话)准备配置。从 src/windows/WslcSDK/wslcsdk.cpp 的实现可以看到,该函数本身并不启动任何后台服务,而是纯粹的“配置初始化”,随后由创建/设置类 API 消费这些配置。
在 C 语言 API 参考索引 中,会话相关 API 被集中收录于 Session APIs 页面,WslcInitSessionSettings是该 API 家族中第一个被调用的成员,其后才是WslcSetSessionSettingsCpuCount、WslcSetSessionSettingsMemory等可选配置项以及WslcCreateSession。
函数签名与参数详解
STDAPI WslcInitSessionSettings(_In_ PCWSTR name, _In_ PCWSTR storagePath, _Out_ WslcSessionSettings* sessionSettings);| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
name | PCWSTR | in | 待创建会话的名称,同时充当显示名称。 |
storagePath | PCWSTR | in | 会话存储的写入路径;若路径不存在,会被自动创建。 |
sessionSettings | WslcSessionSettings* | out | 指向用于接收设置结果的WslcSessionSettings结构的指针。 |
WslcSessionSettings是一个不透明结构体,其定义位于 src/windows/WslcSDK/wslcsdk.h:
#define WSLC_SESSION_OPTIONS_SIZE 72 #define WSLC_SESSION_OPTIONS_ALIGNMENT 8 typedef struct WslcSessionSettings { __declspec(align(WSLC_SESSION_OPTIONS_ALIGNMENT)) BYTE _opaque[WSLC_SESSION_OPTIONS_SIZE]; } WslcSessionSettings;调用者无需也不应直接读写该结构内部字段,而应通过WslcInitSessionSettings完成初始化,再借助WslcSetSessionSettings*系列 API 调整具体配置。这种设计将内部布局(当前为 72 字节、8 字节对齐)与调用方解耦,便于 SDK 演进时维持 ABI 兼容。
返回值
函数返回HRESULT。成功时返回S_OK。从 wslcsdk.cpp 实现 可见,若name或storagePath为NULL,函数返回E_POINTER:
RETURN_HR_IF_NULL(E_POINTER, name); RETURN_HR_IF_NULL(E_POINTER, storagePath);此外,根据 API 文档说明:如果已存在同名会话,则会话创建(而非初始化本身)将失败并返回ERROR_ALREADY_EXISTS。也就是说,名称冲突检查发生在后续的WslcCreateSession阶段。
会话名称:显示名、机器级键与安全边界
文档明确强调,会话名称承担双重职责:
- 显示名称:在日志、诊断信息与面向用户的管理界面中展示;
- 机器级键(machine-wide key):用于在整个机器范围内唯一标识一个会话。
正因为名称是机器级键,WslcInitSessionSettings允许不同用户创建的会话在命名上产生冲突,而冲突会在WslcCreateSession时以ERROR_ALREADY_EXISTS失败告终。因此,应用若需要为每个用户隔离会话,应在名称中显式编码用户维度(例如用户名或 SID 后缀),避免跨用户冲突。
全机器可见的会话元信息
即使会话本身属于某个用户,以下信息依然对机器上的所有用户可见:
- 会话的名称(
name); - 创建会话的用户的 SID;
- 创建会话的进程 PID。
这意味着调用者不应将会话名称当作安全边界。文档给出的明确告诫是:
Do not put credentials or other sensitive information in the session's name.
(不要在会话名称中放置凭据或其他敏感信息。)
这是会话命名中必须遵守的安全红线:即使名称形如“机密项目_令牌ABC”便于区分,也会因其全机器可见性而构成信息泄露风险。应在名称中仅使用可公开的业务标识符,把敏感内容放入会话存储或配置文件中。
storagePath:会话存储的落地位置
storagePath指定会话存储的写入路径。文档说明:若该路径不存在,SDK 会自动创建。从测试用例 test/windows/WslcSdkTests.cpp 可以看到,测试框架使用工作目录下的test-storage子目录:
m_storagePath = std::filesystem::current_path() / "test-storage"; WslcSessionSettings sessionSettings; VERIFY_SUCCEEDED(WslcInitSessionSettings(c_testSessionName, m_storagePath.c_str(), &sessionSettings));值得注意的实践细节:由于默认会话存储卷可达 32 GB(见下文默认值),且不同会话共享同一存储路径可显著减少镜像拉取开销,测试代码特意选择“与 WSLC 运行时测试共用同一存储路径”(见 WslcSdkTests.cpp 注释)。这为生产环境的应用提供了一个参考策略:在同一台机器上复用稳定的存储路径,可以复用已拉取的镜像与缓存,降低首次启动延迟与磁盘占用。
在实际开发中,建议:
- 使用绝对路径(如
C:\WSLC\<app-name>\session),避免依赖进程当前工作目录; - 为不同应用或不同环境规划独立的存储根目录,便于清理与迁移;
- 注意磁盘空间规划——默认 VHD 容量上限为 32 GB(详见下文),需确保存储所在卷有足够余量。
源码级实现剖析:初始化到底做了什么
WslcInitSessionSettings 的实现 非常精简,展示了“配置初始化”的全部逻辑:
STDAPI WslcInitSessionSettings(_In_ PCWSTR name, _In_ PCWSTR storagePath, _Out_ WslcSessionSettings* sessionSettings) try { RETURN_HR_IF_NULL(E_POINTER, name); RETURN_HR_IF_NULL(E_POINTER, storagePath); auto internalType = CheckAndGetInternalType(sessionSettings); *internalType = {}; internalType->displayName = name; internalType->storagePath = storagePath; internalType->cpuCount = s_DefaultCPUCount; internalType->memoryMb = s_DefaultMemoryMB; internalType->timeoutMS = s_DefaultBootTimeout; internalType->vhdRequirements.sizeBytes = s_DefaultStorageSize; return S_OK; } CATCH_RETURN();其核心行为可归纳为三点:
- 空指针防护:对
name与storagePath做空指针检查,非法输入直接返回E_POINTER; - 清空并写入基本配置:通过
CheckAndGetInternalType取得内部类型后,先整体清零,再写入displayName与storagePath; - 填充默认资源规格:CPU、内存、启动超时、存储容量全部被赋为 SDK 默认值。
默认值一览
默认值定义于 src/windows/WslcSDK/Defaults.h:
constexpr uint32_t s_DefaultCPUCount = 2; // 默认 2 个 CPU constexpr uint32_t s_DefaultMemoryMB = 2000; // 默认 2000 MB(约 2 GB)内存 // Maximum value per use with HVSOCKET_CONNECT_TIMEOUT_MAX constexpr ULONG s_DefaultBootTimeout = 300000; // 默认启动超时 300000 ms(5 分钟) // Default to 32 GB constexpr UINT64 s_DefaultStorageSize = 32ULL * 1024 * 1024 * 1024; // 默认存储 32 GB| 配置项 | 默认值 | 说明 |
|---|---|---|
| CPU 数 | 2 | 会话可见的 vCPU 数量 |
| 内存 | 2000MB | 约 2 GB,单位为 MB |
| 启动超时 | 300000ms | 5 分钟,注释提示其上限受HVSOCKET_CONNECT_TIMEOUT_MAX约束 |
| 存储容量 | 32GB | 会话存储 VHD 的默认容量上限 |
从实现可以看出,所有默认值在WslcInitSessionSettings阶段即被写入。这解释了为什么“初始化后立即调用WslcCreateSession”也能得到一个合理配置的会话;若需调整,再调用WslcSetSessionSettingsCpuCount、WslcSetSessionSettingsMemory、WslcSetSessionSettingsTimeout、WslcSetSessionSettingsVhd覆盖对应默认值即可(这些 API 的声明见 wslcsdk.h)。
完整实战:在 HelloWorld 示例中使用 WslcInitSessionSettings
官方 C 语言示例 doc/samples/WSLC-HelloWorld/helloworld.c 展示了从会话初始化到运行容器内进程的完整链路,其中会话初始化部分如下:
// 将存储目录放在可执行文件旁的 "WslcStorage" 文件夹,避免硬编码绝对路径 static void GetStoragePath(wchar_t* buffer, size_t count) { wchar_t exePath[MAX_PATH]; wchar_t* lastSlash; GetModuleFileNameW(NULL, exePath, MAX_PATH); lastSlash = wcsrchr(exePath, L'\\'); if (lastSlash != NULL) { *(lastSlash + 1) = L'\0'; } swprintf(buffer, count, L"%sWslcStorage", exePath); } int wmain(void) { // ... WslcSessionSettings sessionSettings; wchar_t storagePath[MAX_PATH]; hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) { /* 处理错误 */ } // ---- Session ---- GetStoragePath(storagePath, ARRAYSIZE(storagePath)); hr = WslcInitSessionSettings(L"WSLCHelloWorld", storagePath, &sessionSettings); if (FAILED(hr)) { PrintError(L"Init session settings", hr, NULL); goto cleanup; } hr = WslcCreateSession(&sessionSettings, &session, &error); if (FAILED(hr)) { PrintError(L"Create session", hr, error); goto cleanup; } // ... 拉取镜像、创建容器、运行进程 ... cleanup: // 结束会话:终止 + 释放 if (session != NULL) { WslcTerminateSession(session); WslcReleaseSession(session); } CoUninitialize(); return result; }示例中包含几个值得复用的工程实践:
- COM 初始化:
WslcInitSessionSettings及其后续 API 运行在 COM 之上,调用前需CoInitializeEx(NULL, COINIT_MULTITHREADED),结束时CoUninitialize(); - 存储路径的动态推导:通过
GetModuleFileNameW在可执行文件旁生成WslcStorage目录,使示例不依赖硬编码绝对路径,也演示了“路径不存在会自动创建”的特性; - 错误处理与资源清理:每个 API 调用后检查
FAILED(hr),出错时通过goto cleanup统一回收资源;会话结束时先WslcTerminateSession再WslcReleaseSession。
示例对应的构建说明与运行方式详见 WSLC-HelloWorld 的 README。
测试验证:SDK 测试如何覆盖初始化路径
test/windows/WslcSdkTests.cpp 中的 WSLC SDK 测试类把WslcInitSessionSettings作为测试夹具的起点,直接验证了“初始化 + 覆盖默认值 + 创建会话”的完整模式:
TEST_CLASS_SETUP(TestClassSetup) { THROW_IF_WIN32_ERROR(WSAStartup(MAKEWORD(2, 2), &m_wsadata)); m_storagePath = std::filesystem::current_path() / "test-storage"; // Build session settings using the WSLC SDK. WslcSessionSettings sessionSettings; VERIFY_SUCCEEDED(WslcInitSessionSettings(c_testSessionName, m_storagePath.c_str(), &sessionSettings)); VERIFY_SUCCEEDED(WslcSetSessionSettingsCpuCount(&sessionSettings, 4)); VERIFY_SUCCEEDED(WslcSetSessionSettingsMemory(&sessionSettings, 2048)); VERIFY_SUCCEEDED(WslcSetSessionSettingsTimeout(&sessionSettings, 30 * 1000)); WslcVhdRequirements vhdReqs{}; vhdReqs.sizeBytes = 4096ull * 1024 * 1024; // 4 GB vhdReqs.type = WSLC_VHD_TYPE_DYNAMIC; VERIFY_SUCCEEDED(WslcSetSessionSettingsVhd(&sessionSettings, &vhdReqs)); VERIFY_SUCCEEDED(WslcCreateSession(&sessionSettings, &m_defaultSession, nullptr)); // ... }该用例清晰地演示了“初始化 → 逐个覆盖默认资源 → 创建会话”的推荐调用次序。测试套件中还包含多个围绕会话生命周期与配置的独立用例,例如:
CreateSession测试使用独立存储目录wslc-extra-session-storage创建wslc-extra-session(WslcSdkTests.cpp);- 会话终止事件、崩溃回调、VHD 配置(
wslc-vhd-test)、GPU 特性(wslc-gpu-test)等场景均以WslcInitSessionSettings为前置步骤(WslcSdkTests.cpp、L362、L2104、L2711)。
这说明WslcInitSessionSettings是全部会话级能力(资源规格、超时、VHD、特性开关、终止事件、崩溃转储订阅)统一的入口配置点,任何会话级功能测试都始于对它的调用。
初始化之后的会话设置 API 家族
WslcInitSessionSettings只负责写入名称、存储路径与默认值,进一步的定制依赖 wslcsdk.h 中声明的一组可选设置 API:
| API | 作用 |
|---|---|
WslcSetSessionSettingsCpuCount | 设置会话 vCPU 数量(传 0 恢复默认值 2) |
WslcSetSessionSettingsMemory | 设置会话内存,单位 MB(传 0 恢复默认值 2000) |
WslcSetSessionSettingsTimeout | 设置启动超时,单位 ms(默认 300000) |
WslcSetSessionSettingsVhd | 设置会话存储 VHD 的需求(容量、类型) |
WslcSetSessionSettingsFeatureFlags | 设置会话特性标志(如WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU,值为0x00000004) |
例如从 WslcSetSessionSettingsCpuCount 的实现 可以看出,传入非零值则覆盖,传 0 则回退到s_DefaultCPUCount:
STDAPI WslcSetSessionSettingsCpuCount(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t cpuCount) try { auto internalType = CheckAndGetInternalType(sessionSettings); if (cpuCount) { internalType->cpuCount = cpuCount; } else { internalType->cpuCount = s_DefaultCPUCount; } return S_OK; } CATCH_RETURN();设置完成后,通过WslcCreateSession真正创建会话,并在此后通过WslcTerminateSession与WslcReleaseSession结束会话。完整的会话 API 列表与各自文档入口见 Session APIs 索引,一个贯通全部步骤的端到端示例见 end-to-end-example.md。
使用要点小结
WslcInitSessionSettings是 WSLC 会话生命周期的第一步,负责写入会话名称、存储路径并填充 CPU/内存/超时/存储的默认值,本身不执行任何重操作;- 传入
NULL的name或storagePath将得到E_POINTER;同名会话冲突(ERROR_ALREADY_EXISTS)发生在后续的WslcCreateSession; - 会话名称既是显示名又是机器级键,且会话名称、创建者 SID、创建进程 PID 对全机器用户可见,严禁把凭据或敏感信息放入会话名称;
- 存储路径不存在时会自动创建,合理的路径规划(绝对路径、复用存储目录)有助于镜像缓存复用与降低启动开销;
- 默认资源规格(2 CPU / 2000 MB 内存 / 300000 ms 超时 / 32 GB 存储)在初始化阶段即已生效,可通过
WslcSetSessionSettings*系列 API 覆盖,传 0 可回退默认值; - 调用前需完成 COM 初始化(
CoInitializeEx),会话结束时应依次调用WslcTerminateSession与WslcReleaseSession释放资源。
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考