1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "GMPSharedMemManager.h"
7 #include "GMPMessageUtils.h"
8 #include "mozilla/ipc/SharedMemory.h"
9 #include "mozilla/StaticPtr.h"
10 #include "mozilla/ClearOnShutdown.h"
11 
12 namespace mozilla::gmp {
13 
14 // Really one set of pools on each side of the plugin API.
15 
16 // YUV buffers go from Encoder parent to child; pool there, and then return
17 // with Decoded() frames to the Decoder parent and goes into the parent pool.
18 // Compressed (encoded) data goes from the Decoder parent to the child;
19 // pool there, and then return with Encoded() frames and goes into the parent
20 // pool.
MgrAllocShmem(GMPSharedMem::GMPMemoryClasses aClass,size_t aSize,ipc::Shmem::SharedMemory::SharedMemoryType aType,ipc::Shmem * aMem)21 bool GMPSharedMemManager::MgrAllocShmem(
22     GMPSharedMem::GMPMemoryClasses aClass, size_t aSize,
23     ipc::Shmem::SharedMemory::SharedMemoryType aType, ipc::Shmem* aMem) {
24   mData->CheckThread();
25 
26   // first look to see if we have a free buffer large enough
27   for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
28     MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
29     if (aSize <= GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
30       *aMem = GetGmpFreelist(aClass)[i];
31       GetGmpFreelist(aClass).RemoveElementAt(i);
32       return true;
33     }
34   }
35 
36   // Didn't find a buffer free with enough space; allocate one
37   size_t pagesize = ipc::SharedMemory::SystemPageSize();
38   aSize = (aSize + (pagesize - 1)) & ~(pagesize - 1);  // round up to page size
39   bool retval = Alloc(aSize, aType, aMem);
40   if (retval) {
41     // The allocator (or NeedsShmem call) should never return less than we ask
42     // for...
43     MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
44     mData->mGmpAllocated[aClass]++;
45   }
46   return retval;
47 }
48 
MgrDeallocShmem(GMPSharedMem::GMPMemoryClasses aClass,ipc::Shmem & aMem)49 bool GMPSharedMemManager::MgrDeallocShmem(GMPSharedMem::GMPMemoryClasses aClass,
50                                           ipc::Shmem& aMem) {
51   mData->CheckThread();
52 
53   size_t size = aMem.Size<uint8_t>();
54 
55   // XXX Bug NNNNNNN Until we put better guards on ipc::shmem, verify we
56   // weren't fed an shmem we already had.
57   for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
58     if (NS_WARN_IF(aMem == GetGmpFreelist(aClass)[i])) {
59       // Safest to crash in this case; should never happen in normal
60       // operation.
61       MOZ_CRASH("Deallocating Shmem we already have in our cache!");
62       // return true;
63     }
64   }
65 
66   // XXX This works; there are better pool algorithms.  We need to avoid
67   // "falling off a cliff" with too low a number
68   if (GetGmpFreelist(aClass).Length() > 10) {
69     Dealloc(std::move(GetGmpFreelist(aClass)[0]));
70     GetGmpFreelist(aClass).RemoveElementAt(0);
71     // The allocation numbers will be fubar on the Child!
72     mData->mGmpAllocated[aClass]--;
73   }
74   for (uint32_t i = 0; i < GetGmpFreelist(aClass).Length(); i++) {
75     MOZ_ASSERT(GetGmpFreelist(aClass)[i].IsWritable());
76     if (size < GetGmpFreelist(aClass)[i].Size<uint8_t>()) {
77       GetGmpFreelist(aClass).InsertElementAt(i, aMem);
78       return true;
79     }
80   }
81   GetGmpFreelist(aClass).AppendElement(aMem);
82 
83   return true;
84 }
85 
NumInUse(GMPSharedMem::GMPMemoryClasses aClass)86 uint32_t GMPSharedMemManager::NumInUse(GMPSharedMem::GMPMemoryClasses aClass) {
87   return mData->mGmpAllocated[aClass] - GetGmpFreelist(aClass).Length();
88 }
89 
90 }  // namespace mozilla::gmp
91