1 /*
2  * Copyright (C) 2006 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 __FDEVENT_H
18 #define __FDEVENT_H
19 
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include <atomic>
24 #include <chrono>
25 #include <deque>
26 #include <functional>
27 #include <mutex>
28 #include <optional>
29 #include <unordered_map>
30 #include <variant>
31 
32 #include <android-base/thread_annotations.h>
33 
34 #include "adb_unique_fd.h"
35 
36 // Events that may be observed
37 #define FDE_READ 0x0001
38 #define FDE_WRITE 0x0002
39 #define FDE_ERROR 0x0004
40 #define FDE_TIMEOUT 0x0008
41 
42 struct fdevent;
43 
44 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
45 typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
46 
47 void invoke_fde(struct fdevent* fde, unsigned events);
48 std::string dump_fde(const fdevent* fde);
49 
50 struct fdevent_event {
51     fdevent* fde;
52     unsigned events;
53 };
54 
55 struct fdevent final {
56     uint64_t id;
57 
58     unique_fd fd;
59     int force_eof = 0;
60 
61     uint16_t state = 0;
62     std::optional<std::chrono::milliseconds> timeout;
63     std::chrono::steady_clock::time_point last_active;
64 
65     std::variant<fd_func, fd_func2> func;
66     void* arg = nullptr;
67 };
68 
69 struct fdevent_context {
70   public:
71     virtual ~fdevent_context() = default;
72 
73     // Allocate and initialize a new fdevent object.
74     fdevent* Create(unique_fd fd, std::variant<fd_func, fd_func2> func, void* arg);
75 
76     // Deallocate an fdevent object, returning the file descriptor that was owned by it.
77     // Note that this calls Set, which is a virtual method, so destructors that call this must be
78     // final.
79     unique_fd Destroy(fdevent* fde);
80 
81   protected:
82     virtual void Register(fdevent*) = 0;
83     virtual void Unregister(fdevent*) = 0;
84 
85   public:
86     // Change which events should cause notifications.
87     virtual void Set(fdevent* fde, unsigned events) = 0;
88     void Add(fdevent* fde, unsigned events);
89     void Del(fdevent* fde, unsigned events);
90 
91     // Set a timeout on an fdevent.
92     // If no events are triggered by the timeout, an FDE_TIMEOUT will be generated.
93     // Note timeouts are not defused automatically; if a timeout is set on an fdevent, it will
94     // trigger repeatedly every |timeout| ms.
95     void SetTimeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
96 
97   protected:
98     std::optional<std::chrono::milliseconds> CalculatePollDuration();
99     void HandleEvents(const std::vector<fdevent_event>& events);
100 
101   private:
102     // Run all pending functions enqueued via Run().
103     void FlushRunQueue() EXCLUDES(run_queue_mutex_);
104 
105   public:
106     // Loop until TerminateLoop is called, handling events.
107     // Implementations should call FlushRunQueue on every iteration, and check the value of
108     // terminate_loop_ to determine whether to stop.
109     virtual void Loop() = 0;
110 
111     // Assert that the caller is either running on the context's main thread, or that there is no
112     // active main thread.
113     void CheckMainThread();
114 
115     // Queue an operation to be run on the main thread.
116     void Run(std::function<void()> fn);
117 
118     // Test-only functionality:
119     void TerminateLoop();
120     virtual size_t InstalledCount() = 0;
121 
122   protected:
123     // Interrupt the run loop.
124     virtual void Interrupt() = 0;
125 
126     std::optional<uint64_t> main_thread_id_ = std::nullopt;
127     std::atomic<bool> terminate_loop_ = false;
128 
129   protected:
130     std::unordered_map<int, fdevent> installed_fdevents_;
131 
132   private:
133     uint64_t fdevent_id_ = 0;
134     std::mutex run_queue_mutex_;
135     std::deque<std::function<void()>> run_queue_ GUARDED_BY(run_queue_mutex_);
136 };
137 
138 // Backwards compatibility shims that forward to the global fdevent_context.
139 fdevent* fdevent_create(int fd, fd_func func, void* arg);
140 fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
141 
142 unique_fd fdevent_release(fdevent* fde);
143 void fdevent_destroy(fdevent* fde);
144 
145 void fdevent_set(fdevent *fde, unsigned events);
146 void fdevent_add(fdevent *fde, unsigned events);
147 void fdevent_del(fdevent *fde, unsigned events);
148 void fdevent_set_timeout(fdevent* fde, std::optional<std::chrono::milliseconds> timeout);
149 void fdevent_loop();
150 void check_main_thread();
151 
152 // Queue an operation to run on the main thread.
153 void fdevent_run_on_main_thread(std::function<void()> fn);
154 
155 // The following functions are used only for tests.
156 void fdevent_terminate_loop();
157 size_t fdevent_installed_count();
158 void fdevent_reset();
159 
160 #endif
161