RefMessageBodyService.cpp (4553B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "RefMessageBodyService.h" 8 9 #include <cstdint> 10 11 #include "mozilla/ErrorResult.h" 12 #include "mozilla/RefPtr.h" 13 #include "mozilla/dom/ipc/StructuredCloneData.h" 14 #include "nsBaseHashtable.h" 15 #include "nsDebug.h" 16 17 namespace mozilla::dom { 18 19 // Guards sService and its members. 20 StaticMutex sRefMessageBodyServiceMutex; 21 22 // Raw pointer because the service is kept alive by other objects. 23 // See the CTOR and the DTOR of this object. 24 RefMessageBodyService* sService; 25 26 // static 27 already_AddRefed<RefMessageBodyService> RefMessageBodyService::GetOrCreate() { 28 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 29 30 RefPtr<RefMessageBodyService> service = GetOrCreateInternal(lock); 31 return service.forget(); 32 } 33 34 // static 35 RefMessageBodyService* RefMessageBodyService::GetOrCreateInternal( 36 const StaticMutexAutoLock& aProofOfLock) { 37 if (!sService) { 38 sService = new RefMessageBodyService(aProofOfLock); 39 } 40 return sService; 41 } 42 43 RefMessageBodyService::RefMessageBodyService( 44 const StaticMutexAutoLock& aProofOfLock) { 45 MOZ_DIAGNOSTIC_ASSERT(sService == nullptr); 46 } 47 48 RefMessageBodyService::~RefMessageBodyService() { 49 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 50 MOZ_DIAGNOSTIC_ASSERT(sService == this); 51 sService = nullptr; 52 } 53 54 const nsID RefMessageBodyService::Register( 55 already_AddRefed<RefMessageBody> aBody, ErrorResult& aRv) { 56 RefPtr<RefMessageBody> body = aBody; 57 MOZ_ASSERT(body); 58 59 nsID uuid = {}; 60 aRv = nsID::GenerateUUIDInPlace(uuid); 61 if (NS_WARN_IF(aRv.Failed())) { 62 return nsID(); 63 } 64 65 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 66 GetOrCreateInternal(lock)->mMessages.InsertOrUpdate(uuid, std::move(body)); 67 return uuid; 68 } 69 70 already_AddRefed<RefMessageBody> RefMessageBodyService::Steal(const nsID& aID) { 71 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 72 if (!sService) { 73 return nullptr; 74 } 75 76 RefPtr<RefMessageBody> body; 77 sService->mMessages.Remove(aID, getter_AddRefs(body)); 78 79 return body.forget(); 80 } 81 82 already_AddRefed<RefMessageBody> RefMessageBodyService::GetAndCount( 83 const nsID& aID) { 84 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 85 if (!sService) { 86 return nullptr; 87 } 88 89 RefPtr<RefMessageBody> body = sService->mMessages.Get(aID); 90 if (!body) { 91 return nullptr; 92 } 93 94 ++body->mCount; 95 96 MOZ_ASSERT_IF(body->mMaxCount.isSome(), 97 body->mCount <= body->mMaxCount.value()); 98 if (body->mMaxCount.isSome() && body->mCount >= body->mMaxCount.value()) { 99 sService->mMessages.Remove(aID); 100 } 101 102 return body.forget(); 103 } 104 105 void RefMessageBodyService::SetMaxCount(const nsID& aID, uint32_t aMaxCount) { 106 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 107 if (!sService) { 108 return; 109 } 110 111 RefPtr<RefMessageBody> body = sService->mMessages.Get(aID); 112 if (!body) { 113 return; 114 } 115 116 MOZ_ASSERT(body->mMaxCount.isNothing()); 117 body->mMaxCount.emplace(aMaxCount); 118 119 MOZ_ASSERT(body->mCount <= body->mMaxCount.value()); 120 if (body->mCount >= body->mMaxCount.value()) { 121 sService->mMessages.Remove(aID); 122 } 123 } 124 125 void RefMessageBodyService::ForgetPort(const nsID& aPortID) { 126 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex); 127 if (!sService) { 128 return; 129 } 130 131 for (auto iter = sService->mMessages.Iter(); !iter.Done(); iter.Next()) { 132 if (iter.UserData()->PortID() == aPortID) { 133 iter.Remove(); 134 } 135 } 136 } 137 138 RefMessageBody::RefMessageBody(const nsID& aPortID, 139 UniquePtr<ipc::StructuredCloneData>&& aCloneData) 140 : mPortID(aPortID), 141 mMutex("RefMessageBody::mMutex"), 142 mCloneData(std::move(aCloneData)), 143 mMaxCount(Nothing()), 144 mCount(0) {} 145 146 RefMessageBody::~RefMessageBody() = default; 147 148 void RefMessageBody::Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue, 149 const JS::CloneDataPolicy& aCloneDataPolicy, 150 ErrorResult& aRv) { 151 MutexAutoLock lock(mMutex); 152 mCloneData->Read(aCx, aValue, aCloneDataPolicy, aRv); 153 } 154 155 bool RefMessageBody::TakeTransferredPortsAsSequence( 156 Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) { 157 MOZ_ASSERT(mMaxCount.isNothing()); 158 return mCloneData->TakeTransferredPortsAsSequence(aPorts); 159 } 160 161 } // namespace mozilla::dom