master
cpp 106 lines 2.54 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 IORelay.cpp
8
9 Abstract:
10
11 Contains the implementation of the IORelay class.
12
13 --*/
14
15 #include "IORelay.h"
16
17 using wsl::windows::common::io::DockerIORelayHandle;
18 using wsl::windows::common::io::MultiHandleWait;
19 using wsl::windows::common::io::OverlappedIOHandle;
20 using wsl::windows::service::wslc::IORelay;
21
22 IORelay::IORelay()
23 {
24 m_thread = std::thread([this]() { Run(); });
25 }
26
27 IORelay::~IORelay()
28 {
29 Stop();
30 }
31
32 void IORelay::AddHandle(std::unique_ptr<common::io::OverlappedIOHandle>&& Handle)
33 {
34 std::vector<std::unique_ptr<common::io::OverlappedIOHandle>> handles;
35 handles.emplace_back(std::move(Handle));
36
37 AddHandles(std::move(handles));
38 }
39
40 void IORelay::AddHandles(std::vector<std::unique_ptr<common::io::OverlappedIOHandle>>&& Handles)
41 {
42 WI_ASSERT(!m_exit);
43
44 std::lock_guard lock(m_pendingHandlesLock);
45
46 // Append the new handles
47 // N.B. IgnoreErrors is set so the IO doesn't stop on individual handle errors.
48
49 for (auto& e : Handles)
50 {
51 WI_ASSERT(!!e);
52 m_pendingHandles.emplace_back(std::move(e));
53 }
54
55 // Restart the relay thread.
56 m_refreshEvent.SetEvent();
57 }
58
59 void IORelay::Stop()
60 {
61 m_exit = true;
62 m_refreshEvent.SetEvent();
63
64 // Skip join if called from the IORelay thread itself (e.g., from a handle callback).
65 if (m_thread.joinable() && m_thread.get_id() != std::this_thread::get_id())
66 {
67 m_thread.join();
68 }
69 }
70
71 bool IORelay::IsRelayThread() const noexcept
72 {
73 return m_thread.get_id() == std::this_thread::get_id();
74 }
75
76 void IORelay::Run()
77 try
78 {
79 common::wslutil::SetThreadDescription(L"IORelay");
80
81 // Handle callbacks dispatched from this thread (e.g. unexpected VM exit) can tear the VM down,
82 // releasing cross-process COM proxies, so join the process MTA to avoid RPC_E_WRONG_THREAD.
83 const auto coInit = wil::CoInitializeEx(COINIT_MULTITHREADED);
84
85 windows::common::io::MultiHandleWait io;
86
87 // N.B. All the IO must happen on the thread.
88 // If the thread that scheduled the IO exits, the IO is cancelled.
89 while (!m_exit)
90 {
91 {
92 // Add any pending handles.
93 std::lock_guard lock(m_pendingHandlesLock);
94 for (auto& e : m_pendingHandles)
95 {
96 io.AddHandle(std::move(e), MultiHandleWait::IgnoreErrors);
97 }
98
99 m_pendingHandles.clear();
100 }
101
102 io.AddHandle(std::make_unique<common::io::EventHandle>(m_refreshEvent.get()), MultiHandleWait::CancelOnCompleted);
103 io.Run({});
104 }
105 }
106 CATCH_LOG();