Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et ft=cpp : */
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_ShmemPool_h
8 : #define mozilla_ShmemPool_h
9 :
10 : #include "mozilla/ipc/Shmem.h"
11 : #include "mozilla/Mutex.h"
12 : #include "mozilla/SizePrintfMacros.h"
13 :
14 : #undef LOG
15 : #undef LOG_ENABLED
16 : extern mozilla::LazyLogModule gCamerasParentLog;
17 : #define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
18 : #define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
19 :
20 : namespace mozilla {
21 :
22 : class ShmemPool;
23 :
24 0 : class ShmemBuffer {
25 : public:
26 0 : ShmemBuffer() : mInitialized(false) {}
27 0 : explicit ShmemBuffer(mozilla::ipc::Shmem aShmem) {
28 0 : mInitialized = true;
29 0 : mShmem = aShmem;
30 0 : }
31 :
32 0 : ShmemBuffer(ShmemBuffer&& rhs) {
33 0 : mInitialized = rhs.mInitialized;
34 0 : mShmem = Move(rhs.mShmem);
35 0 : }
36 :
37 0 : ShmemBuffer& operator=(ShmemBuffer&& rhs) {
38 0 : MOZ_ASSERT(&rhs != this, "self-moves are prohibited");
39 0 : mInitialized = rhs.mInitialized;
40 0 : mShmem = Move(rhs.mShmem);
41 0 : return *this;
42 : }
43 :
44 : // No copies allowed
45 : ShmemBuffer(const ShmemBuffer&) = delete;
46 : ShmemBuffer& operator=(const ShmemBuffer&) = delete;
47 :
48 0 : bool Valid() {
49 0 : return mInitialized;
50 : }
51 :
52 0 : uint8_t * GetBytes() {
53 0 : return mShmem.get<uint8_t>();
54 : }
55 :
56 0 : mozilla::ipc::Shmem& Get() {
57 0 : return mShmem;
58 : }
59 :
60 : private:
61 : friend class ShmemPool;
62 :
63 : bool mInitialized;
64 : mozilla::ipc::Shmem mShmem;
65 : };
66 :
67 : class ShmemPool {
68 : public:
69 : explicit ShmemPool(size_t aPoolSize);
70 : ~ShmemPool();
71 : // Get/GetIfAvailable differ in what thread they can run on. GetIfAvailable
72 : // can run anywhere but won't allocate if the right size isn't available.
73 : ShmemBuffer GetIfAvailable(size_t aSize);
74 : void Put(ShmemBuffer&& aShmem);
75 :
76 : // We need to use the allocation/deallocation functions
77 : // of a specific IPC child/parent instance.
78 : template <class T>
79 0 : void Cleanup(T* aInstance)
80 : {
81 0 : MutexAutoLock lock(mMutex);
82 0 : for (size_t i = 0; i < mShmemPool.Length(); i++) {
83 0 : if (mShmemPool[i].mInitialized) {
84 0 : aInstance->DeallocShmem(mShmemPool[i].Get());
85 0 : mShmemPool[i].mInitialized = false;
86 : }
87 : }
88 0 : }
89 :
90 : template <class T>
91 0 : ShmemBuffer Get(T* aInstance, size_t aSize)
92 : {
93 0 : MutexAutoLock lock(mMutex);
94 :
95 : // Pool is empty, don't block caller.
96 0 : if (mPoolFree == 0) {
97 : // This isn't initialized, so will be understood as an error.
98 0 : return ShmemBuffer();
99 : }
100 :
101 0 : ShmemBuffer& res = mShmemPool[mPoolFree - 1];
102 :
103 0 : if (!res.mInitialized) {
104 0 : LOG(("Initializing new Shmem in pool"));
105 0 : if (!aInstance->AllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, &res.mShmem)) {
106 0 : LOG(("Failure allocating new Shmem buffer"));
107 0 : return ShmemBuffer();
108 : }
109 0 : res.mInitialized = true;
110 : }
111 :
112 0 : MOZ_ASSERT(res.mShmem.IsWritable(), "Shmem in Pool is not writable?");
113 :
114 : // Prepare buffer, increase size if needed (we never shrink as we don't
115 : // maintain seperate sized pools and we don't want to keep reallocating)
116 0 : if (res.mShmem.Size<char>() < aSize) {
117 0 : LOG(("Size change/increase in Shmem Pool"));
118 0 : aInstance->DeallocShmem(res.mShmem);
119 0 : res.mInitialized = false;
120 : // this may fail; always check return value
121 0 : if (!aInstance->AllocShmem(aSize, ipc::SharedMemory::TYPE_BASIC, &res.mShmem)) {
122 0 : LOG(("Failure allocating resized Shmem buffer"));
123 0 : return ShmemBuffer();
124 : } else {
125 0 : res.mInitialized = true;
126 : }
127 : }
128 :
129 0 : MOZ_ASSERT(res.mShmem.IsWritable(), "Shmem in Pool is not writable post resize?");
130 :
131 0 : mPoolFree--;
132 : #ifdef DEBUG
133 0 : size_t poolUse = mShmemPool.Length() - mPoolFree;
134 0 : if (poolUse > mMaxPoolUse) {
135 0 : mMaxPoolUse = poolUse;
136 0 : LOG(("Maximum ShmemPool use increased: %" PRIuSIZE " buffers", mMaxPoolUse));
137 : }
138 : #endif
139 0 : return Move(res);
140 : }
141 :
142 : private:
143 : Mutex mMutex;
144 : size_t mPoolFree;
145 : #ifdef DEBUG
146 : size_t mMaxPoolUse;
147 : #endif
148 : nsTArray<ShmemBuffer> mShmemPool;
149 : };
150 :
151 :
152 : } // namespace mozilla
153 :
154 : #endif // mozilla_ShmemPool_h
|