Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/windows/service/exe/WslCoreInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,22 @@ void WslCoreInstance::CreateLxProcess(

// Ensure the instance is still running.

std::lock_guard lock(m_lock);
std::unique_lock lock(m_lock);
THROW_HR_IF(HCS_E_TERMINATED, (!m_initChannel || !m_consoleManager));

if (m_oobeCompleteEvent && !m_oobeCompleteEvent.is_signaled())
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageWaitingForOobe(m_configuration.Name.c_str()));
m_oobeCompleteEvent.wait();

const auto oobeCompleteEvent = m_oobeCompleteEvent;
const auto destroyingEvent = m_destroyingEvent;
const HANDLE waitHandles[] = {oobeCompleteEvent.get(), destroyingEvent.get()};
lock.unlock();
const DWORD waitResult = WaitForMultipleObjects(RTL_NUMBER_OF(waitHandles), waitHandles, FALSE, INFINITE);
Comment on lines +183 to +187

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmm this is true. The easiest solution I can think of would be to only create m_oobeCompleteEvent if it isn't already created

THROW_LAST_ERROR_IF(waitResult == WAIT_FAILED);
lock.lock();
THROW_HR_IF(HCS_E_TERMINATED, waitResult == WAIT_OBJECT_0 + 1 || !m_initChannel || !m_consoleManager);
THROW_HR_IF(E_UNEXPECTED, waitResult != WAIT_OBJECT_0);
}

// Initialize the create process message.
Expand Down
4 changes: 2 additions & 2 deletions src/windows/service/exe/WslCoreInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,6 @@ class WslCoreInstance : public LxssRunningInstance
DWORD m_socketTimeout{};
HANDLE m_jobObject{};
std::thread m_oobeThread;
wil::unique_event m_destroyingEvent{wil::EventOptions::ManualReset};
wil::unique_event m_oobeCompleteEvent;
wil::shared_event m_destroyingEvent{wil::EventOptions::ManualReset};
wil::shared_event m_oobeCompleteEvent;
};
43 changes: 43 additions & 0 deletions test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4747,6 +4747,49 @@ VERSION_ID="Invalid|Format"
TerminateDistribution();
}

WSL2_TEST_METHOD(ModernOOBETermination)
{
constexpr DWORD oobeDurationSeconds = 30;
constexpr DWORD waiterObservationTimeout = 1000;
constexpr DWORD terminationTimeout = 10000;
constexpr DWORD cleanupTimeout = 45000;

const auto lxssKey = wsl::windows::common::registry::OpenLxssUserKey();
const auto testDistroId = GetDistributionId(LXSS_DISTRO_NAME_TEST_L);
VERIFY_IS_TRUE(testDistroId.has_value());
const auto testDistroIdString = wsl::shared::string::GuidToString<wchar_t>(testDistroId.value());

DistroFileChange distributionconf(L"/etc/wsl-distribution.conf", false);
distributionconf.SetContent(
std::format(L"[oobe]\ncommand = /bin/bash -c 'echo OOBE_STARTED; sleep {}'\n", oobeDurationSeconds).c_str());

RegistryKeyChange<DWORD> runOOBE(lxssKey.get(), testDistroIdString.c_str(), L"RunOOBE", 1);
TerminateDistribution();

auto [oobeOutputRead, oobeOutputWrite] = CreateSubprocessPipe(false, true);
wsl::windows::common::SubProcess oobeProcessBuilder(
nullptr, LxssGenerateWslCommandLine(L"-d " LXSS_DISTRO_NAME_TEST_L).c_str());
oobeProcessBuilder.SetStdHandles(nullptr, oobeOutputWrite.get(), oobeOutputWrite.get());
const auto oobeProcess = oobeProcessBuilder.Start();
oobeOutputWrite.reset();

PartialHandleRead oobeOutput(oobeOutputRead.get());
oobeOutput.Expect("OOBE_STARTED\n");

wsl::windows::common::SubProcess waitingProcessBuilder(
nullptr, LxssGenerateWslCommandLine(L"-d " LXSS_DISTRO_NAME_TEST_L L" true").c_str());
const auto waitingProcess = waitingProcessBuilder.Start();
const DWORD waitingResult = WaitForSingleObject(waitingProcess.get(), waiterObservationTimeout);

wsl::windows::common::SubProcess terminationProcessBuilder(
nullptr, LxssGenerateWslCommandLine(L"--terminate " LXSS_DISTRO_NAME_TEST_L).c_str());
VERIFY_ARE_EQUAL(terminationProcessBuilder.Run(terminationTimeout), 0u);

VERIFY_ARE_EQUAL(waitingResult, WAIT_TIMEOUT);
VERIFY_ARE_EQUAL(WaitForSingleObject(waitingProcess.get(), cleanupTimeout), WAIT_OBJECT_0);
VERIFY_ARE_EQUAL(WaitForSingleObject(oobeProcess.get(), cleanupTimeout), WAIT_OBJECT_0);
}

static void ValidateDistributionStarts(LPCWSTR Name)
{
auto [out, _] = LxsstuLaunchWslAndCaptureOutput(std::format(L"-d {} echo -n OK", Name));
Expand Down