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 "RefCountedShmem.h"
8 
9 #include "mozilla/Atomics.h"
10 #include "mozilla/ipc/ProtocolUtils.h"
11 #include "mozilla/layers/WebRenderMessages.h"
12 
13 #define SHM_REFCOUNT_HEADER_SIZE 16
14 
15 namespace mozilla {
16 namespace layers {
17 
GetBytes(const RefCountedShmem & aShm)18 uint8_t* RefCountedShm::GetBytes(const RefCountedShmem& aShm) {
19   uint8_t* data = aShm.buffer().get<uint8_t>();
20   if (!data) {
21     return nullptr;
22   }
23   return data + SHM_REFCOUNT_HEADER_SIZE;
24 }
25 
GetSize(const RefCountedShmem & aShm)26 size_t RefCountedShm::GetSize(const RefCountedShmem& aShm) {
27   if (!IsValid(aShm)) {
28     return 0;
29   }
30   size_t totalSize = aShm.buffer().Size<uint8_t>();
31   if (totalSize < SHM_REFCOUNT_HEADER_SIZE) {
32     return 0;
33   }
34 
35   return totalSize - SHM_REFCOUNT_HEADER_SIZE;
36 }
37 
IsValid(const RefCountedShmem & aShm)38 bool RefCountedShm::IsValid(const RefCountedShmem& aShm) {
39   return aShm.buffer().IsWritable() &&
40          aShm.buffer().Size<uint8_t>() > SHM_REFCOUNT_HEADER_SIZE;
41 }
42 
GetReferenceCount(const RefCountedShmem & aShm)43 int32_t RefCountedShm::GetReferenceCount(const RefCountedShmem& aShm) {
44   if (!IsValid(aShm)) {
45     return 0;
46   }
47 
48   return *aShm.buffer().get<Atomic<int32_t>>();
49 }
50 
AddRef(const RefCountedShmem & aShm)51 int32_t RefCountedShm::AddRef(const RefCountedShmem& aShm) {
52   if (!IsValid(aShm)) {
53     return 0;
54   }
55 
56   auto* counter = aShm.buffer().get<Atomic<int32_t>>();
57   if (counter) {
58     return (*counter)++;
59   }
60   return 0;
61 }
62 
Release(const RefCountedShmem & aShm)63 int32_t RefCountedShm::Release(const RefCountedShmem& aShm) {
64   if (!IsValid(aShm)) {
65     return 0;
66   }
67 
68   auto* counter = aShm.buffer().get<Atomic<int32_t>>();
69   if (counter) {
70     return --(*counter);
71   }
72 
73   return 0;
74 }
75 
Alloc(mozilla::ipc::IProtocol * aAllocator,size_t aSize,RefCountedShmem & aShm)76 bool RefCountedShm::Alloc(mozilla::ipc::IProtocol* aAllocator, size_t aSize,
77                           RefCountedShmem& aShm) {
78   MOZ_ASSERT(!IsValid(aShm));
79   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
80   auto size = aSize + SHM_REFCOUNT_HEADER_SIZE;
81   if (!aAllocator->AllocUnsafeShmem(size, shmType, &aShm.buffer())) {
82     return false;
83   }
84   return true;
85 }
86 
Dealloc(mozilla::ipc::IProtocol * aAllocator,RefCountedShmem & aShm)87 void RefCountedShm::Dealloc(mozilla::ipc::IProtocol* aAllocator,
88                             RefCountedShmem& aShm) {
89   aAllocator->DeallocShmem(aShm.buffer());
90   aShm.buffer() = ipc::Shmem();
91 }
92 
93 }  // namespace layers
94 }  // namespace mozilla
95