blob: f9572348e0f2f02c24903b779bf9982aef05d921 [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>
Phil Burkd8bdcab2017-01-03 17:20:30 -080023#include <new>
Phil Burke1ce4912016-11-21 10:40:25 -080024#include <stdint.h>
Phil Burkdec33ab2017-01-17 14:48:16 -080025#include <utils/Mutex.h>
Phil Burke1ce4912016-11-21 10:40:25 -080026
Phil Burka4eb0d82017-04-12 15:44:06 -070027#include <aaudio/AAudio.h>
Phil Burke1ce4912016-11-21 10:40:25 -080028#include "HandleTracker.h"
29
Phil Burkdec33ab2017-01-17 14:48:16 -080030using android::Mutex;
31
Phil Burke1ce4912016-11-21 10:40:25 -080032// Handle format is: tgggiiii
33// where each letter is 4 bits, t=type, g=generation, i=index
34
35#define TYPE_SIZE 4
36#define GENERATION_SIZE 12
37#define INDEX_SIZE 16
38
39#define GENERATION_INVALID 0
40#define GENERATION_SHIFT INDEX_SIZE
41
42#define TYPE_MASK ((1 << TYPE_SIZE) - 1)
43#define GENERATION_MASK ((1 << GENERATION_SIZE) - 1)
44#define INDEX_MASK ((1 << INDEX_SIZE) - 1)
45
46#define SLOT_UNAVAILABLE (-1)
47
48// Error if handle is negative so type is limited to bottom half.
49#define HANDLE_INVALID_TYPE TYPE_MASK
50
51static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
52 "Mismatch between header and cpp.");
53static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
54 "Mismatch between header and cpp.");
55
56HandleTracker::HandleTracker(uint32_t maxHandles)
57 : mMaxHandleCount(maxHandles)
Phil Burke1ce4912016-11-21 10:40:25 -080058 , mHandleHeaders(nullptr)
59{
60 assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
61 // Allocate arrays to hold addresses and validation info.
Phil Burkd8bdcab2017-01-03 17:20:30 -080062 mHandleAddresses = (handle_tracker_address_t *)
63 new(std::nothrow) handle_tracker_address_t[maxHandles];
Phil Burke1ce4912016-11-21 10:40:25 -080064 if (mHandleAddresses != nullptr) {
Phil Burkd8bdcab2017-01-03 17:20:30 -080065 mHandleHeaders = new(std::nothrow) handle_tracker_header_t[maxHandles];
66
Phil Burke1ce4912016-11-21 10:40:25 -080067 if (mHandleHeaders != nullptr) {
Phil Burkd8bdcab2017-01-03 17:20:30 -080068 handle_tracker_header_t initialHeader = buildHeader(0, 1);
69 // Initialize linked list of free nodes. nullptr terminated.
Phil Burke1ce4912016-11-21 10:40:25 -080070 for (uint32_t i = 0; i < (maxHandles - 1); i++) {
71 mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
Phil Burkd8bdcab2017-01-03 17:20:30 -080072 mHandleHeaders[i] = initialHeader;
Phil Burke1ce4912016-11-21 10:40:25 -080073 }
74 mNextFreeAddress = &mHandleAddresses[0];
75 mHandleAddresses[maxHandles - 1] = nullptr;
76 mHandleHeaders[maxHandles - 1] = 0;
77 } else {
78 delete[] mHandleAddresses; // so the class appears uninitialized
Phil Burkd8bdcab2017-01-03 17:20:30 -080079 mHandleAddresses = nullptr;
Phil Burke1ce4912016-11-21 10:40:25 -080080 }
81 }
82}
83
84HandleTracker::~HandleTracker()
85{
Phil Burkdec33ab2017-01-17 14:48:16 -080086 Mutex::Autolock _l(mLock);
Phil Burke1ce4912016-11-21 10:40:25 -080087 delete[] mHandleAddresses;
88 delete[] mHandleHeaders;
Phil Burkdec33ab2017-01-17 14:48:16 -080089 mHandleAddresses = nullptr;
Phil Burke1ce4912016-11-21 10:40:25 -080090}
91
92bool HandleTracker::isInitialized() const {
93 return mHandleAddresses != nullptr;
94}
95
Phil Burkdec33ab2017-01-17 14:48:16 -080096handle_tracker_slot_t HandleTracker::allocateSlot_l() {
Phil Burke1ce4912016-11-21 10:40:25 -080097 void **allocated = mNextFreeAddress;
98 if (allocated == nullptr) {
99 return SLOT_UNAVAILABLE;
100 }
101 // Remove this slot from the head of the linked list.
102 mNextFreeAddress = (void **) *allocated;
103 return (allocated - mHandleAddresses);
104}
105
Phil Burkdec33ab2017-01-17 14:48:16 -0800106handle_tracker_generation_t HandleTracker::nextGeneration_l(handle_tracker_slot_t index) {
Phil Burke1ce4912016-11-21 10:40:25 -0800107 handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
108 // Avoid generation zero so that 0x0 is not a valid handle.
109 if (generation == GENERATION_INVALID) {
110 generation++;
111 }
112 return generation;
113}
114
Phil Burk5ed503c2017-02-01 09:38:15 -0800115aaudio_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
Phil Burke1ce4912016-11-21 10:40:25 -0800116{
117 if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800118 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_OUT_OF_RANGE);
Phil Burke1ce4912016-11-21 10:40:25 -0800119 }
120 if (!isInitialized()) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800121 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_MEMORY);
Phil Burke1ce4912016-11-21 10:40:25 -0800122 }
123
Phil Burkdec33ab2017-01-17 14:48:16 -0800124 Mutex::Autolock _l(mLock);
125
Phil Burke1ce4912016-11-21 10:40:25 -0800126 // Find an empty slot.
Phil Burkdec33ab2017-01-17 14:48:16 -0800127 handle_tracker_slot_t index = allocateSlot_l();
Phil Burke1ce4912016-11-21 10:40:25 -0800128 if (index == SLOT_UNAVAILABLE) {
129 ALOGE("HandleTracker::put() no room for more handles");
Phil Burk5ed503c2017-02-01 09:38:15 -0800130 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_NO_FREE_HANDLES);
Phil Burke1ce4912016-11-21 10:40:25 -0800131 }
132
133 // Cycle the generation counter so stale handles can be detected.
Phil Burkdec33ab2017-01-17 14:48:16 -0800134 handle_tracker_generation_t generation = nextGeneration_l(index); // reads header table
Phil Burke1ce4912016-11-21 10:40:25 -0800135 handle_tracker_header_t inputHeader = buildHeader(type, generation);
136
137 // These two writes may need to be observed by other threads or cores during get().
138 mHandleHeaders[index] = inputHeader;
139 mHandleAddresses[index] = address;
140 // TODO use store release to enforce memory order with get()
141
142 // Generate a handle.
Phil Burk5ed503c2017-02-01 09:38:15 -0800143 aaudio_handle_t handle = buildHandle(inputHeader, index);
Phil Burke1ce4912016-11-21 10:40:25 -0800144
Phil Burkd8bdcab2017-01-03 17:20:30 -0800145 ALOGV("HandleTracker::put(%p) returns 0x%08x", address, handle);
Phil Burke1ce4912016-11-21 10:40:25 -0800146 return handle;
147}
148
149handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
Phil Burk5ed503c2017-02-01 09:38:15 -0800150 aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800151{
152 // Validate the handle.
153 handle_tracker_slot_t index = extractIndex(handle);
154 if (index >= mMaxHandleCount) {
155 ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
Phil Burk5ed503c2017-02-01 09:38:15 -0800156 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800157 }
158 handle_tracker_generation_t handleGeneration = extractGeneration(handle);
159 handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
Phil Burkdec33ab2017-01-17 14:48:16 -0800160 // We do not need to synchronize this access to mHandleHeaders because it is constant for
161 // the lifetime of the handle.
Phil Burke1ce4912016-11-21 10:40:25 -0800162 if (inputHeader != mHandleHeaders[index]) {
163 ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
164 inputHeader, index, mHandleHeaders[index]);
Phil Burk5ed503c2017-02-01 09:38:15 -0800165 return static_cast<aaudio_handle_t>(AAUDIO_ERROR_INVALID_HANDLE);
Phil Burke1ce4912016-11-21 10:40:25 -0800166 }
167 return index;
168}
169
Phil Burk5ed503c2017-02-01 09:38:15 -0800170handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, aaudio_handle_t handle) const
Phil Burke1ce4912016-11-21 10:40:25 -0800171{
172 if (!isInitialized()) {
173 return nullptr;
174 }
175 handle_tracker_slot_t index = handleToIndex(type, handle);
176 if (index >= 0) {
Phil Burkdec33ab2017-01-17 14:48:16 -0800177 // We do not need to synchronize this access to mHandleHeaders because this slot
178 // is allocated and, therefore, not part of the linked list of free slots.
Phil Burke1ce4912016-11-21 10:40:25 -0800179 return mHandleAddresses[index];
180 } else {
181 return nullptr;
182 }
183}
184
Phil Burk5ed503c2017-02-01 09:38:15 -0800185handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, aaudio_handle_t handle) {
Phil Burke1ce4912016-11-21 10:40:25 -0800186 if (!isInitialized()) {
187 return nullptr;
188 }
Phil Burkdec33ab2017-01-17 14:48:16 -0800189
190 Mutex::Autolock _l(mLock);
191
Phil Burke1ce4912016-11-21 10:40:25 -0800192 handle_tracker_slot_t index = handleToIndex(type,handle);
193 if (index >= 0) {
194 handle_tracker_address_t address = mHandleAddresses[index];
195
196 // Invalidate the header type but preserve the generation count.
197 handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
198 handle_tracker_header_t inputHeader = buildHeader(
199 (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
200 mHandleHeaders[index] = inputHeader;
201
202 // Add this slot to the head of the linked list.
203 mHandleAddresses[index] = mNextFreeAddress;
204 mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
205 return address;
206 } else {
207 return nullptr;
208 }
209}
210
Phil Burk5ed503c2017-02-01 09:38:15 -0800211aaudio_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
Phil Burke1ce4912016-11-21 10:40:25 -0800212 handle_tracker_slot_t index) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800213 return (aaudio_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
Phil Burke1ce4912016-11-21 10:40:25 -0800214}
215
216handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
217 handle_tracker_generation_t generation)
218{
219 return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
220 | (generation & GENERATION_MASK));
221}
222
Phil Burk5ed503c2017-02-01 09:38:15 -0800223handle_tracker_slot_t HandleTracker::extractIndex(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800224{
225 return handle & INDEX_MASK;
226}
227
Phil Burk5ed503c2017-02-01 09:38:15 -0800228handle_tracker_generation_t HandleTracker::extractGeneration(aaudio_handle_t handle)
Phil Burke1ce4912016-11-21 10:40:25 -0800229{
230 return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
231}