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/. */
9 #include "ProtocolUtils.h"
10 #include "SharedMemoryBasic.h"
11 #include "ShmemMessageUtils.h"
12 #include "chrome/common/ipc_message_utils.h"
13 #include "mozilla/Unused.h"
18 class ShmemCreated
: public IPC::Message
{
20 typedef Shmem::id_t id_t
;
23 ShmemCreated(int32_t routingId
, id_t aIPDLId
, size_t aSize
)
25 routingId
, SHMEM_CREATED_MESSAGE_TYPE
, 0,
26 HeaderFlags(NESTED_INSIDE_CPOW
, CONTROL_PRIORITY
, COMPRESSION_NONE
,
27 LAZY_SEND
, NOT_CONSTRUCTOR
, ASYNC
, NOT_REPLY
)) {
28 MOZ_RELEASE_ASSERT(aSize
< std::numeric_limits
<uint32_t>::max(),
29 "Tried to create Shmem with size larger than 4GB");
30 IPC::MessageWriter
writer(*this);
31 IPC::WriteParam(&writer
, aIPDLId
);
32 IPC::WriteParam(&writer
, uint32_t(aSize
));
35 static bool ReadInfo(IPC::MessageReader
* aReader
, id_t
* aIPDLId
,
38 if (!IPC::ReadParam(aReader
, aIPDLId
) || !IPC::ReadParam(aReader
, &size
)) {
45 void Log(const std::string
& aPrefix
, FILE* aOutf
) const {
46 fputs("(special ShmemCreated msg)", aOutf
);
50 class ShmemDestroyed
: public IPC::Message
{
52 typedef Shmem::id_t id_t
;
55 ShmemDestroyed(int32_t routingId
, id_t aIPDLId
)
57 routingId
, SHMEM_DESTROYED_MESSAGE_TYPE
, 0,
58 HeaderFlags(NOT_NESTED
, NORMAL_PRIORITY
, COMPRESSION_NONE
,
59 LAZY_SEND
, NOT_CONSTRUCTOR
, ASYNC
, NOT_REPLY
)) {
60 IPC::MessageWriter
writer(*this);
61 IPC::WriteParam(&writer
, aIPDLId
);
65 static already_AddRefed
<SharedMemory
> NewSegment() {
66 return MakeAndAddRef
<SharedMemoryBasic
>();
69 static already_AddRefed
<SharedMemory
> CreateSegment(size_t aNBytes
) {
73 RefPtr
<SharedMemory
> segment
= NewSegment();
77 size_t size
= SharedMemory::PageAlignedSize(aNBytes
);
78 if (!segment
->Create(size
) || !segment
->Map(size
)) {
81 return segment
.forget();
84 static already_AddRefed
<SharedMemory
> ReadSegment(
85 const IPC::Message
& aDescriptor
, Shmem::id_t
* aId
, size_t* aNBytes
) {
86 if (SHMEM_CREATED_MESSAGE_TYPE
!= aDescriptor
.type()) {
87 NS_ERROR("expected 'shmem created' message");
90 IPC::MessageReader
reader(aDescriptor
);
91 if (!ShmemCreated::ReadInfo(&reader
, aId
, aNBytes
)) {
94 RefPtr
<SharedMemory
> segment
= NewSegment();
98 if (!segment
->ReadHandle(&reader
)) {
99 NS_ERROR("trying to open invalid handle");
106 size_t size
= SharedMemory::PageAlignedSize(*aNBytes
);
107 if (!segment
->Map(size
)) {
110 // close the handle to the segment after it is mapped
111 segment
->CloseHandle();
112 return segment
.forget();
117 static void Protect(SharedMemory
* aSegment
) {
118 MOZ_ASSERT(aSegment
, "null segment");
119 aSegment
->Protect(reinterpret_cast<char*>(aSegment
->memory()),
120 aSegment
->Size(), RightsNone
);
123 static void Unprotect(SharedMemory
* aSegment
) {
124 MOZ_ASSERT(aSegment
, "null segment");
125 aSegment
->Protect(reinterpret_cast<char*>(aSegment
->memory()),
126 aSegment
->Size(), RightsRead
| RightsWrite
);
129 void Shmem::AssertInvariants() const {
130 MOZ_ASSERT(mSegment
, "null segment");
131 MOZ_ASSERT(mData
, "null data pointer");
132 MOZ_ASSERT(mSize
> 0, "invalid size");
133 // if the segment isn't owned by the current process, these will
135 char checkMappingFront
= *reinterpret_cast<char*>(mData
);
136 char checkMappingBack
= *(reinterpret_cast<char*>(mData
) + mSize
- 1);
138 // avoid "unused" warnings for these variables:
139 Unused
<< checkMappingFront
;
140 Unused
<< checkMappingBack
;
143 void Shmem::RevokeRights() {
146 // When sending a non-unsafe shmem, remove read/write rights from the local
147 // mapping of the segment.
153 #endif // if defined(DEBUG)
155 Shmem::Shmem(SharedMemory
* aSegment
, id_t aId
, size_t aSize
, bool aUnsafe
)
156 : mSegment(aSegment
), mData(aSegment
->memory()), mSize(aSize
), mId(aId
) {
162 MOZ_RELEASE_ASSERT(mSegment
->Size() >= mSize
,
163 "illegal size in shared memory segment");
167 already_AddRefed
<Shmem::SharedMemory
> Shmem::Alloc(size_t aNBytes
) {
168 RefPtr
<SharedMemory
> segment
= CreateSegment(aNBytes
);
173 return segment
.forget();
177 already_AddRefed
<Shmem::SharedMemory
> Shmem::OpenExisting(
178 const IPC::Message
& aDescriptor
, id_t
* aId
, bool /*unused*/) {
180 RefPtr
<SharedMemory
> segment
= ReadSegment(aDescriptor
, aId
, &size
);
185 return segment
.forget();
188 UniquePtr
<IPC::Message
> Shmem::MkCreatedMessage(int32_t routingId
) {
191 auto msg
= MakeUnique
<ShmemCreated
>(routingId
, mId
, mSize
);
192 IPC::MessageWriter
writer(*msg
);
193 if (!mSegment
->WriteHandle(&writer
)) {
196 // close the handle to the segment after it is shared
197 mSegment
->CloseHandle();
201 UniquePtr
<IPC::Message
> Shmem::MkDestroyedMessage(int32_t routingId
) {
203 return MakeUnique
<ShmemDestroyed
>(routingId
, mId
);
206 void IPDLParamTraits
<Shmem
>::Write(IPC::MessageWriter
* aWriter
,
207 IProtocol
* aActor
, Shmem
&& aParam
) {
208 WriteIPDLParam(aWriter
, aActor
, aParam
.mId
);
209 WriteIPDLParam(aWriter
, aActor
, uint32_t(aParam
.mSize
));
211 WriteIPDLParam(aWriter
, aActor
, aParam
.mUnsafe
);
214 aParam
.RevokeRights();
218 bool IPDLParamTraits
<Shmem
>::Read(IPC::MessageReader
* aReader
,
219 IProtocol
* aActor
, paramType
* aResult
) {
222 if (!ReadIPDLParam(aReader
, aActor
, &id
) ||
223 !ReadIPDLParam(aReader
, aActor
, &size
)) {
229 if (!ReadIPDLParam(aReader
, aActor
, &unsafe
)) {
234 Shmem::SharedMemory
* rawmem
= aActor
->LookupSharedMemory(id
);
236 if (size
> rawmem
->Size()) {
240 *aResult
= Shmem(rawmem
, id
, size
, unsafe
);
248 } // namespace mozilla