winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }