winget-cli

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

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 }