blob: 35ce95a1a4ff6fdab6c8a139cd32a3ab1c2bbb68 [file] [log] [blame]
Phil Burke1ce4912016-11-21 10:40:25 -08001/*
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
Phil Burk5ed503c2017-02-01 09:38:15 -080018#define LOG_TAG "AAudio"
Phil Burke1ce4912016-11-21 10:40:25 -080019//#define LOG_NDEBUG 0
20#include <utils/Log.h>
21
Phil Burkdec33ab2017-01-17 14:48:16 -080022#include <assert.h>
Andy Hung47c5e532017-06-26 18:28:00 -070023#include <functional>
24#include <iomanip>
Phil Burkd8bdcab2017-01-03 17:20:30 -080025#include <new>
Andy Hung47c5e532017-06-26 18:28:00 -070026#include <sstream>
Phil Burke1ce4912016-11-21 10:40:25 -080027#include <stdint.h>
Phil Burkdec33ab2017-01-17 14:48:16 -080028#include <utils/Mutex.h>
Phil Burke1ce4912016-11-21 10:40:25 -080029
Phil Burka4eb0d82017-04-12 15:44:06 -070030#include <aaudio/AAudio.h>
Andy Hung47c5e532017-06-26 18:28:00 -070031#include "AAudioUtilities.h"
Phil Burke1ce4912016-11-21 10:40:25 -080032#include "HandleTracker.h"
33
Phil Burkdec33ab2017-01-17 14:48:16 -080034using android::Mutex;
35
Phil Burke1ce4912016-11-21 10:40:25 -080036// Handle format is: tgggiiii
37// where each letter is 4 bits, t=type, g=generation, i=index
38
39#define TYPE_SIZE 4
40#define GENERATION_SIZE 12
41#define INDEX_SIZE 16
42
43#define GENERATION_INVALID 0
44#define GENERATION_SHIFT INDEX_SIZE
45
46#define TYPE_MASK ((1 << TYPE_SIZE) - 1)
47#define GENERATION_MASK ((1 << GENERATION_SIZE) - 1)
48#define INDEX_MASK ((1 << INDEX_SIZE) - 1)
49
50#define SLOT_UNAVAILABLE (-1)
51
52// Error if handle is negative so type is limited to bottom half.
53#define HANDLE_INVALID_TYPE TYPE_MASK
54
55static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
56 "Mismatch between header and cpp.");
57static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
58 "Mismatch between header and cpp.");
59
60HandleTracker::HandleTracker(uint32_t maxHandles)
61 : mMaxHandleCount(maxHandles)
Phil Burke1ce4912016-11-21 10:40:25 -080062 , mHandleHeaders(nullptr)
63{
64 assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
65 // Allocate arrays to hold addresses and validation info.
Phil Burkd8bdcab2017-01-03 17:20:30 -080066 mHandleAddresses = (handle_tracker_address_t *)
67 new(std::nothrow) handle_tracker_address_t[maxHandles];
Phil Burke1ce4912016-11-21 10:40:25 -080068 if (mHandleAddresses != nullptr) {
Phil Burkd8bdcab2017-01-03 17:20:30 -080069 mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
70
Phil Burke1ce4912016-11-21 10:40:25 -080071 if (mHandleHeaders != nullptr) {
Phil Burkd8bdcab2017-01-03 17:20:30 -080072 handle_tracker_header_t initialHeader = buildHeader(0, 1);
73 // Initialize linked list of free nodes. nullptr terminated.
Phil Burke1ce4912016-11-21 10:40:25 -080074 for (uint32_t i = 0; i < (maxHandles - 1); i++) {
75 mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
Phil Burkd8bdcab2017-01-03 17:20:30 -080076 mHandleHeaders[i] = initialHeader;
Phil Burke1ce4912016-11-21 10:40:25 -080077 }
78 mNextFreeAddress = &mHandleAddresses[0];
79 mHandleAddresses[maxHandles - 1] = nullptr;
80 mHandleHeaders[maxHandles - 1] = 0;
81 } else {
82 delete[] mHandleAddresses; // so the class appears uninitialized
Phil Burkd8bdcab2017-01-03 17:20:30 -080083 mHandleAddresses = nullptr;
Phil Burke1ce4912016-11-21 10:40:25 -080084 }
85 }
86}
87
88HandleTracker::~HandleTracker()
89{
Phil Burkdec33ab2017-01-17 14:48:16 -080090 Mutex::Autolock _l(mLock);
Phil Burke1ce4912016-11-21 10:40:25 -080091 delete[] mHandleAddresses;
92 delete[] mHandleHeaders;
Phil Burkdec33ab2017-01-17 14:48:16 -080093 mHandleAddresses = nullptr;
Phil Burke1ce4912016-11-21 10:40:25 -080094}
95
96bool HandleTracker::isInitialized() const {
97 return mHandleAddresses != nullptr;
98}
99
Andy Hung47c5e532017-06-26 18:28:00 -0700100
101
102std::string HandleTracker::dump() const {
103 if (!isInitialized()) {
104 return "HandleTracker is not initialized\n";
105 }
106
107 std::stringstream result;
108 const bool isLocked = AAudio_tryUntilTrue(
109 [this]()->bool { return mLock.tryLock(); } /* f */,
110 50 /* times */,
111 20 /* sleepMs */);
112 if (!isLocked) {
113 result << "HandleTracker may be deadlocked\n";
114 }
115
Phil Burk4501b352017-06-29 18:12:36 -0700116 result << "HandleTracker:\n";
117 result << " HandleHeaders:\n";
Andy Hung47c5e532017-06-26 18:28:00 -0700118 // atLineStart() can be changed to support an arbitrary line breaking algorithm;
119 // it should return true when a new line starts.
120 // For simplicity, we will use a constant 16 items per line.
121 const auto atLineStart = [](int index) -> bool {
122 // Magic constant of 0xf used for mask to detect start every 16 items.
123 return (index & 0xf) == 0; };
124 const auto atLineEnd = [this, &atLineStart](int index) -> bool {
125 return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
126
127 for (int i = 0; i < mMaxHandleCount; ++i) {
128 if (atLineStart(i)) {
Phil Burk4501b352017-06-29 18:12:36 -0700129 result << " ";
Andy Hung47c5e532017-06-26 18:28:00 -0700130 }
131 result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
132 << (atLineEnd(i) ? "\n" : " ");
133 }
134
135 if (isLocked) {
136 mLock.unlock();
137 }
138 return result.str();
139}
140
Phil Burkdec33ab2017-01-17 14:48:16 -0800141handle_tracker_slot_t HandleTracker::allocateSlot_l() {
Phil Burke1ce4912016-11-21 10:40:25 -0800142 void **allocated = mNextFreeAddress;
143 if (allocated == nullptr) {
144 return SLOT_UNAVAILABLE;
145 }
146 // Remove this slot from the head of the linked list.
147 mNextFreeAddress = (void **) *allocated;
148 return (allocated - mHandleAddresses);
149}
150
Phil Burkdec33ab2017-01-17 14:48:16 -0800151handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
Phil Burke1ce4912016-11-21 10:40:25 -0800152 handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
153 // Avoid generation zero so that 0x0 is not a valid handle.
154 if (generation == GENERATION_INVALID) {
155 generation++;
156 }
157 return generation;
158}
159
Phil Burk5ed503c2017-02-01 09:38:15 -0800160aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
Phil Burke1ce4912016-11-21 10:40:25 -0800161{
162 if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800163 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
Phil Burke1ce4912016-11-21 10:40:25 -0800164 }
165 if (!isInitialized()) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800166 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
Phil Burke1ce4912016-11-21 10:40:25 -0800167 }
168
Phil Burkdec33ab2017-01-17 14:48:16 -0800169 Mutex::Autolock _l(mLock);
170
Phil Burke1ce4912016-11-21 10:40:25 -0800171 // Find an empty slot.
Phil Burkdec33ab2017-01-17 14:48:16 -0800172 handle_tracker_slot_t index = allocateSlot_l();
Phil Burke1ce4912016-11-21 10:40:25 -0800173 if (index == SLOT_UNAVAILABLE) {
174 ALOGE("HandleTracker::put() no room for more handles");
Phil Burk5ed503c2017-02-01 09:38:15 -0800175 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
Phil Burke1ce4912016-11-21 10:40:25 -0800176 }
177
178 // Cycle the generation counter so stale handles can be detected.
Phil Burkdec33ab2017-01-17 14:48:16 -0800179 handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
Phil Burke1ce4912016-11-21 10:40:25 -0800180 handle_tracker_header_t inputHeader = buildHeader(type, generation);
181
182 // These two writes may need to be observed by other threads or cores during get().
183 mHandleHeaders[index] = inputHeader;
184 mHandleAddresses[index] = address;
185 // TODO use store release to enforce memory order with get()
186
187 // Generate a handle.
Phil Burk5ed503c2017-02-01 09:38:15 -0800188 aaudio_handle_t handle = buildHandle(inputHeader, index);
Phil Burke1ce4912016-11-21 10:40:25 -0800189
Phil Burkd8bdcab2017-01-03 17:20:30 -0800190 ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
Phil Burke1ce4912016-11-21 10:40:25 -0800191 return handle;
192}
193
194handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
Phil Burk5ed503c2017-02-01 09:38:15 -0800195 aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800196{
197 // Validate the handle.
198 handle_tracker_slot_t index = extractIndex(handle);
199 if (index >= mMaxHandleCount) {
200 ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
Phil Burk5ed503c2017-02-01 09:38:15 -0800201 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800202 }
203 handle_tracker_generation_t handleGeneration = extractGeneration(handle);
204 handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
Phil Burkdec33ab2017-01-17 14:48:16 -0800205 // We do not need to synchronize this access to mHandleHeaders because it is constant for
206 // the lifetime of the handle.
Phil Burke1ce4912016-11-21 10:40:25 -0800207 if (inputHeader != mHandleHeaders[index]) {
208 ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
209 inputHeader, index, mHandleHeaders[index]);
Phil Burk5ed503c2017-02-01 09:38:15 -0800210 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800211 }
212 return index;
213}
214
Phil Burk5ed503c2017-02-01 09:38:15 -0800215handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800216{
217 if (!isInitialized()) {
218 return nullptr;
219 }
220 handle_tracker_slot_t index = handleToIndex(type, handle);
221 if (index >= 0) {
Phil Burkdec33ab2017-01-17 14:48:16 -0800222 // We do not need to synchronize this access to mHandleHeaders because this slot
223 // is allocated and, therefore, not part of the linked list of free slots.
Phil Burke1ce4912016-11-21 10:40:25 -0800224 return mHandleAddresses[index];
225 } else {
226 return nullptr;
227 }
228}
229
Phil Burk5ed503c2017-02-01 09:38:15 -0800230handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
Phil Burke1ce4912016-11-21 10:40:25 -0800231 if (!isInitialized()) {
232 return nullptr;
233 }
Phil Burkdec33ab2017-01-17 14:48:16 -0800234
235 Mutex::Autolock _l(mLock);
236
Phil Burke1ce4912016-11-21 10:40:25 -0800237 handle_tracker_slot_t index = handleToIndex(type,handle);
238 if (index >= 0) {
239 handle_tracker_address_t address = mHandleAddresses[index];
240
241 // Invalidate the header type but preserve the generation count.
242 handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
243 handle_tracker_header_t inputHeader = buildHeader(
244 (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
245 mHandleHeaders[index] = inputHeader;
246
247 // Add this slot to the head of the linked list.
248 mHandleAddresses[index] = mNextFreeAddress;
249 mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
250 return address;
251 } else {
252 return nullptr;
253 }
254}
255
Phil Burk5ed503c2017-02-01 09:38:15 -0800256aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
Phil Burke1ce4912016-11-21 10:40:25 -0800257 handle_tracker_slot_t index) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800258 return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
Phil Burke1ce4912016-11-21 10:40:25 -0800259}
260
261handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
262 handle_tracker_generation_t generation)
263{
264 return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
265 | (generation & GENERATION_MASK));
266}
267
Phil Burk5ed503c2017-02-01 09:38:15 -0800268handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800269{
270 return handle & INDEX_MASK;
271}
272
Phil Burk5ed503c2017-02-01 09:38:15 -0800273handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800274{
275 return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
276}