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 #include "StructuredCloneData.h"
9 #include "nsContentUtils.h"
10
11 namespace mozilla {
12 namespace dom {
13
14 StaticMutex sRefMessageBodyServiceMutex;
15
16 // Raw pointer because the service is kept alive by other objects.
17 // See the CTOR and the DTOR of this object.
18 RefMessageBodyService* sService;
19
20 // static
GetOrCreate()21 already_AddRefed<RefMessageBodyService> RefMessageBodyService::GetOrCreate() {
22 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
23
24 RefPtr<RefMessageBodyService> service = GetOrCreateInternal(lock);
25 return service.forget();
26 }
27
28 // static
GetOrCreateInternal(const StaticMutexAutoLock & aProofOfLock)29 RefMessageBodyService* RefMessageBodyService::GetOrCreateInternal(
30 const StaticMutexAutoLock& aProofOfLock) {
31 if (!sService) {
32 sService = new RefMessageBodyService();
33 }
34 return sService;
35 }
36
RefMessageBodyService()37 RefMessageBodyService::RefMessageBodyService() {
38 MOZ_DIAGNOSTIC_ASSERT(sService == nullptr);
39 }
40
~RefMessageBodyService()41 RefMessageBodyService::~RefMessageBodyService() {
42 MOZ_DIAGNOSTIC_ASSERT(sService == this);
43 sService = nullptr;
44 }
45
Register(already_AddRefed<RefMessageBody> aBody,ErrorResult & aRv)46 const nsID RefMessageBodyService::Register(
47 already_AddRefed<RefMessageBody> aBody, ErrorResult& aRv) {
48 RefPtr<RefMessageBody> body = aBody;
49 MOZ_ASSERT(body);
50
51 nsID uuid = {};
52 aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
53 if (NS_WARN_IF(aRv.Failed())) {
54 return nsID();
55 }
56
57 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
58 GetOrCreateInternal(lock)->mMessages.Put(uuid, std::move(body));
59 return uuid;
60 }
61
Steal(const nsID & aID)62 already_AddRefed<RefMessageBody> RefMessageBodyService::Steal(const nsID& aID) {
63 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
64 if (!sService) {
65 return nullptr;
66 }
67
68 RefPtr<RefMessageBody> body;
69 sService->mMessages.Remove(aID, getter_AddRefs(body));
70
71 return body.forget();
72 }
73
GetAndCount(const nsID & aID)74 already_AddRefed<RefMessageBody> RefMessageBodyService::GetAndCount(
75 const nsID& aID) {
76 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
77 if (!sService) {
78 return nullptr;
79 }
80
81 RefPtr<RefMessageBody> body = sService->mMessages.Get(aID);
82 if (!body) {
83 return nullptr;
84 }
85
86 ++body->mCount;
87
88 MOZ_ASSERT_IF(body->mMaxCount.isSome(),
89 body->mCount <= body->mMaxCount.value());
90 if (body->mMaxCount.isSome() && body->mCount >= body->mMaxCount.value()) {
91 sService->mMessages.Remove(aID);
92 }
93
94 return body.forget();
95 }
96
SetMaxCount(const nsID & aID,uint32_t aMaxCount)97 void RefMessageBodyService::SetMaxCount(const nsID& aID, uint32_t aMaxCount) {
98 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
99 if (!sService) {
100 return;
101 }
102
103 RefPtr<RefMessageBody> body = sService->mMessages.Get(aID);
104 if (!body) {
105 return;
106 }
107
108 MOZ_ASSERT(body->mMaxCount.isNothing());
109 body->mMaxCount.emplace(aMaxCount);
110
111 MOZ_ASSERT(body->mCount <= body->mMaxCount.value());
112 if (body->mCount >= body->mMaxCount.value()) {
113 sService->mMessages.Remove(aID);
114 }
115 }
116
ForgetPort(const nsID & aPortID)117 void RefMessageBodyService::ForgetPort(const nsID& aPortID) {
118 StaticMutexAutoLock lock(sRefMessageBodyServiceMutex);
119 if (!sService) {
120 return;
121 }
122
123 for (auto iter = sService->mMessages.ConstIter(); !iter.Done(); iter.Next()) {
124 if (iter.UserData()->PortID() == aPortID) {
125 iter.Remove();
126 }
127 }
128 }
129
RefMessageBody(const nsID & aPortID,UniquePtr<ipc::StructuredCloneData> && aCloneData)130 RefMessageBody::RefMessageBody(const nsID& aPortID,
131 UniquePtr<ipc::StructuredCloneData>&& aCloneData)
132 : mPortID(aPortID),
133 mMutex("RefMessageBody::mMutex"),
134 mCloneData(std::move(aCloneData)),
135 mMaxCount(Nothing()),
136 mCount(0) {}
137
Read(JSContext * aCx,JS::MutableHandle<JS::Value> aValue,const JS::CloneDataPolicy & aCloneDataPolicy,ErrorResult & aRv)138 void RefMessageBody::Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
139 const JS::CloneDataPolicy& aCloneDataPolicy,
140 ErrorResult& aRv) {
141 MutexAutoLock lock(mMutex);
142 mCloneData->Read(aCx, aValue, aCloneDataPolicy, aRv);
143 }
144
TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>> & aPorts)145 bool RefMessageBody::TakeTransferredPortsAsSequence(
146 Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) {
147 MOZ_ASSERT(mMaxCount.isNothing());
148 return mCloneData->TakeTransferredPortsAsSequence(aPorts);
149 }
150
151 } // namespace dom
152 } // namespace mozilla
153