1 /*
2  * Copyright (C) 2019 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 #pragma once
18 
19 #include <atomic>
20 #include <chrono>
21 #include <deque>
22 #include <functional>
23 #include <map>
24 #include <memory>
25 #include <mutex>
26 #include <optional>
27 #include <poll.h>
28 #include <string>
29 #include <string_view>
30 #include <thread>
31 #include <vector>
32 
33 #include <sys/select.h>
34 
35 struct MainRunLoop;
36 
37 struct RunLoop {
38     explicit RunLoop(std::string_view name);
39     ~RunLoop();
40 
41     static std::shared_ptr<RunLoop> main();
42 
43     // For public use on the main RunLoop only.
44     void stop();
45     void run();
46 
47     RunLoop(const RunLoop &) = delete;
48     RunLoop &operator=(const RunLoop &) = delete;
49 
50     typedef std::function<void()> AsyncFunction;
51     typedef int32_t Token;
52 
53     Token post(AsyncFunction fn);
54     // Post a callback to the run loop and wait for it to be executed. Returns
55     // whether it actually waited for the execution to happen (if posted from
56     // the same run loop's thread it won't wait to avoid a deadlock).
57     // WARNING: This function can cause the calling thread to wait forever if
58     // the run loop is stopped.
59     bool postAndAwait(AsyncFunction fn);
60 
61     Token postWithDelay(
62             std::chrono::steady_clock::duration delay, AsyncFunction fn);
63 
64     // Returns true iff matching event was cancelled.
65     bool cancelToken(Token token);
66 
67     void postSocketRecv(int sock, AsyncFunction fn);
68     void postSocketSend(int sock, AsyncFunction fn);
69     void cancelSocket(int sock);
70 
71     bool isCurrentThread() const;
72 
73 private:
74     friend struct MainRunLoop;
75 
76     struct QueueElem {
77         std::optional<std::chrono::steady_clock::time_point> mWhen;
78         AsyncFunction mFn;
79         Token mToken;
80 
81         bool operator<=(const QueueElem &other) const;
82     };
83 
84     struct SocketCallbacks {
85         AsyncFunction mRecvFn;
86         AsyncFunction mSendFn;
87         size_t mPollFdIndex;
88     };
89 
90     enum class InfoType {
91         RECV,
92         SEND,
93         CANCEL,
94     };
95 
96     struct AddSocketCallbackInfo {
97         int mSock;
98         InfoType mType;
99         AsyncFunction mFn;
100     };
101 
102     std::string mName;
103 
104     int mControlFds[2];
105 
106     std::mutex mLock;
107     std::deque<QueueElem> mQueue;
108     std::vector<AddSocketCallbackInfo> mAddInfos;
109 
110     std::atomic<bool> mDone;
111     std::thread mThread;
112     pthread_t mPThread;
113 
114     std::atomic<Token> mNextToken;
115 
116     explicit RunLoop();  // constructor for the main RunLoop.
117 
118     void interrupt();
119     void insert(const QueueElem &elem);
120     void addPollFd_l(int sock);
121 };
122 
123