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