|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * vim: sw=2 ts=8 et : |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "Shmem.h" |
|
9 |
|
10 #include "ProtocolUtils.h" |
|
11 #include "SharedMemoryBasic.h" |
|
12 #include "SharedMemorySysV.h" |
|
13 |
|
14 #include "nsAutoPtr.h" |
|
15 #include "mozilla/unused.h" |
|
16 |
|
17 |
|
18 namespace mozilla { |
|
19 namespace ipc { |
|
20 |
|
21 class ShmemCreated : public IPC::Message |
|
22 { |
|
23 private: |
|
24 typedef Shmem::id_t id_t; |
|
25 |
|
26 public: |
|
27 ShmemCreated(int32_t routingId, |
|
28 const id_t& aIPDLId, |
|
29 const size_t& aSize, |
|
30 const SharedMemoryBasic::Handle& aHandle) : |
|
31 IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL) |
|
32 { |
|
33 IPC::WriteParam(this, aIPDLId); |
|
34 IPC::WriteParam(this, aSize); |
|
35 IPC::WriteParam(this, int32_t(SharedMemory::TYPE_BASIC)), |
|
36 IPC::WriteParam(this, aHandle); |
|
37 } |
|
38 |
|
39 // Instead of a single Read() function, we have ReadInfo() and |
|
40 // ReadHandle(). The reason is that the handle type is specific to |
|
41 // the shmem type. These functions should only be called in the |
|
42 // order ReadInfo(); ReadHandle();, and only once each. |
|
43 |
|
44 static bool |
|
45 ReadInfo(const Message* msg, void** iter, |
|
46 id_t* aIPDLId, |
|
47 size_t* aSize, |
|
48 SharedMemory::SharedMemoryType* aType) |
|
49 { |
|
50 if (!IPC::ReadParam(msg, iter, aIPDLId) || |
|
51 !IPC::ReadParam(msg, iter, aSize) || |
|
52 !IPC::ReadParam(msg, iter, reinterpret_cast<int32_t*>(aType))) |
|
53 return false; |
|
54 return true; |
|
55 } |
|
56 |
|
57 static bool |
|
58 ReadHandle(const Message* msg, void** iter, |
|
59 SharedMemoryBasic::Handle* aHandle) |
|
60 { |
|
61 if (!IPC::ReadParam(msg, iter, aHandle)) |
|
62 return false; |
|
63 msg->EndRead(*iter); |
|
64 return true; |
|
65 } |
|
66 |
|
67 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
68 ShmemCreated(int32_t routingId, |
|
69 const id_t& aIPDLId, |
|
70 const size_t& aSize, |
|
71 const SharedMemorySysV::Handle& aHandle) : |
|
72 IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL) |
|
73 { |
|
74 IPC::WriteParam(this, aIPDLId); |
|
75 IPC::WriteParam(this, aSize); |
|
76 IPC::WriteParam(this, int32_t(SharedMemory::TYPE_SYSV)), |
|
77 IPC::WriteParam(this, aHandle); |
|
78 } |
|
79 |
|
80 static bool |
|
81 ReadHandle(const Message* msg, void** iter, |
|
82 SharedMemorySysV::Handle* aHandle) |
|
83 { |
|
84 if (!IPC::ReadParam(msg, iter, aHandle)) |
|
85 return false; |
|
86 msg->EndRead(*iter); |
|
87 return true; |
|
88 } |
|
89 #endif |
|
90 |
|
91 void Log(const std::string& aPrefix, |
|
92 FILE* aOutf) const |
|
93 { |
|
94 fputs("(special ShmemCreated msg)", aOutf); |
|
95 } |
|
96 }; |
|
97 |
|
98 class ShmemDestroyed : public IPC::Message |
|
99 { |
|
100 private: |
|
101 typedef Shmem::id_t id_t; |
|
102 |
|
103 public: |
|
104 ShmemDestroyed(int32_t routingId, |
|
105 const id_t& aIPDLId) : |
|
106 IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL) |
|
107 { |
|
108 IPC::WriteParam(this, aIPDLId); |
|
109 } |
|
110 }; |
|
111 |
|
112 |
|
113 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
114 static Shmem::SharedMemory* |
|
115 CreateSegment(size_t aNBytes, SharedMemorySysV::Handle aHandle) |
|
116 { |
|
117 nsAutoPtr<SharedMemory> segment; |
|
118 |
|
119 if (SharedMemorySysV::IsHandleValid(aHandle)) { |
|
120 segment = new SharedMemorySysV(aHandle); |
|
121 } |
|
122 else { |
|
123 segment = new SharedMemorySysV(); |
|
124 |
|
125 if (!segment->Create(aNBytes)) |
|
126 return 0; |
|
127 } |
|
128 if (!segment->Map(aNBytes)) |
|
129 return 0; |
|
130 |
|
131 segment->AddRef(); |
|
132 return segment.forget(); |
|
133 } |
|
134 #endif |
|
135 |
|
136 static Shmem::SharedMemory* |
|
137 CreateSegment(size_t aNBytes, SharedMemoryBasic::Handle aHandle) |
|
138 { |
|
139 nsAutoPtr<SharedMemory> segment; |
|
140 |
|
141 if (SharedMemoryBasic::IsHandleValid(aHandle)) { |
|
142 segment = new SharedMemoryBasic(aHandle); |
|
143 } |
|
144 else { |
|
145 segment = new SharedMemoryBasic(); |
|
146 |
|
147 if (!segment->Create(aNBytes)) |
|
148 return 0; |
|
149 } |
|
150 if (!segment->Map(aNBytes)) |
|
151 return 0; |
|
152 |
|
153 segment->AddRef(); |
|
154 return segment.forget(); |
|
155 } |
|
156 |
|
157 static void |
|
158 DestroySegment(SharedMemory* aSegment) |
|
159 { |
|
160 // the SharedMemory dtor closes and unmaps the actual OS shmem segment |
|
161 if (aSegment) |
|
162 aSegment->Release(); |
|
163 } |
|
164 |
|
165 |
|
166 #if defined(DEBUG) |
|
167 |
|
168 static const char sMagic[] = |
|
169 "This little piggy went to market.\n" |
|
170 "This little piggy stayed at home.\n" |
|
171 "This little piggy has roast beef,\n" |
|
172 "This little piggy had none.\n" |
|
173 "And this little piggy cried \"Wee! Wee! Wee!\" all the way home"; |
|
174 |
|
175 |
|
176 struct Header { |
|
177 // Don't use size_t or bool here because their size depends on the |
|
178 // architecture. |
|
179 uint32_t mSize; |
|
180 uint32_t mUnsafe; |
|
181 char mMagic[sizeof(sMagic)]; |
|
182 }; |
|
183 |
|
184 static void |
|
185 GetSections(Shmem::SharedMemory* aSegment, |
|
186 Header** aHeader, |
|
187 char** aFrontSentinel, |
|
188 char** aData, |
|
189 char** aBackSentinel) |
|
190 { |
|
191 NS_ABORT_IF_FALSE(aSegment && aFrontSentinel && aData && aBackSentinel, |
|
192 "NULL param(s)"); |
|
193 |
|
194 *aFrontSentinel = reinterpret_cast<char*>(aSegment->memory()); |
|
195 NS_ABORT_IF_FALSE(*aFrontSentinel, "NULL memory()"); |
|
196 |
|
197 *aHeader = reinterpret_cast<Header*>(*aFrontSentinel); |
|
198 |
|
199 size_t pageSize = Shmem::SharedMemory::SystemPageSize(); |
|
200 *aData = *aFrontSentinel + pageSize; |
|
201 |
|
202 *aBackSentinel = *aFrontSentinel + aSegment->Size() - pageSize; |
|
203 } |
|
204 |
|
205 static Header* |
|
206 GetHeader(Shmem::SharedMemory* aSegment) |
|
207 { |
|
208 Header* header; |
|
209 char* dontcare; |
|
210 GetSections(aSegment, &header, &dontcare, &dontcare, &dontcare); |
|
211 return header; |
|
212 } |
|
213 |
|
214 static void |
|
215 Protect(SharedMemory* aSegment) |
|
216 { |
|
217 NS_ABORT_IF_FALSE(aSegment, "NULL segment"); |
|
218 aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()), |
|
219 aSegment->Size(), |
|
220 RightsNone); |
|
221 } |
|
222 |
|
223 static void |
|
224 Unprotect(SharedMemory* aSegment) |
|
225 { |
|
226 NS_ABORT_IF_FALSE(aSegment, "NULL segment"); |
|
227 aSegment->Protect(reinterpret_cast<char*>(aSegment->memory()), |
|
228 aSegment->Size(), |
|
229 RightsRead | RightsWrite); |
|
230 } |
|
231 |
|
232 // |
|
233 // In debug builds, we specially allocate shmem segments. The layout |
|
234 // is as follows |
|
235 // |
|
236 // Page 0: "front sentinel" |
|
237 // size of mapping |
|
238 // magic bytes |
|
239 // Page 1 through n-1: |
|
240 // user data |
|
241 // Page n: "back sentinel" |
|
242 // [nothing] |
|
243 // |
|
244 // The mapping can be in one of the following states, wrt to the |
|
245 // current process. |
|
246 // |
|
247 // State "unmapped": all pages are mapped with no access rights. |
|
248 // |
|
249 // State "mapping": all pages are mapped with read/write access. |
|
250 // |
|
251 // State "mapped": the front and back sentinels are mapped with no |
|
252 // access rights, and all the other pages are mapped with |
|
253 // read/write access. |
|
254 // |
|
255 // When a SharedMemory segment is first allocated, it starts out in |
|
256 // the "mapping" state for the process that allocates the segment, and |
|
257 // in the "unmapped" state for the other process. The allocating |
|
258 // process will then create a Shmem, which takes the segment into the |
|
259 // "mapped" state, where it can be accessed by clients. |
|
260 // |
|
261 // When a Shmem is sent to another process in an IPDL message, the |
|
262 // segment transitions into the "unmapped" state for the sending |
|
263 // process, and into the "mapping" state for the receiving process. |
|
264 // The receiving process will then create a Shmem from the underlying |
|
265 // segment, and take the segment into the "mapped" state. |
|
266 // |
|
267 // In the "mapping" state, we use the front sentinel to verify the |
|
268 // integrity of the shmem segment. If valid, it has a size_t |
|
269 // containing the number of bytes the user allocated followed by the |
|
270 // magic bytes above. |
|
271 // |
|
272 // In the "mapped" state, the front and back sentinels have no access |
|
273 // rights. They act as guards against buffer overflows and underflows |
|
274 // in client code; if clients touch a sentinel, they die with SIGSEGV. |
|
275 // |
|
276 // The "unmapped" state is used to enforce single-owner semantics of |
|
277 // the shmem segment. If a process other than the current owner tries |
|
278 // to touch the segment, it dies with SIGSEGV. |
|
279 // |
|
280 |
|
281 Shmem::Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
282 SharedMemory* aSegment, id_t aId) : |
|
283 mSegment(aSegment), |
|
284 mData(0), |
|
285 mSize(0) |
|
286 { |
|
287 NS_ABORT_IF_FALSE(mSegment, "NULL segment"); |
|
288 NS_ABORT_IF_FALSE(aId != 0, "invalid ID"); |
|
289 |
|
290 Unprotect(mSegment); |
|
291 |
|
292 Header* header; |
|
293 char* frontSentinel; |
|
294 char* data; |
|
295 char* backSentinel; |
|
296 GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel); |
|
297 |
|
298 // do a quick validity check to avoid weird-looking crashes in libc |
|
299 char check = *frontSentinel; |
|
300 (void)check; |
|
301 |
|
302 NS_ABORT_IF_FALSE(!strncmp(header->mMagic, sMagic, sizeof(sMagic)), |
|
303 "invalid segment"); |
|
304 mSize = static_cast<size_t>(header->mSize); |
|
305 |
|
306 size_t pageSize = SharedMemory::SystemPageSize(); |
|
307 // transition into the "mapped" state by protecting the front and |
|
308 // back sentinels (which guard against buffer under/overflows) |
|
309 mSegment->Protect(frontSentinel, pageSize, RightsNone); |
|
310 mSegment->Protect(backSentinel, pageSize, RightsNone); |
|
311 |
|
312 // don't set these until we know they're valid |
|
313 mData = data; |
|
314 mId = aId; |
|
315 } |
|
316 |
|
317 void |
|
318 Shmem::AssertInvariants() const |
|
319 { |
|
320 NS_ABORT_IF_FALSE(mSegment, "NULL segment"); |
|
321 NS_ABORT_IF_FALSE(mData, "NULL data pointer"); |
|
322 NS_ABORT_IF_FALSE(mSize > 0, "invalid size"); |
|
323 // if the segment isn't owned by the current process, these will |
|
324 // trigger SIGSEGV |
|
325 char checkMappingFront = *reinterpret_cast<char*>(mData); |
|
326 char checkMappingBack = *(reinterpret_cast<char*>(mData) + mSize - 1); |
|
327 |
|
328 // avoid "unused" warnings for these variables: |
|
329 unused << checkMappingFront; |
|
330 unused << checkMappingBack; |
|
331 } |
|
332 |
|
333 void |
|
334 Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) |
|
335 { |
|
336 AssertInvariants(); |
|
337 |
|
338 size_t pageSize = SharedMemory::SystemPageSize(); |
|
339 Header* header = GetHeader(mSegment); |
|
340 |
|
341 // Open this up for reading temporarily |
|
342 mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsRead); |
|
343 |
|
344 if (!header->mUnsafe) { |
|
345 Protect(mSegment); |
|
346 } else { |
|
347 mSegment->Protect(reinterpret_cast<char*>(header), pageSize, RightsNone); |
|
348 } |
|
349 } |
|
350 |
|
351 // static |
|
352 Shmem::SharedMemory* |
|
353 Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
354 size_t aNBytes, |
|
355 SharedMemoryType aType, |
|
356 bool aUnsafe, |
|
357 bool aProtect) |
|
358 { |
|
359 NS_ASSERTION(aNBytes <= UINT32_MAX, "Will truncate shmem segment size!"); |
|
360 NS_ABORT_IF_FALSE(!aProtect || !aUnsafe, "protect => !unsafe"); |
|
361 |
|
362 size_t pageSize = SharedMemory::SystemPageSize(); |
|
363 SharedMemory* segment = nullptr; |
|
364 // |2*pageSize| is for the front and back sentinel |
|
365 size_t segmentSize = SharedMemory::PageAlignedSize(aNBytes + 2*pageSize); |
|
366 |
|
367 if (aType == SharedMemory::TYPE_BASIC) |
|
368 segment = CreateSegment(segmentSize, SharedMemoryBasic::NULLHandle()); |
|
369 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
370 else if (aType == SharedMemory::TYPE_SYSV) |
|
371 segment = CreateSegment(segmentSize, SharedMemorySysV::NULLHandle()); |
|
372 #endif |
|
373 else { |
|
374 NS_ERROR("unknown shmem type"); |
|
375 return nullptr; |
|
376 } |
|
377 |
|
378 if (!segment) |
|
379 return 0; |
|
380 |
|
381 Header* header; |
|
382 char *frontSentinel; |
|
383 char *data; |
|
384 char *backSentinel; |
|
385 GetSections(segment, &header, &frontSentinel, &data, &backSentinel); |
|
386 |
|
387 // initialize the segment with Shmem-internal information |
|
388 |
|
389 // NB: this can't be a static assert because technically pageSize |
|
390 // isn't known at compile time, event though in practice it's always |
|
391 // going to be 4KiB |
|
392 NS_ABORT_IF_FALSE(sizeof(Header) <= pageSize, |
|
393 "Shmem::Header has gotten too big"); |
|
394 memcpy(header->mMagic, sMagic, sizeof(sMagic)); |
|
395 header->mSize = static_cast<uint32_t>(aNBytes); |
|
396 header->mUnsafe = aUnsafe; |
|
397 |
|
398 if (aProtect) |
|
399 Protect(segment); |
|
400 |
|
401 return segment; |
|
402 } |
|
403 |
|
404 // static |
|
405 Shmem::SharedMemory* |
|
406 Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
407 const IPC::Message& aDescriptor, |
|
408 id_t* aId, |
|
409 bool aProtect) |
|
410 { |
|
411 if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { |
|
412 NS_ERROR("expected 'shmem created' message"); |
|
413 return nullptr; |
|
414 } |
|
415 |
|
416 void* iter = 0; |
|
417 SharedMemory::SharedMemoryType type; |
|
418 size_t size; |
|
419 if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type)) |
|
420 return 0; |
|
421 |
|
422 SharedMemory* segment = 0; |
|
423 size_t pageSize = SharedMemory::SystemPageSize(); |
|
424 // |2*pageSize| is for the front and back sentinels |
|
425 size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize); |
|
426 |
|
427 if (SharedMemory::TYPE_BASIC == type) { |
|
428 SharedMemoryBasic::Handle handle; |
|
429 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) |
|
430 return 0; |
|
431 |
|
432 if (!SharedMemoryBasic::IsHandleValid(handle)) { |
|
433 NS_ERROR("trying to open invalid handle"); |
|
434 return nullptr; |
|
435 } |
|
436 segment = CreateSegment(segmentSize, handle); |
|
437 } |
|
438 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
439 else if (SharedMemory::TYPE_SYSV == type) { |
|
440 SharedMemorySysV::Handle handle; |
|
441 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) |
|
442 return 0; |
|
443 |
|
444 if (!SharedMemorySysV::IsHandleValid(handle)) { |
|
445 NS_ERROR("trying to open invalid handle"); |
|
446 return nullptr; |
|
447 } |
|
448 segment = CreateSegment(segmentSize, handle); |
|
449 } |
|
450 #endif |
|
451 else { |
|
452 NS_ERROR("unknown shmem type"); |
|
453 return nullptr; |
|
454 } |
|
455 |
|
456 if (!segment) |
|
457 return 0; |
|
458 |
|
459 Header* header = GetHeader(segment); |
|
460 |
|
461 if (size != header->mSize) { |
|
462 NS_ERROR("Wrong size for this Shmem!"); |
|
463 delete segment; |
|
464 return nullptr; |
|
465 } |
|
466 |
|
467 // The caller of this function may not know whether the segment is |
|
468 // unsafe or not |
|
469 if (!header->mUnsafe && aProtect) |
|
470 Protect(segment); |
|
471 |
|
472 return segment; |
|
473 } |
|
474 |
|
475 // static |
|
476 void |
|
477 Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
478 SharedMemory* aSegment) |
|
479 { |
|
480 if (!aSegment) |
|
481 return; |
|
482 |
|
483 size_t pageSize = SharedMemory::SystemPageSize(); |
|
484 Header* header; |
|
485 char *frontSentinel; |
|
486 char *data; |
|
487 char *backSentinel; |
|
488 GetSections(aSegment, &header, &frontSentinel, &data, &backSentinel); |
|
489 |
|
490 aSegment->Protect(frontSentinel, pageSize, RightsWrite | RightsRead); |
|
491 memset(header->mMagic, 0, sizeof(sMagic)); |
|
492 header->mSize = 0; |
|
493 header->mUnsafe = false; // make it "safe" so as to catch errors |
|
494 |
|
495 DestroySegment(aSegment); |
|
496 } |
|
497 |
|
498 |
|
499 #else // !defined(DEBUG) |
|
500 |
|
501 // static |
|
502 Shmem::SharedMemory* |
|
503 Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
504 size_t aNBytes, |
|
505 SharedMemoryType aType, |
|
506 bool /*unused*/, |
|
507 bool /*unused*/) |
|
508 { |
|
509 SharedMemory *segment = nullptr; |
|
510 |
|
511 if (aType == SharedMemory::TYPE_BASIC) |
|
512 segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)), |
|
513 SharedMemoryBasic::NULLHandle()); |
|
514 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
515 else if (aType == SharedMemory::TYPE_SYSV) |
|
516 segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)), |
|
517 SharedMemorySysV::NULLHandle()); |
|
518 #endif |
|
519 else { |
|
520 return nullptr; |
|
521 } |
|
522 |
|
523 if (!segment) |
|
524 return 0; |
|
525 |
|
526 *PtrToSize(segment) = static_cast<uint32_t>(aNBytes); |
|
527 |
|
528 return segment; |
|
529 } |
|
530 |
|
531 // static |
|
532 Shmem::SharedMemory* |
|
533 Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
534 const IPC::Message& aDescriptor, |
|
535 id_t* aId, |
|
536 bool /*unused*/) |
|
537 { |
|
538 if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { |
|
539 return nullptr; |
|
540 } |
|
541 |
|
542 SharedMemory::SharedMemoryType type; |
|
543 void* iter = 0; |
|
544 size_t size; |
|
545 if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type)) |
|
546 return 0; |
|
547 |
|
548 SharedMemory* segment = 0; |
|
549 size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32_t)); |
|
550 |
|
551 if (SharedMemory::TYPE_BASIC == type) { |
|
552 SharedMemoryBasic::Handle handle; |
|
553 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) |
|
554 return 0; |
|
555 |
|
556 if (!SharedMemoryBasic::IsHandleValid(handle)) { |
|
557 return nullptr; |
|
558 } |
|
559 |
|
560 segment = CreateSegment(segmentSize, handle); |
|
561 } |
|
562 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
563 else if (SharedMemory::TYPE_SYSV == type) { |
|
564 SharedMemorySysV::Handle handle; |
|
565 if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) |
|
566 return 0; |
|
567 |
|
568 if (!SharedMemorySysV::IsHandleValid(handle)) { |
|
569 return nullptr; |
|
570 } |
|
571 segment = CreateSegment(segmentSize, handle); |
|
572 } |
|
573 #endif |
|
574 else { |
|
575 return nullptr; |
|
576 } |
|
577 |
|
578 if (!segment) |
|
579 return 0; |
|
580 |
|
581 // this is the only validity check done in non-DEBUG builds |
|
582 if (size != static_cast<size_t>(*PtrToSize(segment))) { |
|
583 delete segment; |
|
584 return nullptr; |
|
585 } |
|
586 |
|
587 return segment; |
|
588 } |
|
589 |
|
590 // static |
|
591 void |
|
592 Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
593 SharedMemory* aSegment) |
|
594 { |
|
595 DestroySegment(aSegment); |
|
596 } |
|
597 |
|
598 #endif // if defined(DEBUG) |
|
599 |
|
600 int |
|
601 Shmem::GetSysVID() const |
|
602 { |
|
603 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
604 AssertInvariants(); |
|
605 |
|
606 if (mSegment->Type() != SharedMemory::TYPE_SYSV) { |
|
607 NS_ERROR("Can't call GetSysVID() on a non-SysV Shmem!"); |
|
608 return -1; |
|
609 } |
|
610 |
|
611 SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment); |
|
612 return seg->GetHandle(); |
|
613 #else |
|
614 NS_ERROR("Can't call GetSysVID() with no support for SysV shared memory!"); |
|
615 return -1; // not reached |
|
616 #endif |
|
617 } |
|
618 |
|
619 IPC::Message* |
|
620 Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
621 base::ProcessHandle aProcess, |
|
622 int32_t routingId) |
|
623 { |
|
624 AssertInvariants(); |
|
625 |
|
626 if (SharedMemory::TYPE_BASIC == mSegment->Type()) { |
|
627 SharedMemoryBasic* seg = static_cast<SharedMemoryBasic*>(mSegment); |
|
628 SharedMemoryBasic::Handle handle; |
|
629 if (!seg->ShareToProcess(aProcess, &handle)) |
|
630 return 0; |
|
631 |
|
632 return new ShmemCreated(routingId, mId, mSize, handle); |
|
633 } |
|
634 #ifdef MOZ_HAVE_SHAREDMEMORYSYSV |
|
635 else if (SharedMemory::TYPE_SYSV == mSegment->Type()) { |
|
636 SharedMemorySysV* seg = static_cast<SharedMemorySysV*>(mSegment); |
|
637 return new ShmemCreated(routingId, mId, mSize, seg->GetHandle()); |
|
638 } |
|
639 #endif |
|
640 else { |
|
641 NS_ABORT_IF_FALSE(false, "unknown shmem type (here?!)"); |
|
642 return nullptr; |
|
643 } |
|
644 |
|
645 return 0; |
|
646 } |
|
647 |
|
648 IPC::Message* |
|
649 Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, |
|
650 base::ProcessHandle aProcess, |
|
651 int32_t routingId) |
|
652 { |
|
653 AssertInvariants(); |
|
654 return new ShmemDestroyed(routingId, mId); |
|
655 } |
|
656 |
|
657 } // namespace ipc |
|
658 } // namespace mozilla |