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