diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /ipc/mscom/Ptr.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/mscom/Ptr.h')
-rw-r--r-- | ipc/mscom/Ptr.h | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/ipc/mscom/Ptr.h b/ipc/mscom/Ptr.h new file mode 100644 index 0000000000..fd4bd9c91f --- /dev/null +++ b/ipc/mscom/Ptr.h @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_mscom_Ptr_h +#define mozilla_mscom_Ptr_h + +#include "mozilla/Assertions.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/mscom/EnsureMTA.h" +#include "mozilla/SchedulerGroup.h" +#include "mozilla/UniquePtr.h" +#include "nsError.h" +#include "nsThreadUtils.h" +#include "nsXULAppAPI.h" + +#include <objidl.h> + +/** + * The glue code in mozilla::mscom often needs to pass around interface pointers + * belonging to a different apartment from the current one. We must not touch + * the reference counts of those objects on the wrong apartment. By using these + * UniquePtr specializations, we may ensure that the reference counts are always + * handled correctly. + */ + +namespace mozilla { +namespace mscom { + +namespace detail { + +template <typename T> +struct MainThreadRelease { + void operator()(T* aPtr) { + if (!aPtr) { + return; + } + if (NS_IsMainThread()) { + aPtr->Release(); + return; + } + DebugOnly<nsresult> rv = SchedulerGroup::Dispatch( + TaskCategory::Other, + NewNonOwningRunnableMethod("mscom::MainThreadRelease", aPtr, + &T::Release)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + } +}; + +template <typename T> +struct MTADelete { + void operator()(T* aPtr) { + if (!aPtr) { + return; + } + + EnsureMTA::AsyncOperation([aPtr]() -> void { delete aPtr; }); + } +}; + +template <typename T> +struct MTARelease { + void operator()(T* aPtr) { + if (!aPtr) { + return; + } + + // Static analysis doesn't recognize that, even though aPtr escapes the + // current scope, we are in effect moving our strong ref into the lambda. + void* ptr = aPtr; + EnsureMTA::AsyncOperation( + [ptr]() -> void { reinterpret_cast<T*>(ptr)->Release(); }); + } +}; + +template <typename T> +struct MTAReleaseInChildProcess { + void operator()(T* aPtr) { + if (!aPtr) { + return; + } + + if (XRE_IsParentProcess()) { + MOZ_ASSERT(NS_IsMainThread()); + aPtr->Release(); + return; + } + + // Static analysis doesn't recognize that, even though aPtr escapes the + // current scope, we are in effect moving our strong ref into the lambda. + void* ptr = aPtr; + EnsureMTA::AsyncOperation( + [ptr]() -> void { reinterpret_cast<T*>(ptr)->Release(); }); + } +}; + +struct InterceptorTargetDeleter { + void operator()(IUnknown* aPtr) { + // We intentionally do not touch the refcounts of interceptor targets! + } +}; + +struct PreservedStreamDeleter { + void operator()(IStream* aPtr) { + if (!aPtr) { + return; + } + + // Static analysis doesn't recognize that, even though aPtr escapes the + // current scope, we are in effect moving our strong ref into the lambda. + void* ptr = aPtr; + auto cleanup = [ptr]() -> void { + DebugOnly<HRESULT> hr = + ::CoReleaseMarshalData(reinterpret_cast<LPSTREAM>(ptr)); + MOZ_ASSERT(SUCCEEDED(hr)); + reinterpret_cast<LPSTREAM>(ptr)->Release(); + }; + + if (XRE_IsParentProcess()) { + MOZ_ASSERT(NS_IsMainThread()); + cleanup(); + return; + } + + EnsureMTA::AsyncOperation(cleanup); + } +}; + +} // namespace detail + +template <typename T> +using STAUniquePtr = mozilla::UniquePtr<T, detail::MainThreadRelease<T>>; + +template <typename T> +using MTAUniquePtr = mozilla::UniquePtr<T, detail::MTARelease<T>>; + +template <typename T> +using MTADeletePtr = mozilla::UniquePtr<T, detail::MTADelete<T>>; + +template <typename T> +using ProxyUniquePtr = + mozilla::UniquePtr<T, detail::MTAReleaseInChildProcess<T>>; + +template <typename T> +using InterceptorTargetPtr = + mozilla::UniquePtr<T, detail::InterceptorTargetDeleter>; + +using PreservedStreamPtr = + mozilla::UniquePtr<IStream, detail::PreservedStreamDeleter>; + +namespace detail { + +// We don't have direct access to UniquePtr's storage, so we use mPtrStorage +// to receive the pointer and then set the target inside the destructor. +template <typename T, typename Deleter> +class UniquePtrGetterAddRefs { + public: + explicit UniquePtrGetterAddRefs(UniquePtr<T, Deleter>& aSmartPtr) + : mTargetSmartPtr(aSmartPtr), mPtrStorage(nullptr) {} + + ~UniquePtrGetterAddRefs() { mTargetSmartPtr.reset(mPtrStorage); } + + operator void**() { return reinterpret_cast<void**>(&mPtrStorage); } + + operator T**() { return &mPtrStorage; } + + T*& operator*() { return mPtrStorage; } + + private: + UniquePtr<T, Deleter>& mTargetSmartPtr; + T* mPtrStorage; +}; + +} // namespace detail + +template <typename T> +inline STAUniquePtr<T> ToSTAUniquePtr(RefPtr<T>&& aRefPtr) { + return STAUniquePtr<T>(aRefPtr.forget().take()); +} + +template <typename T> +inline STAUniquePtr<T> ToSTAUniquePtr(const RefPtr<T>& aRefPtr) { + MOZ_ASSERT(NS_IsMainThread()); + return STAUniquePtr<T>(do_AddRef(aRefPtr).take()); +} + +template <typename T> +inline STAUniquePtr<T> ToSTAUniquePtr(T* aRawPtr) { + MOZ_ASSERT(NS_IsMainThread()); + if (aRawPtr) { + aRawPtr->AddRef(); + } + return STAUniquePtr<T>(aRawPtr); +} + +template <typename T, typename U> +inline STAUniquePtr<T> ToSTAUniquePtr(const InterceptorTargetPtr<U>& aTarget) { + MOZ_ASSERT(NS_IsMainThread()); + RefPtr<T> newRef(static_cast<T*>(aTarget.get())); + return ToSTAUniquePtr(std::move(newRef)); +} + +template <typename T> +inline MTAUniquePtr<T> ToMTAUniquePtr(RefPtr<T>&& aRefPtr) { + return MTAUniquePtr<T>(aRefPtr.forget().take()); +} + +template <typename T> +inline MTAUniquePtr<T> ToMTAUniquePtr(const RefPtr<T>& aRefPtr) { + MOZ_ASSERT(IsCurrentThreadMTA()); + return MTAUniquePtr<T>(do_AddRef(aRefPtr).take()); +} + +template <typename T> +inline MTAUniquePtr<T> ToMTAUniquePtr(T* aRawPtr) { + MOZ_ASSERT(IsCurrentThreadMTA()); + if (aRawPtr) { + aRawPtr->AddRef(); + } + return MTAUniquePtr<T>(aRawPtr); +} + +template <typename T> +inline ProxyUniquePtr<T> ToProxyUniquePtr(RefPtr<T>&& aRefPtr) { + return ProxyUniquePtr<T>(aRefPtr.forget().take()); +} + +template <typename T> +inline ProxyUniquePtr<T> ToProxyUniquePtr(const RefPtr<T>& aRefPtr) { + MOZ_ASSERT(IsProxy(aRefPtr)); + MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) || + (XRE_IsContentProcess() && IsCurrentThreadMTA())); + + return ProxyUniquePtr<T>(do_AddRef(aRefPtr).take()); +} + +template <typename T> +inline ProxyUniquePtr<T> ToProxyUniquePtr(T* aRawPtr) { + MOZ_ASSERT(IsProxy(aRawPtr)); + MOZ_ASSERT((XRE_IsParentProcess() && NS_IsMainThread()) || + (XRE_IsContentProcess() && IsCurrentThreadMTA())); + + if (aRawPtr) { + aRawPtr->AddRef(); + } + return ProxyUniquePtr<T>(aRawPtr); +} + +template <typename T, typename Deleter> +inline InterceptorTargetPtr<T> ToInterceptorTargetPtr( + const UniquePtr<T, Deleter>& aTargetPtr) { + return InterceptorTargetPtr<T>(aTargetPtr.get()); +} + +inline PreservedStreamPtr ToPreservedStreamPtr(RefPtr<IStream>&& aStream) { + return PreservedStreamPtr(aStream.forget().take()); +} + +inline PreservedStreamPtr ToPreservedStreamPtr( + already_AddRefed<IStream>& aStream) { + return PreservedStreamPtr(aStream.take()); +} + +template <typename T, typename Deleter> +inline detail::UniquePtrGetterAddRefs<T, Deleter> getter_AddRefs( + UniquePtr<T, Deleter>& aSmartPtr) { + return detail::UniquePtrGetterAddRefs<T, Deleter>(aSmartPtr); +} + +} // namespace mscom +} // namespace mozilla + +// This block makes it possible for these smart pointers to be correctly +// applied in NewRunnableMethod and friends +namespace detail { + +template <typename T> +struct SmartPointerStorageClass<mozilla::mscom::STAUniquePtr<T>> { + typedef StoreCopyPassByRRef<mozilla::mscom::STAUniquePtr<T>> Type; +}; + +template <typename T> +struct SmartPointerStorageClass<mozilla::mscom::MTAUniquePtr<T>> { + typedef StoreCopyPassByRRef<mozilla::mscom::MTAUniquePtr<T>> Type; +}; + +template <typename T> +struct SmartPointerStorageClass<mozilla::mscom::ProxyUniquePtr<T>> { + typedef StoreCopyPassByRRef<mozilla::mscom::ProxyUniquePtr<T>> Type; +}; + +template <typename T> +struct SmartPointerStorageClass<mozilla::mscom::InterceptorTargetPtr<T>> { + typedef StoreCopyPassByRRef<mozilla::mscom::InterceptorTargetPtr<T>> Type; +}; + +template <> +struct SmartPointerStorageClass<mozilla::mscom::PreservedStreamPtr> { + typedef StoreCopyPassByRRef<mozilla::mscom::PreservedStreamPtr> Type; +}; + +} // namespace detail + +#endif // mozilla_mscom_Ptr_h |