1 /* 2 * Copyright 2023 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 TEST_VENDOR_LIB_ASYNC_MANAGER_H_ 18 #define TEST_VENDOR_LIB_ASYNC_MANAGER_H_ 19 20 #include <time.h> 21 22 #include <chrono> 23 #include <cstdint> 24 #include <functional> 25 #include <map> 26 #include <memory> 27 #include <mutex> 28 #include <set> 29 #include <utility> 30 31 #include "errno.h" 32 #include "stdio.h" 33 34 namespace rootcanal { 35 36 using TaskCallback = std::function<void(void)>; 37 using ReadCallback = std::function<void(int)>; 38 using CriticalCallback = std::function<void(void)>; 39 using AsyncTaskId = uint16_t; 40 using AsyncUserId = uint16_t; 41 constexpr uint16_t kInvalidTaskId = 0; 42 43 // Manages tasks that should be done in the future. It can watch file 44 // descriptors to call a given callback when it is certain that a non-blocking 45 // read is possible or can call a callback at a specific time (approximately) 46 // and (optionally) repeat the call periodically. 47 // The class is thread safe in the sense that all its member functions can be 48 // called simultaneously from different concurrent threads. The exception to 49 // this rule is the class destructor, which is unsafe to call concurrently with 50 // calls to other class member functions. This exception also has its own 51 // exception: it is safe to destroy the object even if some of its callbacks may 52 // call its member functions, because the destructor will make sure all callback 53 // calling threads are stopped before actually destroying anything. Callbacks 54 // that wait for file descriptor always run on the same thread, so there is no 55 // need of additional synchronization between them. The same applies to task 56 // callbacks since they also run on a thread of their own, however it is 57 // possible for a read callback and a task callback to execute at the same time 58 // (they are guaranteed to run in different threads) so synchronization is 59 // needed to access common state (other than the internal state of the 60 // AsyncManager class). While not required, it is strongly recommended to use 61 // the Synchronize(const CriticalCallback&) member function to execute code 62 // inside critical sections. Callbacks passed to this method on the same 63 // AsyncManager object from different threads are granted to *NOT* run 64 // concurrently. 65 class AsyncManager { 66 public: 67 // Starts watching a file descriptor in a separate thread. The 68 // on_read_fd_ready_callback() will be asynchronously called when it is 69 // guaranteed that a call to read() on the FD will not block. No promise is 70 // made about when in the future the callback will be called, in particular, 71 // it is perfectly possible to have it called before this function returns. A 72 // return of 0 means success, an error code is returned otherwise. 73 int WatchFdForNonBlockingReads(int file_descriptor, 74 const ReadCallback& on_read_fd_ready_callback); 75 76 // If the fd was not being watched before the call will be ignored. 77 void StopWatchingFileDescriptor(int file_descriptor); 78 79 // Get an identifier for the scheduler so that tasks can be cancelled per user 80 AsyncUserId GetNextUserId(); 81 82 // Schedules an action to occur in the future. Even if the delay given is not 83 // positive the callback will be called asynchronously. 84 AsyncTaskId ExecAsync(AsyncUserId user_id, std::chrono::milliseconds delay, 85 const TaskCallback& callback); 86 87 // Schedules an action to occur periodically in the future. If the delay given 88 // is not positive the callback will be asynchronously called once for each 89 // time in the past that it should have been called and then scheduled for 90 // future times. 91 AsyncTaskId ExecAsyncPeriodically(AsyncUserId user_id, 92 std::chrono::milliseconds delay, 93 std::chrono::milliseconds period, 94 const TaskCallback& callback); 95 96 // Cancels the/every future occurrence of the action specified by this id. 97 // The following invariants will hold: 98 // - The task will not be invoked after this method returns 99 // - If the task is currently running it will block until the task is 100 // completed, unless cancel is called from the running task. 101 bool CancelAsyncTask(AsyncTaskId async_task_id); 102 103 // Cancels the/every future occurrence of the action specified by this id. 104 // The following invariants will hold: 105 // - The task will not be invoked after this method returns 106 // - If the task is currently running it will block until the task is 107 // completed, unless cancel is called from the running task. 108 bool CancelAsyncTasksFromUser(AsyncUserId user_id); 109 110 // Execs the given code in a synchronized manner. It is guaranteed that code 111 // given on (possibly)concurrent calls to this member function on the same 112 // AsyncManager object will never be executed simultaneously. It is the 113 // class's user's responsibility to ensure that no calls to Synchronize are 114 // made from inside a CriticalCallback, since that would cause a lock to be 115 // acquired twice with unpredictable results. It is strongly recommended to 116 // have very simple CriticalCallbacks, preferably using lambda expressions. 117 void Synchronize(const CriticalCallback& critical_callback); 118 119 AsyncManager(); 120 AsyncManager(const AsyncManager&) = delete; 121 AsyncManager& operator=(const AsyncManager&) = delete; 122 123 ~AsyncManager(); 124 125 private: 126 // Implementation of the FD watching part of AsyncManager, extracted to its 127 // own class for clarity purposes. 128 class AsyncFdWatcher; 129 130 // Implementation of the asynchronous tasks part of AsyncManager, extracted to 131 // its own class for clarity purposes. 132 class AsyncTaskManager; 133 134 // Kept as pointers because we may want to support resetting either without 135 // destroying the other one 136 std::unique_ptr<AsyncFdWatcher> fdWatcher_p_; 137 std::unique_ptr<AsyncTaskManager> taskManager_p_; 138 }; 139 } // namespace rootcanal 140 #endif // TEST_VENDOR_LIB_ASYNC_MANAGER_H_ 141