| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | Lifetime.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | This file contains function declarations around client lifetime. |
| 12 | |
| 13 | --*/ |
| 14 | |
| 15 | #pragma once |
| 16 | #include <mutex> |
| 17 | #include <wil/resource.h> |
| 18 | |
| 19 | class LifetimeManager |
| 20 | { |
| 21 | public: |
| 22 | LifetimeManager(); |
| 23 | ~LifetimeManager(); |
| 24 | |
| 25 | LifetimeManager(const LifetimeManager&) = delete; |
| 26 | void operator=(const LifetimeManager&) = delete; |
| 27 | LifetimeManager(LifetimeManager&& source) = delete; |
| 28 | |
| 29 | ULONG64 GetRegistrationId(); |
| 30 | |
| 31 | bool IsAnyProcessRegistered(_In_ ULONG64 ClientKey); |
| 32 | |
| 33 | void RegisterCallback(_In_ ULONG64 ClientKey, _In_ const std::function<bool(void)>& Callback, _In_opt_ HANDLE ClientProcess, _In_ DWORD TimeoutMs = 0); |
| 34 | |
| 35 | bool RemoveCallback(_In_ ULONG64 ClientKey); |
| 36 | |
| 37 | void ClearCallbacks(); |
| 38 | |
| 39 | struct OwnedProcess |
| 40 | { |
| 41 | OwnedProcess(); |
| 42 | ~OwnedProcess(); |
| 43 | OwnedProcess(OwnedProcess&& other) noexcept; |
| 44 | void operator=(OwnedProcess&&) noexcept; |
| 45 | OwnedProcess(const OwnedProcess&) = delete; |
| 46 | void operator=(const OwnedProcess&) = delete; |
| 47 | |
| 48 | void InitializeListenForTermination(_In_ PTP_WAIT_CALLBACK Callback, _In_ PVOID Context); |
| 49 | void ListenForTermination() const; |
| 50 | |
| 51 | wil::unique_handle process; |
| 52 | wil::unique_threadpool_wait_nowait terminationWait; |
| 53 | }; |
| 54 | |
| 55 | struct ClientCallback |
| 56 | { |
| 57 | ClientCallback(); |
| 58 | ~ClientCallback(); |
| 59 | ClientCallback(ClientCallback&& other) noexcept; |
| 60 | void operator=(ClientCallback&&) noexcept; |
| 61 | ClientCallback(const ClientCallback&) = delete; |
| 62 | void operator=(const ClientCallback&) = delete; |
| 63 | |
| 64 | void CancelTimer() const; |
| 65 | void CreateTimer(_In_ PTP_TIMER_CALLBACK Callback, _In_ PVOID Context); |
| 66 | std::list<OwnedProcess>::iterator FindProcess(_In_ HANDLE Process); |
| 67 | void SetTimer(_In_ DWORD DueTimeMs) const; |
| 68 | |
| 69 | std::list<OwnedProcess> clientProcesses; |
| 70 | wil::unique_threadpool_timer_nowait timer; |
| 71 | ULONG64 clientKey{}; |
| 72 | std::function<bool(void)> callback; |
| 73 | DWORD timeout{}; |
| 74 | }; |
| 75 | |
| 76 | private: |
| 77 | _Requires_lock_held_(m_lock) |
| 78 | std::list<ClientCallback>::iterator _FindClient(_In_ ULONG64 ClientKey); |
| 79 | |
| 80 | static VOID CALLBACK s_OnClientProcessTerminated(_Inout_ PTP_CALLBACK_INSTANCE, _Inout_opt_ PVOID Context, _Inout_ PTP_WAIT Wait, _In_ TP_WAIT_RESULT WaitResult); |
| 81 | |
| 82 | static VOID CALLBACK s_OnTimeout(_Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context, _Inout_ PTP_TIMER Timer); |
| 83 | |
| 84 | std::mutex m_lock; |
| 85 | |
| 86 | _Guarded_by_(m_lock) bool m_exiting = false; |
| 87 | |
| 88 | _Guarded_by_(m_lock) ULONG64 m_nextClientKey; |
| 89 | |
| 90 | _Guarded_by_(m_lock) std::list<ClientCallback> m_callbackList; |
| 91 | |
| 92 | // N.B. There is a race that could cause AV between callbacks firing and |
| 93 | // the destruction of the lifetime manager class. To avoid the race |
| 94 | // create a chain of waits where each callback waits for the previous |
| 95 | // callback to finish. The destructor of the class waits on the final |
| 96 | // callback before returning. |
| 97 | wil::unique_threadpool_wait m_lastCallbackWait; |
| 98 | wil::unique_threadpool_timer m_lastTimerWait; |
| 99 | }; |