1 /* 2 * Copyright (C) 2024 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 CHRE_UTIL_TRANSACTION_MANAGER_H_ 18 #define CHRE_UTIL_TRANSACTION_MANAGER_H_ 19 20 #include <cstdint> 21 #include <type_traits> 22 23 #include "chre/platform/mutex.h" 24 #include "chre/util/array_queue.h" 25 #include "chre/util/non_copyable.h" 26 #include "chre/util/optional.h" 27 #include "chre/util/time.h" 28 29 namespace chre { 30 31 /** 32 * TransactionManager tracks pending transactions. 33 * 34 * Transactions are long running operations identified by an ID. 35 * The TransactionManager makes sure that the transactions will complete only 36 * once after a call to completeTransaction or after the optional timeout 37 * expires whichever comes first. A transaction will be retried by calling 38 * the start callback after no complete call has been made before the retry 39 * wait time. 40 * 41 * Typical usage: 42 * 1. Start a transaction. Get the ID back. 43 * 2. TransactionManager will run start callback with the data. 44 * 3. If the start callback fails or if the transaction is not completed, 45 * TransactionManager will call the start callback again after the retry 46 * wait time. 47 * 4. Call completeTransaction with the ID. 48 * 5. TransactionManager will call the complete callback with the data. 49 * 50 * If completeTransaction is not called before the timeout, the transaction 51 * will be completed with a CHRE_ERROR_TIMEOUT. 52 * 53 * Ensure the thread processing the deferred callbacks is completed before the 54 * destruction of the TransactionManager. 55 * 56 * @param TransactionData The data passed to the start and complete callbacks. 57 * @param kMaxTransactions The maximum number of pending transactions. 58 */ 59 template <typename TransactionData, size_t kMaxTransactions> 60 class TransactionManager : public NonCopyable { 61 public: 62 /** 63 * Type of the callback called on transaction completion. This callback is 64 * called in the defer callback thread. 65 * 66 * This callback cannot call any of the TransactionManager methods. 67 * 68 * @param data The data for the transaction. 69 * @param errorCode The error code passed to completeTransaction. 70 * @return whether the callback succeeded. 71 */ 72 using CompleteCallback = typename std::conditional< 73 std::is_pointer<TransactionData>::value || 74 std::is_fundamental<TransactionData>::value, 75 bool (*)(TransactionData data, uint8_t errorCode), 76 bool (*)(const TransactionData &data, uint8_t errorCode)>::type; 77 78 /** 79 * Type of the callback called to start the transaction. This is the action 80 * that will be repeated on a retry of the transaction. This callback is 81 * called in the defer callback thread. 82 * 83 * This callback cannot call any of the TransactionManager methods. 84 * 85 * @param data The data for the transaction. 86 * @return whether the callback succeeded. 87 */ 88 using StartCallback = 89 typename std::conditional<std::is_pointer<TransactionData>::value || 90 std::is_fundamental<TransactionData>::value, 91 bool (*)(TransactionData data), 92 bool (*)(TransactionData &data)>::type; 93 94 /** 95 * The type of function used to defer a callback. See DeferCallback. 96 * 97 * @param type The type passed from the DeferCallback. 98 * @param data The data passed from the DeferCallback. 99 * @param extraData The extra data passed from the DeferCallback. 100 */ 101 using DeferCallbackFunction = void (*)(uint16_t type, void *data, 102 void *extraData); 103 104 /** 105 * Type of the callback used to defer the call of func with data and extraData 106 * after waiting for delay. extraData is ignored if delay > 0 ns. 107 * 108 * This callback cannot call any of the TransactionManager methods. 109 * 110 * @param func The function to call when the callback is executed. 111 * @param data The data to pass to the function. 112 * @param extraData The extra data to pass to the function. 113 * @param delay The nanoseconds delay to wait before calling the function. 114 * @param outTimerHandle The output timer handle if delay > 0 ns. 115 * @return whether the callback succeeded. 116 */ 117 using DeferCallback = bool (*)(DeferCallbackFunction func, void *data, 118 void *extraData, Nanoseconds delay, 119 uint32_t *outTimerHandle); 120 121 /** 122 * Type of the callback used to cancel a defer call made using the 123 * DeferCallback. 124 * 125 * This callback cannot call any of the TransactionManager methods. 126 * 127 * @param timerHandle the timer handle returned using the DeferCallback. 128 * @return whether the callback was successfully cancelled. 129 */ 130 using DeferCancelCallback = bool (*)(uint32_t timerHandle); 131 132 /** 133 * The callback used to determine which elements to remove 134 * during a flush. 135 * 136 * This callback cannot call any of the TransactionManager methods. 137 */ 138 using FlushCallback = typename std::conditional< 139 std::is_pointer<TransactionData>::value || 140 std::is_fundamental<TransactionData>::value, 141 bool (*)(TransactionData data, void *callbackData), 142 bool (*)(const TransactionData &data, void *callbackData)>::type; 143 144 /** 145 * The function called when the transaction processing timer is fired. 146 * @see DeferCallbackFunction() for parameter information. 147 */ onTimerFired(uint16_t,void * data,void *)148 static void onTimerFired(uint16_t /* type */, void *data, 149 void * /* extraData */) { 150 auto transactionManagerPtr = static_cast<TransactionManager *>(data); 151 if (transactionManagerPtr == nullptr) { 152 LOGE("Could not get transaction manager to process transactions"); 153 return; 154 } 155 156 transactionManagerPtr->mTimerHandle = CHRE_TIMER_INVALID; 157 transactionManagerPtr->processTransactions(); 158 } 159 160 TransactionManager() = delete; 161 162 TransactionManager(StartCallback startCallback, 163 CompleteCallback completeCallback, 164 DeferCallback deferCallback, 165 DeferCancelCallback deferCancelCallback, 166 Nanoseconds retryWaitTime, Nanoseconds timeout, 167 uint16_t maxNumRetries = 3) kStartCallback(startCallback)168 : kStartCallback(startCallback), 169 kCompleteCallback(completeCallback), 170 kDeferCallback(deferCallback), 171 kDeferCancelCallback(deferCancelCallback), 172 kRetryWaitTime(retryWaitTime), 173 kTimeout(timeout), 174 kMaxNumRetries(maxNumRetries) { 175 CHRE_ASSERT(startCallback != nullptr); 176 CHRE_ASSERT(completeCallback != nullptr); 177 CHRE_ASSERT(deferCallback != nullptr); 178 CHRE_ASSERT(deferCancelCallback != nullptr); 179 CHRE_ASSERT(retryWaitTime.toRawNanoseconds() > 0); 180 CHRE_ASSERT(timeout.toRawNanoseconds() == 0 || 181 timeout.toRawNanoseconds() > retryWaitTime.toRawNanoseconds()); 182 } 183 184 /** 185 * Completes a transaction. 186 * 187 * The callback registered when starting the transaction is called with the 188 * errorCode if the error is not CHRE_ERROR_TRANSIENT. If the error is 189 * CHRE_ERROR_TRANSIENT, this function marks the transaction as ready 190 * to retry and processes transactions. 191 * 192 * This function is safe to call in any thread. 193 * 194 * Note that the callback will be called at most once on the first call to 195 * this method. For example if the transaction timed out before an explicit 196 * call to completeTransaction, the callback is only invoked for the timeout. 197 * 198 * @param transactionId ID of the transaction to complete. 199 * @param errorCode Error code to pass to the callback. 200 * @return Whether the transaction was completed successfully. 201 */ 202 bool completeTransaction(uint32_t transactionId, uint8_t errorCode); 203 204 /** 205 * Flushes all the pending transactions that match the FlushCallback. 206 * 207 * This function is safe to call in any thread. 208 * 209 * The completion callback is not called. 210 * 211 * @param flushCallback The function that determines which transactions will 212 * be flushed (upon return true). 213 * @param data The data to be passed to the flush callback. 214 * @return The number of flushed transactions. 215 */ 216 size_t flushTransactions(FlushCallback flushCallback, void *data); 217 218 /** 219 * Starts a transaction. This function will mark the transaction as ready to 220 * execute the StartCallback and processes transactions. The StartCallback 221 * will be called only when there are no other pending transactions for the 222 * unique cookie. 223 * 224 * The transaction will complete with a CHRE_ERROR_TIMEOUT if 225 * completeTransaction has not been called before the timeout. The timeout 226 * is calculated from the time the StartCallback is called. 227 * 228 * This function is safe to call in any thread. 229 * 230 * @param data The transaction data and callbacks used to run the transaction. 231 * @param cookie The cookie used to ensure only one transaction will be 232 * started and pending for a given cookie. 233 * @param id A pointer to the transaction ID that will be populated when 234 * startTransaction succeed. It must not be null. 235 * @return Whether the transaction was started successfully. 236 */ 237 bool startTransaction(const TransactionData &data, uint16_t cookie, 238 uint32_t *id); 239 240 private: 241 //! Stores transaction-related data. 242 struct Transaction { 243 uint32_t id; 244 TransactionData data; 245 Nanoseconds nextRetryTime; 246 Nanoseconds timeoutTime; 247 uint16_t cookie; 248 uint16_t numCompletedStartCalls; 249 Optional<uint8_t> errorCode; 250 }; 251 252 /** 253 * Defers processing transactions in the defer callback thread. 254 */ 255 void deferProcessTransactions(); 256 257 /** 258 * Calls the complete callback for a transaction if needed. Also updates the 259 * transaction state. Assumes the caller holds the mutex. 260 * 261 * @param transaction The transaction. 262 */ 263 void doCompleteTransactionLocked(Transaction &transaction); 264 265 /** 266 * Calls the start callback for a transaction if needed. Also updates the 267 * transaction state. Assumes the caller holds the mutex. 268 * 269 * @param transaction The transaction. 270 * @param i The index of the transaction in mTransactions. 271 * @param now The current time. 272 */ 273 void doStartTransactionLocked(Transaction &transaction, size_t i, 274 Nanoseconds now); 275 276 /** 277 * Generates a pseudo random ID for a transaction in the range of 278 * [0, 2^30 - 1]. 279 * @return The generated ID. 280 */ 281 uint32_t generatePseudoRandomId(); 282 283 /** 284 * Processes transactions. This function will call the start callback and 285 * complete callback where appropriate and keep track of which transactions 286 * need to be retried next. This function is called in the defer callback 287 * thread and will defer a call to itself at the next time needed to processes 288 * the next transaction. 289 */ 290 void processTransactions(); 291 292 //! The start callback. 293 const StartCallback kStartCallback; 294 295 //! The complete callback. 296 const CompleteCallback kCompleteCallback; 297 298 //! The defer callback. 299 const DeferCallback kDeferCallback; 300 301 //! The defer cancel callback. 302 const DeferCancelCallback kDeferCancelCallback; 303 304 //! The retry wait time. 305 const Nanoseconds kRetryWaitTime; 306 307 //! The timeout for a transaction. 308 const Nanoseconds kTimeout; 309 310 //! The maximum number of retries for a transaction. 311 const uint16_t kMaxNumRetries; 312 313 //! The mutex protecting mTransactions and mTimerHandle. 314 Mutex mMutex; 315 316 //! The next ID for use when creating a transaction. 317 Optional<uint32_t> mNextTransactionId; 318 319 //! The timer handle for the timer tracking execution of processTransactions. 320 //! Can only be modified in the defer callback thread. 321 uint32_t mTimerHandle = CHRE_TIMER_INVALID; 322 323 //! The list of transactions. 324 ArrayQueue<Transaction, kMaxTransactions> mTransactions; 325 }; 326 327 } // namespace chre 328 329 #include "chre/util/transaction_manager_impl.h" 330 331 #endif // CHRE_UTIL_TRANSACTION_MANAGER_H_ 332