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/. */
7 #include "RefMessageBodyService.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/dom/ipc/StructuredCloneData.h"
14 #include "nsBaseHashtable.h"
17 namespace mozilla::dom
{
19 // Guards sService and its members.
20 StaticMutex sRefMessageBodyServiceMutex
;
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
;
27 already_AddRefed
<RefMessageBodyService
> RefMessageBodyService::GetOrCreate() {
28 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
30 RefPtr
<RefMessageBodyService
> service
= GetOrCreateInternal(lock
);
31 return service
.forget();
35 RefMessageBodyService
* RefMessageBodyService::GetOrCreateInternal(
36 const StaticMutexAutoLock
& aProofOfLock
) {
38 sService
= new RefMessageBodyService(aProofOfLock
);
43 RefMessageBodyService::RefMessageBodyService(
44 const StaticMutexAutoLock
& aProofOfLock
) {
45 MOZ_DIAGNOSTIC_ASSERT(sService
== nullptr);
48 RefMessageBodyService::~RefMessageBodyService() {
49 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
50 MOZ_DIAGNOSTIC_ASSERT(sService
== this);
54 const nsID
RefMessageBodyService::Register(
55 already_AddRefed
<RefMessageBody
> aBody
, ErrorResult
& aRv
) {
56 RefPtr
<RefMessageBody
> body
= aBody
;
60 aRv
= nsID::GenerateUUIDInPlace(uuid
);
61 if (NS_WARN_IF(aRv
.Failed())) {
65 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
66 GetOrCreateInternal(lock
)->mMessages
.InsertOrUpdate(uuid
, std::move(body
));
70 already_AddRefed
<RefMessageBody
> RefMessageBodyService::Steal(const nsID
& aID
) {
71 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
76 RefPtr
<RefMessageBody
> body
;
77 sService
->mMessages
.Remove(aID
, getter_AddRefs(body
));
82 already_AddRefed
<RefMessageBody
> RefMessageBodyService::GetAndCount(
84 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
89 RefPtr
<RefMessageBody
> body
= sService
->mMessages
.Get(aID
);
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
);
102 return body
.forget();
105 void RefMessageBodyService::SetMaxCount(const nsID
& aID
, uint32_t aMaxCount
) {
106 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
111 RefPtr
<RefMessageBody
> body
= sService
->mMessages
.Get(aID
);
116 MOZ_ASSERT(body
->mMaxCount
.isNothing());
117 body
->mMaxCount
.emplace(aMaxCount
);
119 MOZ_ASSERT(body
->mCount
<= body
->mMaxCount
.value());
120 if (body
->mCount
>= body
->mMaxCount
.value()) {
121 sService
->mMessages
.Remove(aID
);
125 void RefMessageBodyService::ForgetPort(const nsID
& aPortID
) {
126 StaticMutexAutoLock
lock(sRefMessageBodyServiceMutex
);
131 for (auto iter
= sService
->mMessages
.Iter(); !iter
.Done(); iter
.Next()) {
132 if (iter
.UserData()->PortID() == aPortID
) {
138 RefMessageBody::RefMessageBody(const nsID
& aPortID
,
139 UniquePtr
<ipc::StructuredCloneData
>&& aCloneData
)
141 mMutex("RefMessageBody::mMutex"),
142 mCloneData(std::move(aCloneData
)),
143 mMaxCount(Nothing()),
146 RefMessageBody::~RefMessageBody() = default;
148 void RefMessageBody::Read(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aValue
,
149 const JS::CloneDataPolicy
& aCloneDataPolicy
,
151 MutexAutoLock
lock(mMutex
);
152 mCloneData
->Read(aCx
, aValue
, aCloneDataPolicy
, aRv
);
155 bool RefMessageBody::TakeTransferredPortsAsSequence(
156 Sequence
<OwningNonNull
<mozilla::dom::MessagePort
>>& aPorts
) {
157 MOZ_ASSERT(mMaxCount
.isNothing());
158 return mCloneData
->TakeTransferredPortsAsSequence(aPorts
);
161 } // namespace mozilla::dom