/work/obj-fuzz/dist/include/mozilla/ipc/Shmem.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef mozilla_ipc_Shmem_h |
8 | | #define mozilla_ipc_Shmem_h |
9 | | |
10 | | #include "mozilla/Attributes.h" |
11 | | |
12 | | #include "base/basictypes.h" |
13 | | #include "base/process.h" |
14 | | |
15 | | #include "nscore.h" |
16 | | #include "nsDebug.h" |
17 | | |
18 | | #include "ipc/IPCMessageUtils.h" |
19 | | #include "mozilla/ipc/SharedMemory.h" |
20 | | #include "mozilla/ipc/IPDLParamTraits.h" |
21 | | |
22 | | /** |
23 | | * |Shmem| is one agent in the IPDL shared memory scheme. The way it |
24 | | works is essentially |
25 | | * |
26 | | * (1) C++ code calls, say, |parentActor->AllocShmem(size)| |
27 | | |
28 | | * (2) IPDL-generated code creates a |mozilla::ipc::SharedMemory| |
29 | | * wrapping the bare OS shmem primitives. The code then adds the new |
30 | | * SharedMemory to the set of shmem segments being managed by IPDL. |
31 | | * |
32 | | * (3) IPDL-generated code "shares" the new SharedMemory to the child |
33 | | * process, and then sends a special asynchronous IPC message to the |
34 | | * child notifying it of the creation of the segment. (What this |
35 | | * means is OS specific.) |
36 | | * |
37 | | * (4a) The child receives the special IPC message, and using the |
38 | | * |SharedMemory{Basic}::Handle| it was passed, creates a |
39 | | * |mozilla::ipc::SharedMemory| in the child |
40 | | * process. |
41 | | * |
42 | | * (4b) After sending the "shmem-created" IPC message, IPDL-generated |
43 | | * code in the parent returns a |mozilla::ipc::Shmem| back to the C++ |
44 | | * caller of |parentActor->AllocShmem()|. The |Shmem| is a "weak |
45 | | * reference" to the underlying |SharedMemory|, which is managed by |
46 | | * IPDL-generated code. C++ consumers of |Shmem| can't get at the |
47 | | * underlying |SharedMemory|. |
48 | | * |
49 | | * If parent code wants to give access rights to the Shmem to the |
50 | | * child, it does so by sending its |Shmem| to the child, in an IPDL |
51 | | * message. The parent's |Shmem| then "dies", i.e. becomes |
52 | | * inaccessible. This process could be compared to passing a |
53 | | * "shmem-access baton" between parent and child. |
54 | | */ |
55 | | |
56 | | namespace mozilla { |
57 | | namespace layers { |
58 | | class ShadowLayerForwarder; |
59 | | } // namespace layers |
60 | | |
61 | | namespace ipc { |
62 | | |
63 | | class Shmem final |
64 | | { |
65 | | friend struct IPDLParamTraits<mozilla::ipc::Shmem>; |
66 | | #ifdef DEBUG |
67 | | // For ShadowLayerForwarder::CheckSurfaceDescriptor |
68 | | friend class mozilla::layers::ShadowLayerForwarder; |
69 | | #endif |
70 | | |
71 | | public: |
72 | | typedef int32_t id_t; |
73 | | // Low-level wrapper around platform shmem primitives. |
74 | | typedef mozilla::ipc::SharedMemory SharedMemory; |
75 | | typedef SharedMemory::SharedMemoryType SharedMemoryType; |
76 | | // Shmem objects should only be constructed directly from SharedMemory |
77 | | // objects by the Shmem implementation itself, or by a select few functions |
78 | | // in ProtocolUtils.{h,cpp}. You should not need to add new instances of |
79 | | // this token. |
80 | | struct PrivateIPDLCaller {}; |
81 | | |
82 | | Shmem() : |
83 | | mSegment(nullptr), |
84 | | mData(nullptr), |
85 | | mSize(0), |
86 | | mId(0) |
87 | 0 | { |
88 | 0 | } |
89 | | |
90 | | Shmem(const Shmem& aOther) : |
91 | | mSegment(aOther.mSegment), |
92 | | mData(aOther.mData), |
93 | | mSize(aOther.mSize), |
94 | | mId(aOther.mId) |
95 | 0 | { |
96 | 0 | } |
97 | | |
98 | | #if !defined(DEBUG) |
99 | | Shmem(PrivateIPDLCaller, |
100 | | SharedMemory* aSegment, id_t aId) : |
101 | | mSegment(aSegment), |
102 | | mData(aSegment->memory()), |
103 | | mSize(0), |
104 | | mId(aId) |
105 | | { |
106 | | mSize = static_cast<size_t>(*PtrToSize(mSegment)); |
107 | | } |
108 | | #else |
109 | | Shmem(PrivateIPDLCaller, |
110 | | SharedMemory* aSegment, id_t aId); |
111 | | #endif |
112 | | |
113 | | ~Shmem() |
114 | 0 | { |
115 | 0 | // Shmem only holds a "weak ref" to the actual segment, which is |
116 | 0 | // owned by IPDL. So there's nothing interesting to be done here |
117 | 0 | forget(PrivateIPDLCaller()); |
118 | 0 | } |
119 | | |
120 | | Shmem& operator=(const Shmem& aRhs) |
121 | | { |
122 | | mSegment = aRhs.mSegment; |
123 | | mData = aRhs.mData; |
124 | | mSize = aRhs.mSize; |
125 | | mId = aRhs.mId; |
126 | | return *this; |
127 | | } |
128 | | |
129 | | bool operator==(const Shmem& aRhs) const |
130 | 0 | { |
131 | 0 | return mSegment == aRhs.mSegment; |
132 | 0 | } |
133 | | |
134 | | // Returns whether this Shmem is writable by you, and thus whether you can |
135 | | // transfer writability to another actor. |
136 | | bool |
137 | | IsWritable() const |
138 | 0 | { |
139 | 0 | return mSegment != nullptr; |
140 | 0 | } |
141 | | |
142 | | // Returns whether this Shmem is readable by you, and thus whether you can |
143 | | // transfer readability to another actor. |
144 | | bool |
145 | | IsReadable() const |
146 | 0 | { |
147 | 0 | return mSegment != nullptr; |
148 | 0 | } |
149 | | |
150 | | // Return a pointer to the user-visible data segment. |
151 | | template<typename T> |
152 | | T* |
153 | | get() const |
154 | 0 | { |
155 | 0 | AssertInvariants(); |
156 | 0 | AssertAligned<T>(); |
157 | 0 |
|
158 | 0 | return reinterpret_cast<T*>(mData); |
159 | 0 | } Unexecuted instantiation: unsigned char* mozilla::ipc::Shmem::get<unsigned char>() const Unexecuted instantiation: char* mozilla::ipc::Shmem::get<char>() const Unexecuted instantiation: mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader* mozilla::ipc::Shmem::get<mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader>() const Unexecuted instantiation: mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void>* mozilla::ipc::Shmem::get<mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void> >() const |
160 | | |
161 | | // Return the size of the segment as requested when this shmem |
162 | | // segment was allocated, in units of T. The underlying mapping may |
163 | | // actually be larger because of page alignment and private data, |
164 | | // but this isn't exposed to clients. |
165 | | template<typename T> |
166 | | size_t |
167 | | Size() const |
168 | 0 | { |
169 | 0 | AssertInvariants(); |
170 | 0 | AssertAligned<T>(); |
171 | 0 |
|
172 | 0 | return mSize / sizeof(T); |
173 | 0 | } Unexecuted instantiation: unsigned long mozilla::ipc::Shmem::Size<unsigned char>() const Unexecuted instantiation: unsigned long mozilla::ipc::Shmem::Size<char>() const |
174 | | |
175 | | // These shouldn't be used directly, use the IPDL interface instead. |
176 | | id_t Id(PrivateIPDLCaller) const { |
177 | | return mId; |
178 | | } |
179 | | |
180 | 0 | SharedMemory* Segment(PrivateIPDLCaller) const { |
181 | 0 | return mSegment; |
182 | 0 | } |
183 | | |
184 | | #ifndef DEBUG |
185 | | void RevokeRights(PrivateIPDLCaller) |
186 | | { |
187 | | } |
188 | | #else |
189 | | void RevokeRights(PrivateIPDLCaller); |
190 | | #endif |
191 | | |
192 | | void forget(PrivateIPDLCaller) |
193 | 0 | { |
194 | 0 | mSegment = nullptr; |
195 | 0 | mData = nullptr; |
196 | 0 | mSize = 0; |
197 | 0 | mId = 0; |
198 | 0 | } |
199 | | |
200 | | static already_AddRefed<Shmem::SharedMemory> |
201 | | Alloc(PrivateIPDLCaller, |
202 | | size_t aNBytes, |
203 | | SharedMemoryType aType, |
204 | | bool aUnsafe, |
205 | | bool aProtect=false); |
206 | | |
207 | | // Prepare this to be shared with |aProcess|. Return an IPC message |
208 | | // that contains enough information for the other process to map |
209 | | // this segment in OpenExisting() below. Return a new message if |
210 | | // successful (owned by the caller), nullptr if not. |
211 | | IPC::Message* |
212 | | ShareTo(PrivateIPDLCaller, |
213 | | base::ProcessId aTargetPid, |
214 | | int32_t routingId); |
215 | | |
216 | | // Stop sharing this with |aTargetPid|. Return an IPC message that |
217 | | // contains enough information for the other process to unmap this |
218 | | // segment. Return a new message if successful (owned by the |
219 | | // caller), nullptr if not. |
220 | | IPC::Message* |
221 | | UnshareFrom(PrivateIPDLCaller, |
222 | | int32_t routingId); |
223 | | |
224 | | // Return a SharedMemory instance in this process using the |
225 | | // descriptor shared to us by the process that created the |
226 | | // underlying OS shmem resource. The contents of the descriptor |
227 | | // depend on the type of SharedMemory that was passed to us. |
228 | | static already_AddRefed<SharedMemory> |
229 | | OpenExisting(PrivateIPDLCaller, |
230 | | const IPC::Message& aDescriptor, |
231 | | id_t* aId, |
232 | | bool aProtect=false); |
233 | | |
234 | | static void |
235 | | Dealloc(PrivateIPDLCaller, |
236 | | SharedMemory* aSegment); |
237 | | |
238 | | private: |
239 | | template<typename T> |
240 | | void AssertAligned() const |
241 | 0 | { |
242 | 0 | if (0 != (mSize % sizeof(T))) |
243 | 0 | MOZ_CRASH("shmem is not T-aligned"); |
244 | 0 | } Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<unsigned char>() const Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<char>() const Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<mozilla::layers::FixedSizeSmallShmemSectionAllocator::ShmemSectionHeapHeader>() const Unexecuted instantiation: void mozilla::ipc::Shmem::AssertAligned<mozilla::Atomic<int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void> >() const |
245 | | |
246 | | #if !defined(DEBUG) |
247 | | void AssertInvariants() const |
248 | 0 | { } |
249 | | |
250 | | static uint32_t* |
251 | | PtrToSize(SharedMemory* aSegment) |
252 | | { |
253 | | char* endOfSegment = |
254 | | reinterpret_cast<char*>(aSegment->memory()) + aSegment->Size(); |
255 | | return reinterpret_cast<uint32_t*>(endOfSegment - sizeof(uint32_t)); |
256 | | } |
257 | | |
258 | | #else |
259 | | void AssertInvariants() const; |
260 | | #endif |
261 | | |
262 | | RefPtr<SharedMemory> mSegment; |
263 | | void* mData; |
264 | | size_t mSize; |
265 | | id_t mId; |
266 | | }; |
267 | | |
268 | | template<> |
269 | | struct IPDLParamTraits<Shmem> |
270 | | { |
271 | | typedef Shmem paramType; |
272 | | |
273 | | static void Write(IPC::Message* aMsg, IProtocol* aActor, paramType& aParam); |
274 | | static bool Read(const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor, paramType* aResult); |
275 | | |
276 | | static void Log(const paramType& aParam, std::wstring* aLog) |
277 | 0 | { |
278 | 0 | aLog->append(L"(shmem segment)"); |
279 | 0 | } |
280 | | }; |
281 | | |
282 | | } // namespace ipc |
283 | | } // namespace mozilla |
284 | | |
285 | | #endif // ifndef mozilla_ipc_Shmem_h |