blob: d4202dbc0b6b05fde8f708f00b2f7ec8c8ce6ed4 [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
116 result << "Handles:\n";
117 // atLineStart() can be changed to support an arbitrary line breaking algorithm;
118 // it should return true when a new line starts.
119 // For simplicity, we will use a constant 16 items per line.
120 const auto atLineStart = [](int index) -> bool {
121 // Magic constant of 0xf used for mask to detect start every 16 items.
122 return (index & 0xf) == 0; };
123 const auto atLineEnd = [this, &atLineStart](int index) -> bool {
124 return atLineStart(index + 1) || index == mMaxHandleCount - 1; };
125
126 for (int i = 0; i < mMaxHandleCount; ++i) {
127 if (atLineStart(i)) {
128 result << " ";
129 }
130 result << std::hex << std::setw(4) << std::setfill('0') << mHandleHeaders[i]
131 << (atLineEnd(i) ? "\n" : " ");
132 }
133
134 if (isLocked) {
135 mLock.unlock();
136 }
137 return result.str();
138}
139
Phil Burkdec33ab2017-01-17 14:48:16 -0800140handle_tracker_slot_t HandleTracker::allocateSlot_l() {
Phil Burke1ce4912016-11-21 10:40:25 -0800141 void **allocated = mNextFreeAddress;
142 if (allocated == nullptr) {
143 return SLOT_UNAVAILABLE;
144 }
145 // Remove this slot from the head of the linked list.
146 mNextFreeAddress = (void **) *allocated;
147 return (allocated - mHandleAddresses);
148}
149
Phil Burkdec33ab2017-01-17 14:48:16 -0800150handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
Phil Burke1ce4912016-11-21 10:40:25 -0800151 handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
152 // Avoid generation zero so that 0x0 is not a valid handle.
153 if (generation == GENERATION_INVALID) {
154 generation++;
155 }
156 return generation;
157}
158
Phil Burk5ed503c2017-02-01 09:38:15 -0800159aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
Phil Burke1ce4912016-11-21 10:40:25 -0800160{
161 if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800162 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
Phil Burke1ce4912016-11-21 10:40:25 -0800163 }
164 if (!isInitialized()) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800165 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
Phil Burke1ce4912016-11-21 10:40:25 -0800166 }
167
Phil Burkdec33ab2017-01-17 14:48:16 -0800168 Mutex::Autolock _l(mLock);
169
Phil Burke1ce4912016-11-21 10:40:25 -0800170 // Find an empty slot.
Phil Burkdec33ab2017-01-17 14:48:16 -0800171 handle_tracker_slot_t index = allocateSlot_l();
Phil Burke1ce4912016-11-21 10:40:25 -0800172 if (index == SLOT_UNAVAILABLE) {
173 ALOGE("HandleTracker::put() no room for more handles");
Phil Burk5ed503c2017-02-01 09:38:15 -0800174 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
Phil Burke1ce4912016-11-21 10:40:25 -0800175 }
176
177 // Cycle the generation counter so stale handles can be detected.
Phil Burkdec33ab2017-01-17 14:48:16 -0800178 handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
Phil Burke1ce4912016-11-21 10:40:25 -0800179 handle_tracker_header_t inputHeader = buildHeader(type, generation);
180
181 // These two writes may need to be observed by other threads or cores during get().
182 mHandleHeaders[index] = inputHeader;
183 mHandleAddresses[index] = address;
184 // TODO use store release to enforce memory order with get()
185
186 // Generate a handle.
Phil Burk5ed503c2017-02-01 09:38:15 -0800187 aaudio_handle_t handle = buildHandle(inputHeader, index);
Phil Burke1ce4912016-11-21 10:40:25 -0800188
Phil Burkd8bdcab2017-01-03 17:20:30 -0800189 ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
Phil Burke1ce4912016-11-21 10:40:25 -0800190 return handle;
191}
192
193handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
Phil Burk5ed503c2017-02-01 09:38:15 -0800194 aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800195{
196 // Validate the handle.
197 handle_tracker_slot_t index = extractIndex(handle);
198 if (index >= mMaxHandleCount) {
199 ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
Phil Burk5ed503c2017-02-01 09:38:15 -0800200 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800201 }
202 handle_tracker_generation_t handleGeneration = extractGeneration(handle);
203 handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
Phil Burkdec33ab2017-01-17 14:48:16 -0800204 // We do not need to synchronize this access to mHandleHeaders because it is constant for
205 // the lifetime of the handle.
Phil Burke1ce4912016-11-21 10:40:25 -0800206 if (inputHeader != mHandleHeaders[index]) {
207 ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
208 inputHeader, index, mHandleHeaders[index]);
Phil Burk5ed503c2017-02-01 09:38:15 -0800209 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800210 }
211 return index;
212}
213
Phil Burk5ed503c2017-02-01 09:38:15 -0800214handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800215{
216 if (!isInitialized()) {
217 return nullptr;
218 }
219 handle_tracker_slot_t index = handleToIndex(type, handle);
220 if (index >= 0) {
Phil Burkdec33ab2017-01-17 14:48:16 -0800221 // We do not need to synchronize this access to mHandleHeaders because this slot
222 // is allocated and, therefore, not part of the linked list of free slots.
Phil Burke1ce4912016-11-21 10:40:25 -0800223 return mHandleAddresses[index];
224 } else {
225 return nullptr;
226 }
227}
228
Phil Burk5ed503c2017-02-01 09:38:15 -0800229handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
Phil Burke1ce4912016-11-21 10:40:25 -0800230 if (!isInitialized()) {
231 return nullptr;
232 }
Phil Burkdec33ab2017-01-17 14:48:16 -0800233
234 Mutex::Autolock _l(mLock);
235
Phil Burke1ce4912016-11-21 10:40:25 -0800236 handle_tracker_slot_t index = handleToIndex(type,handle);
237 if (index >= 0) {
238 handle_tracker_address_t address = mHandleAddresses[index];
239
240 // Invalidate the header type but preserve the generation count.
241 handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
242 handle_tracker_header_t inputHeader = buildHeader(
243 (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
244 mHandleHeaders[index] = inputHeader;
245
246 // Add this slot to the head of the linked list.
247 mHandleAddresses[index] = mNextFreeAddress;
248 mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
249 return address;
250 } else {
251 return nullptr;
252 }
253}
254
Phil Burk5ed503c2017-02-01 09:38:15 -0800255aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
Phil Burke1ce4912016-11-21 10:40:25 -0800256 handle_tracker_slot_t index) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800257 return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
Phil Burke1ce4912016-11-21 10:40:25 -0800258}
259
260handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
261 handle_tracker_generation_t generation)
262{
263 return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
264 | (generation & GENERATION_MASK));
265}
266
Phil Burk5ed503c2017-02-01 09:38:15 -0800267handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800268{
269 return handle & INDEX_MASK;
270}
271
Phil Burk5ed503c2017-02-01 09:38:15 -0800272handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800273{
274 return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
275}