1 /* 2 * Copyright (C) 2018 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 ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H 18 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H 19 20 #include <android-base/thread_annotations.h> 21 #include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h> 22 #include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h> 23 #include <hidl/Status.h> 24 #include <condition_variable> 25 #include <mutex> 26 27 /* 28 * The Callback classes are used internally by the NeuralNetworks runtime to 29 * synchronize between different threads. An asynchronous task is launched 30 * paired with a callback object. When a client thread requires the output being 31 * generated by the asynchronous task, the client thread can wait for the result 32 * and be blocked until it has completed. Any wait may safely be called 33 * concurrently, even on the same callback object. When the asynchronous task 34 * has finished its workload, it must immediately call "notify". If the 35 * asynchronous task has failed to launch, the function that tried to launch the 36 * asynchronous task must immediately call "notify". This "notify" call 37 * awakens any client threads waiting on the callback object. 38 * 39 * These classes exist to enable synchronization across HIDL. When 40 * synchronization is only required in the same process, consider using 41 * std::future, std::mutex, std::condition_variable, or std::experimental::latch 42 * instead. 43 */ 44 45 namespace android::hardware::neuralnetworks::V1_0::implementation { 46 47 /** 48 * The PreparedModelCallback class is used to receive the error status of 49 * preparing a model as well as the prepared model from a task executing 50 * asynchronously with respect to the runtime. If a calling thread calls wait 51 * or get* on a PreparedModelCallback object and the corresponding asynchronous 52 * task has not finished preparing the model, the calling thread will block 53 * until the asynchronous task has called notify. 54 * 55 * If the callback object is notified more than once, only the results of the 56 * first call to notify are used, and the results from subsequent calls are 57 * discarded. 58 * 59 * This callback object is passed as an argument to IDevice::prepareModel*. 60 */ 61 class PreparedModelCallback : public IPreparedModelCallback { 62 public: 63 /** 64 * IPreparedModelCallback::notify marks the callback object with the return 65 * status of the asynchronous model preparation along with the prepared 66 * model, and allows all prior and future wait calls on the 67 * PreparedModelCallback object to proceed. 68 * 69 * IPreparedModelCallback::notify must be called on a given 70 * PreparedModelCallback object. 71 * 72 * If the callback object is notified more than once, only the results of 73 * the first call to notify are used, and the results from subsequent calls 74 * are discarded. 75 * 76 * @param status Error status returned from asynchronously preparing the 77 * model; will be: 78 * - NONE if the asynchronous preparation was successful 79 * - DEVICE_UNAVAILABLE if driver is offline or busy 80 * - GENERAL_FAILURE if there is an unspecified error 81 * - INVALID_ARGUMENT if the input model is invalid 82 * @param preparedModel Returned model that has been prepared for execution, 83 * nullptr if the model was unable to be prepared. 84 */ 85 Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override; 86 87 /** 88 * PreparedModelCallback::wait blocks until notify has been called on the 89 * callback object. 90 */ 91 void wait() const; 92 93 /** 94 * Retrieves the error status returned from the asynchronous task launched 95 * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished 96 * asynchronously preparing the model, this call will block until the 97 * asynchronous task notifies the object. 98 * 99 * @return status Error status returned from asynchronously preparing the 100 * model; will be: 101 * - NONE if the asynchronous preparation was successful 102 * - DEVICE_UNAVAILABLE if driver is offline or busy 103 * - GENERAL_FAILURE if there is an unspecified error 104 * - INVALID_ARGUMENT if the input model is invalid 105 */ 106 ErrorStatus getStatus() const; 107 108 /** 109 * Retrieves the model that has been prepared for execution from the 110 * asynchronous task launched by IDevice::prepareModel*. If 111 * IDevice::prepareModel* has not finished asynchronously preparing the 112 * model, this call will block until the asynchronous task notifies the 113 * object. 114 * 115 * @return preparedModel Returned model that has been prepared for 116 * execution, nullptr if the model was unable to be prepared. 117 */ 118 sp<IPreparedModel> getPreparedModel() const; 119 120 private: 121 mutable std::mutex mMutex; 122 mutable std::condition_variable mCondition; 123 bool mNotified GUARDED_BY(mMutex) = false; 124 ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; 125 sp<IPreparedModel> mPreparedModel; 126 }; 127 128 /** 129 * The ExecutionCallback class is used to receive the results of the execution 130 * from a task executing asynchronously with respect to the runtime. If a 131 * calling thread calls wait or get* on a ExecutionCallback object and the 132 * corresponding asynchronous task has not finished the execution, the calling 133 * thread will block until the asynchronous task has called notify. 134 * 135 * If the callback object is notified more than once, only the results of the 136 * first call to notify are used, and the results from subsequent calls are 137 * discarded. 138 * 139 * This callback object is passed as an argument to IPreparedModel::execute*. 140 */ 141 class ExecutionCallback : public IExecutionCallback { 142 public: 143 /** 144 * IExecutionCallback::notify marks the callback object with the return 145 * status of the asynchronous execution that held this callback and enables 146 * all prior and future wait calls on the ExecutionCallback object to 147 * proceed. 148 * 149 * IExecutionCallback::notify must be called on a given ExecutionCallback 150 * object. 151 * 152 * If the callback object is notified more than once, only the results of 153 * the first call to notify are used, and the results from subsequent calls 154 * are discarded. 155 * 156 * @param status Error status returned from launching the asynchronous task 157 * (if the launch fails) or from the asynchronous task itself (if the 158 * launch succeeds). Must be: 159 * - NONE if the asynchronous execution was successful 160 * - DEVICE_UNAVAILABLE if driver is offline or busy 161 * - GENERAL_FAILURE if there is an unspecified error 162 * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large 163 * enough to store the resultant values 164 * - INVALID_ARGUMENT if the input request is invalid 165 */ 166 Return<void> notify(ErrorStatus status) override; 167 168 /** 169 * ExecutionCallback::wait blocks until notify has been called on the 170 * callback object. 171 */ 172 void wait() const; 173 174 /** 175 * Retrieves the error status returned from the asynchronous task launched 176 * by IPreparedModel::execute. If IPreparedModel::execute has not finished 177 * asynchronously executing, this call will block until the asynchronous 178 * task notifies the object. 179 * 180 * @return status Error status returned from launching the asynchronous task 181 * (if the launch fails) or from the asynchronous task itself (if the 182 * launch succeeds). Must be: 183 * - NONE if the asynchronous execution was successful 184 * - DEVICE_UNAVAILABLE if driver is offline or busy 185 * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified 186 * error 187 * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is 188 * not large enough to store the corresponding output 189 * - INVALID_ARGUMENT if one of the input arguments to prepareModel is 190 * invalid 191 */ 192 ErrorStatus getStatus() const; 193 194 private: 195 mutable std::mutex mMutex; 196 mutable std::condition_variable mCondition; 197 bool mNotified GUARDED_BY(mMutex) = false; 198 ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE; 199 }; 200 201 } // namespace android::hardware::neuralnetworks::V1_0::implementation 202 203 #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H 204