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