1 /* 2 * Copyright 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 UTILITY_HANDLE_TRACKER_H 18 #define UTILITY_HANDLE_TRACKER_H 19 20 #include <stdint.h> 21 #include <utils/Mutex.h> 22 23 typedef int32_t aaudio_handle_t; 24 typedef int32_t handle_tracker_type_t; // what kind of handle 25 typedef int32_t handle_tracker_slot_t; // index in allocation table 26 typedef int32_t handle_tracker_generation_t; // incremented when slot used 27 typedef uint16_t handle_tracker_header_t; // combines type and generation 28 typedef void *handle_tracker_address_t; // address of something that is stored here 29 30 #define HANDLE_TRACKER_MAX_TYPES (1 << 3) 31 #define HANDLE_TRACKER_MAX_HANDLES (1 << 16) 32 33 /** 34 * Represent Objects using an integer handle that can be used with Java. 35 * This also makes the 'C' ABI more robust. 36 * 37 * Note that this should only be called from a single thread. 38 * If you call it from more than one thread then you need to use your own mutex. 39 */ 40 class HandleTracker { 41 42 public: 43 /** 44 * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES 45 */ 46 HandleTracker(uint32_t maxHandles = 256); 47 virtual ~HandleTracker(); 48 49 /** 50 * Don't use if this returns false; 51 * @return true if the internal allocation succeeded 52 */ 53 bool isInitialized() const; 54 55 /** 56 * Store a pointer and return a handle that can be used to retrieve the pointer. 57 * 58 * It is safe to call put() or remove() from multiple threads. 59 * 60 * @param expectedType the type of the object to be tracked 61 * @param address pointer to be converted to a handle 62 * @return a valid handle or a negative error 63 */ 64 aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address); 65 66 /** 67 * Get the original pointer associated with the handle. 68 * The handle will be validated to prevent stale handles from being reused. 69 * Note that the validation is designed to prevent common coding errors and not 70 * to prevent deliberate hacking. 71 * 72 * @param expectedType shouldmatch the type we passed to put() 73 * @param handle to be converted to a pointer 74 * @return address associated with handle or nullptr 75 */ 76 handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const; 77 78 /** 79 * Free up the storage associated with the handle. 80 * Subsequent attempts to use the handle will fail. 81 * 82 * Do NOT remove() a handle while get() is being called for the same handle from another thread. 83 * 84 * @param expectedType shouldmatch the type we passed to put() 85 * @param handle to be removed from tracking 86 * @return address associated with handle or nullptr if not found 87 */ 88 handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle); 89 90 private: 91 const int32_t mMaxHandleCount; // size of array 92 // This address is const after initialization. 93 handle_tracker_address_t * mHandleAddresses; // address of objects or a free linked list node 94 // This address is const after initialization. 95 handle_tracker_header_t * mHandleHeaders; // combination of type and generation 96 // head of the linked list of free nodes in mHandleAddresses 97 handle_tracker_address_t * mNextFreeAddress; 98 99 // This Mutex protects the linked list of free nodes. 100 // The list is managed using mHandleAddresses and mNextFreeAddress. 101 // The data in mHandleHeaders is only changed by put() and remove(). 102 android::Mutex mLock; 103 104 /** 105 * Pull slot off of a list of empty slots. 106 * @return index or a negative error 107 */ 108 handle_tracker_slot_t allocateSlot_l(); 109 110 /** 111 * Increment the generation for the slot, avoiding zero. 112 */ 113 handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index); 114 115 /** 116 * Validate the handle and return the corresponding index. 117 * @return slot index or a negative error 118 */ 119 handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const; 120 121 /** 122 * Construct a handle from a header and an index. 123 * @param header combination of a type and a generation 124 * @param index slot index returned from allocateSlot 125 * @return handle or a negative error 126 */ 127 static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index); 128 129 /** 130 * Combine a type and a generation field into a header. 131 */ 132 static handle_tracker_header_t buildHeader(handle_tracker_type_t type, 133 handle_tracker_generation_t generation); 134 135 /** 136 * Extract the index from a handle. 137 * Does not validate the handle. 138 * @return index associated with a handle 139 */ 140 static handle_tracker_slot_t extractIndex(aaudio_handle_t handle); 141 142 /** 143 * Extract the generation from a handle. 144 * Does not validate the handle. 145 * @return generation associated with a handle 146 */ 147 static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle); 148 149 }; 150 151 #endif //UTILITY_HANDLE_TRACKER_H 152