HandleTracker.h revision 3316d5e6d375a4f09c681205e9094d30a0bfc4a2
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
23typedef int32_t  aaudio_handle_t;
24typedef int32_t  handle_tracker_type_t;       // what kind of handle
25typedef int32_t  handle_tracker_slot_t;       // index in allocation table
26typedef int32_t  handle_tracker_generation_t; // incremented when slot used
27typedef uint16_t handle_tracker_header_t;     // combines type and generation
28typedef 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 */
40class HandleTracker {
41
42public:
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
90private:
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