1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef _GTS_NANOAPPS_SHARED_CHUNK_ALLOCATOR_H_
18 #define _GTS_NANOAPPS_SHARED_CHUNK_ALLOCATOR_H_
19 
20 #include <cstddef>
21 #include <cstdint>
22 
23 namespace nanoapp_testing {
24 
25 // Implementation Note: We chose the pattern of having ChunkAllocatorBase to
26 // reduce the code duplication from multiple instances of ChunkAllocator with
27 // different template parameters.
28 // See ChunkAllocator below for usage and API documentation.
29 class ChunkAllocatorBase {
30  protected:
31   ChunkAllocatorBase(size_t allocSize, size_t slotCount, uint8_t *rawMemory);
32 
33   void *alloc(size_t bytes);
34   bool free(void *ptr);
35   bool contains(const void *ptr) const;
36 
MaxSlotCount()37   static constexpr size_t MaxSlotCount() {
38     // Our mAllocatedSlots is treated as a bit array, so we get 8 slots for
39     // each byte it has.
40     return (sizeof(mAllocatedSlots) * 8);
41   }
42 
43  private:
44   const size_t mAllocSize;
45   const size_t mSlotCount;
46   uint8_t *const mRawMemory;
47   uint32_t mAllocatedSlots;
48 
49   bool getSlot(const void *ptr, size_t *slot) const;
50 };
51 
52 /**
53  * This chunk allocator is designed to allow us to easily get chunks of
54  * memory without needing to go through heap allocation.  The idea is to
55  * reduce our dependency on CHRE for some aspects of our tests.
56  *
57  * This allocator is non-reentrant.  It's also inefficient and a bad idea
58  * for shipping code, but useful for reducing dependencies during testing.
59  *
60  * This will allow up to kSlotCount allocations of up to kAllocSize bytes
61  * each, and costs (kSlotCount * kAllocSize) bytes of underlying storage.
62  */
63 template <size_t kAllocSize, size_t kSlotCount>
64 class ChunkAllocator : ChunkAllocatorBase {
65  public:
ChunkAllocator()66   ChunkAllocator()
67       : ChunkAllocatorBase(kAllocSize, kSlotCount, mRawMemoryArray) {}
68 
69   /**
70    * If "bytes" <= kAllocSize, and there are less than kSlotCount allocations,
71    * return a valid pointer.  Otherwise, nullptr.
72    *
73    * Reminder this is non-reentrant.
74    */
alloc(size_t bytes)75   void *alloc(size_t bytes) {
76     return ChunkAllocatorBase::alloc(bytes);
77   }
78 
79   /**
80    * If contains(ptr) is true, free the allocation and return true.
81    * Otherwise, do nothing and return false.
82    *
83    * Reminder this is non-reentrant.
84    */
free(void * ptr)85   bool free(void *ptr) {
86     return ChunkAllocatorBase::free(ptr);
87   }
88 
89   /**
90    * If "ptr" was a non-null pointer returned from alloc() on this instance,
91    * return true.  Otherwise, do nothing and return false.
92    */
contains(const void * ptr)93   bool contains(const void *ptr) const {
94     return ChunkAllocatorBase::contains(ptr);
95   }
96 
97  private:
98   uint8_t mRawMemoryArray[kAllocSize * kSlotCount];
99 
100   static_assert(kSlotCount <= MaxSlotCount(), "kSlotCount is too high");
101 };
102 
103 }  // namespace nanoapp_testing
104 
105 #endif  // _GTS_NANOAPPS_SHARED_CHUNK_ALLOCATOR_H_
106