ShutdownSynchronization.h (6746B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <winget/AsyncTokens.h> 5 #include <wil/resource.h> 6 #include <atomic> 7 #include <set> 8 9 namespace winrt::Microsoft::Management::Configuration::implementation 10 { 11 // Promise type implementation for cancellation_token 12 struct ShutdownAwareAsyncCancellationPromise 13 { 14 Windows::Foundation::AsyncStatus Status() noexcept; 15 void cancellation_callback(winrt::delegate<>&& cancel) noexcept; 16 bool enable_cancellation_propagation(bool value) noexcept; 17 void Cancel() noexcept; 18 19 private: 20 slim_mutex m_lock; 21 winrt::delegate<> m_cancel; 22 std::atomic<Windows::Foundation::AsyncStatus> m_status{ Windows::Foundation::AsyncStatus::Started }; 23 }; 24 25 // An AsyncCancellation that registers with ShutdownSynchronization. 26 struct ShutdownAwareAsyncCancellation 27 { 28 // Creates a cancellable object without an external cancellation token. 29 ShutdownAwareAsyncCancellation(); 30 31 // Create a cancellation object from the winrt token. 32 template <typename Promise> 33 ShutdownAwareAsyncCancellation(winrt::impl::cancellation_token<Promise>&& token) 34 { 35 m_cancellation = std::make_unique<AppInstaller::WinRT::AsyncCancellation>(std::move(token)); 36 RegisterWithShutdownSynchronization(); 37 } 38 39 // Removes the shutdown registration. 40 ~ShutdownAwareAsyncCancellation(); 41 42 // Returns true if the operation has been cancelled, false if not. 43 bool IsCancelled() const noexcept; 44 45 // Throws the appropriate exception if the operation has been cancelled. 46 void ThrowIfCancelled() const; 47 48 // Sets a callback that will be invoked on cancellation. 49 void Callback(winrt::delegate<>&& callback) const noexcept; 50 51 protected: 52 void RegisterWithShutdownSynchronization(); 53 54 std::unique_ptr<ShutdownAwareAsyncCancellationPromise> m_defaultPromise; 55 std::unique_ptr<AppInstaller::WinRT::AsyncCancellation> m_cancellation; 56 }; 57 58 // An AsyncProgress that registers with ShutdownSynchronization. 59 template <typename ResultT, typename ProgressT> 60 struct ShutdownAwareAsyncProgress 61 { 62 // Creates a cancellable object without an external cancellation token. 63 ShutdownAwareAsyncProgress() 64 { 65 m_defaultPromise = std::make_unique<ShutdownAwareAsyncCancellationPromise>(); 66 m_progress = std::make_unique<AppInstaller::WinRT::AsyncProgress<ResultT, ProgressT>>(winrt::impl::cancellation_token<ShutdownAwareAsyncCancellationPromise>{ m_defaultPromise.get() }); 67 RegisterWithShutdownSynchronization(); 68 } 69 70 // Create a progress object from the winrt token. 71 template <typename Promise> 72 ShutdownAwareAsyncProgress(winrt::impl::progress_token<Promise, ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) 73 { 74 m_progress = std::make_unique<AppInstaller::WinRT::AsyncProgress<ResultT, ProgressT>>(std::move(progress), std::move(cancellation)); 75 RegisterWithShutdownSynchronization(); 76 } 77 78 // Create a progress object from an EventHandler. 79 template <typename Promise> 80 ShutdownAwareAsyncProgress(winrt::Windows::Foundation::EventHandler<ProgressT>&& progress, winrt::impl::cancellation_token<Promise>&& cancellation) 81 { 82 m_progress = std::make_unique<AppInstaller::WinRT::AsyncProgress<ResultT, ProgressT>>(std::move(progress), std::move(cancellation)); 83 RegisterWithShutdownSynchronization(); 84 } 85 86 ShutdownAwareAsyncProgress(const ShutdownAwareAsyncProgress&) = delete; 87 ShutdownAwareAsyncProgress& operator=(const ShutdownAwareAsyncProgress&) = delete; 88 89 ShutdownAwareAsyncProgress(ShutdownAwareAsyncProgress&&) = default; 90 ShutdownAwareAsyncProgress& operator=(ShutdownAwareAsyncProgress&&) = default; 91 92 // Removes the shutdown registration. 93 ~ShutdownAwareAsyncProgress() 94 { 95 if (m_progress) 96 { 97 ShutdownSynchronization::Instance().RegisterWorkEnd(m_progress->GetWeak()); 98 } 99 } 100 101 AppInstaller::WinRT::AsyncCancellation& GetCancellation() 102 { 103 return *m_progress; 104 } 105 106 // Returns true if the operation has been cancelled, false if not. 107 bool IsCancelled() const noexcept 108 { 109 return m_progress->IsCancelled(); 110 } 111 112 // Throws the appropriate exception if the operation has been cancelled. 113 void ThrowIfCancelled() const 114 { 115 m_progress->ThrowIfCancelled(); 116 } 117 118 // Sets a callback that will be invoked on cancellation. 119 void Callback(winrt::delegate<>&& callback) const noexcept 120 { 121 m_progress->Callback(std::move(callback)); 122 } 123 124 // Sends progress if this object is not empty. 125 void Progress(ProgressT const& progress) const 126 { 127 m_progress->Progress(progress); 128 } 129 130 // Sets the result onto the progress object if it is not empty. 131 void Result(ResultT const& result) const 132 { 133 m_progress->Result(result); 134 } 135 136 protected: 137 void RegisterWithShutdownSynchronization() 138 { 139 ShutdownSynchronization::Instance().RegisterWorkBegin(m_progress->GetWeak()); 140 } 141 142 std::unique_ptr<ShutdownAwareAsyncCancellationPromise> m_defaultPromise; 143 std::unique_ptr<AppInstaller::WinRT::AsyncProgress<ResultT, ProgressT>> m_progress; 144 }; 145 146 struct ShutdownSynchronization 147 { 148 using CancellableWeakPtr = std::weak_ptr<AppInstaller::WinRT::details::AsyncCancellationTypeErasure>; 149 150 ShutdownSynchronization() = default; 151 152 static ShutdownSynchronization& Instance(); 153 154 // Signals that new work should be blocked. 155 void BlockNewWork(); 156 157 // Call to register the begin and end of work. 158 void RegisterWorkBegin(CancellableWeakPtr&& ptr); 159 void RegisterWorkEnd(CancellableWeakPtr&& ptr); 160 161 // Cancels all currently registered work. 162 void CancelAllWork(); 163 164 // Waits for outstanding work to be completed. 165 void Wait(); 166 167 private: 168 std::atomic_bool m_disabled{ false }; 169 std::mutex m_workLock; 170 std::set<CancellableWeakPtr, std::owner_less<CancellableWeakPtr>> m_work; 171 wil::slim_event_manual_reset m_noActiveWork{ true }; 172 }; 173 }