ShutdownSynchronization.cpp (4956B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "ShutdownSynchronization.h" 5 6 namespace winrt::Microsoft::Management::Configuration::implementation 7 { 8 ShutdownAwareAsyncCancellation::ShutdownAwareAsyncCancellation() 9 { 10 m_defaultPromise = std::make_unique<ShutdownAwareAsyncCancellationPromise>(); 11 m_cancellation = std::make_unique<AppInstaller::WinRT::AsyncCancellation>(winrt::impl::cancellation_token<ShutdownAwareAsyncCancellationPromise>{ m_defaultPromise.get() }); 12 RegisterWithShutdownSynchronization(); 13 } 14 15 ShutdownAwareAsyncCancellation::~ShutdownAwareAsyncCancellation() 16 { 17 if (m_cancellation) 18 { 19 ShutdownSynchronization::Instance().RegisterWorkEnd(m_cancellation->GetWeak()); 20 } 21 } 22 23 bool ShutdownAwareAsyncCancellation::IsCancelled() const noexcept 24 { 25 return m_cancellation->IsCancelled(); 26 } 27 28 void ShutdownAwareAsyncCancellation::ThrowIfCancelled() const 29 { 30 m_cancellation->ThrowIfCancelled(); 31 } 32 33 void ShutdownAwareAsyncCancellation::Callback(winrt::delegate<>&& callback) const noexcept 34 { 35 m_cancellation->Callback(std::move(callback)); 36 } 37 38 void ShutdownAwareAsyncCancellation::RegisterWithShutdownSynchronization() 39 { 40 ShutdownSynchronization::Instance().RegisterWorkBegin(m_cancellation->GetWeak()); 41 } 42 43 Windows::Foundation::AsyncStatus ShutdownAwareAsyncCancellationPromise::Status() noexcept 44 { 45 return m_status.load(std::memory_order_acquire); 46 } 47 48 void ShutdownAwareAsyncCancellationPromise::cancellation_callback(winrt::delegate<>&& cancel) noexcept 49 { 50 { 51 slim_lock_guard const guard(m_lock); 52 53 if (m_status.load(std::memory_order_relaxed) != Windows::Foundation::AsyncStatus::Canceled) 54 { 55 m_cancel = std::move(cancel); 56 return; 57 } 58 } 59 60 if (cancel) 61 { 62 cancel(); 63 } 64 } 65 66 bool ShutdownAwareAsyncCancellationPromise::enable_cancellation_propagation(bool) noexcept 67 { 68 THROW_HR(E_NOTIMPL); 69 } 70 71 void ShutdownAwareAsyncCancellationPromise::Cancel() noexcept 72 { 73 winrt::delegate<> cancel; 74 75 { 76 slim_lock_guard const guard(m_lock); 77 78 if (m_status.load(std::memory_order_relaxed) == Windows::Foundation::AsyncStatus::Started) 79 { 80 m_status.store(Windows::Foundation::AsyncStatus::Canceled, std::memory_order_relaxed); 81 cancel = std::move(m_cancel); 82 } 83 } 84 85 if (cancel) 86 { 87 cancel(); 88 } 89 } 90 91 ShutdownSynchronization& ShutdownSynchronization::Instance() 92 { 93 static ShutdownSynchronization s_instance; 94 return s_instance; 95 } 96 97 void ShutdownSynchronization::BlockNewWork() 98 { 99 m_disabled = true; 100 } 101 102 void ShutdownSynchronization::RegisterWorkBegin(CancellableWeakPtr&& ptr) 103 { 104 if (m_disabled) 105 { 106 THROW_HR(E_ABORT); 107 } 108 109 std::lock_guard<std::mutex> lock{ m_workLock }; 110 m_work.emplace(std::move(ptr)); 111 m_noActiveWork.ResetEvent(); 112 } 113 114 void ShutdownSynchronization::RegisterWorkEnd(CancellableWeakPtr&& ptr) 115 { 116 std::lock_guard<std::mutex> lock{ m_workLock }; 117 118 auto itr = m_work.find(ptr); 119 if (itr != m_work.end()) 120 { 121 m_work.erase(itr); 122 123 if (m_work.empty()) 124 { 125 m_noActiveWork.SetEvent(); 126 } 127 } 128 } 129 130 void ShutdownSynchronization::CancelAllWork() 131 { 132 std::lock_guard<std::mutex> lock{ m_workLock }; 133 134 for (auto itr = m_work.begin(); itr != m_work.end(); ++itr) 135 { 136 if (auto locked = itr->lock()) 137 { 138 locked->Cancel(); 139 } 140 else 141 { 142 m_work.erase(itr); 143 } 144 } 145 146 if (m_work.empty()) 147 { 148 m_noActiveWork.SetEvent(); 149 } 150 } 151 152 void ShutdownSynchronization::Wait() 153 { 154 for (;;) 155 { 156 { 157 std::lock_guard<std::mutex> lock{ m_workLock }; 158 159 // Check for any inactive work before waiting 160 for (auto itr = m_work.begin(); itr != m_work.end(); ++itr) 161 { 162 if (!itr->lock()) 163 { 164 m_work.erase(itr); 165 } 166 } 167 168 if (m_work.empty()) 169 { 170 break; 171 } 172 } 173 174 if (m_noActiveWork.wait(250)) 175 { 176 break; 177 } 178 } 179 } 180 }