1 /*
2 * Copyright (C) 2016 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 #include "IOEventLoop.h"
18
19 #include <event2/event.h>
20 #include <fcntl.h>
21
22 #include <android-base/logging.h>
23
24 struct IOEvent {
25 IOEventLoop* loop;
26 event* e;
27 std::function<bool()> callback;
28 bool enabled;
29
IOEventIOEvent30 IOEvent(IOEventLoop* loop, const std::function<bool()>& callback)
31 : loop(loop), e(nullptr), callback(callback), enabled(false) {}
32
~IOEventIOEvent33 ~IOEvent() {
34 if (e != nullptr) {
35 event_free(e);
36 }
37 }
38 };
39
IOEventLoop()40 IOEventLoop::IOEventLoop() : ebase_(nullptr), has_error_(false), use_precise_timer_(false) {}
41
~IOEventLoop()42 IOEventLoop::~IOEventLoop() {
43 events_.clear();
44 if (ebase_ != nullptr) {
45 event_base_free(ebase_);
46 }
47 }
48
UsePreciseTimer()49 bool IOEventLoop::UsePreciseTimer() {
50 if (ebase_ != nullptr) {
51 return false; // Too late to set the flag.
52 }
53 use_precise_timer_ = true;
54 return true;
55 }
56
EnsureInit()57 bool IOEventLoop::EnsureInit() {
58 if (ebase_ == nullptr) {
59 event_config* cfg = event_config_new();
60 if (cfg != nullptr) {
61 if (use_precise_timer_) {
62 event_config_set_flag(cfg, EVENT_BASE_FLAG_PRECISE_TIMER);
63 }
64 ebase_ = event_base_new_with_config(cfg);
65 event_config_free(cfg);
66 }
67 if (ebase_ == nullptr) {
68 LOG(ERROR) << "failed to create event_base";
69 return false;
70 }
71 }
72 return true;
73 }
74
EventCallbackFn(int,short,void * arg)75 void IOEventLoop::EventCallbackFn(int, short, void* arg) {
76 IOEvent* e = static_cast<IOEvent*>(arg);
77 if (!e->callback()) {
78 e->loop->has_error_ = true;
79 e->loop->ExitLoop();
80 }
81 }
82
MakeFdNonBlocking(int fd)83 static bool MakeFdNonBlocking(int fd) {
84 int flags = fcntl(fd, F_GETFL, 0);
85 if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
86 PLOG(ERROR) << "fcntl() failed";
87 return false;
88 }
89 return true;
90 }
91
AddReadEvent(int fd,const std::function<bool ()> & callback)92 IOEventRef IOEventLoop::AddReadEvent(int fd,
93 const std::function<bool()>& callback) {
94 if (!MakeFdNonBlocking(fd)) {
95 return nullptr;
96 }
97 return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback);
98 }
99
AddWriteEvent(int fd,const std::function<bool ()> & callback)100 IOEventRef IOEventLoop::AddWriteEvent(int fd,
101 const std::function<bool()>& callback) {
102 if (!MakeFdNonBlocking(fd)) {
103 return nullptr;
104 }
105 return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback);
106 }
107
AddSignalEvent(int sig,const std::function<bool ()> & callback)108 bool IOEventLoop::AddSignalEvent(int sig,
109 const std::function<bool()>& callback) {
110 return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback) != nullptr;
111 }
112
AddSignalEvents(std::vector<int> sigs,const std::function<bool ()> & callback)113 bool IOEventLoop::AddSignalEvents(std::vector<int> sigs,
114 const std::function<bool()>& callback) {
115 for (auto sig : sigs) {
116 if (!AddSignalEvent(sig, callback)) {
117 return false;
118 }
119 }
120 return true;
121 }
122
AddPeriodicEvent(timeval duration,const std::function<bool ()> & callback)123 bool IOEventLoop::AddPeriodicEvent(timeval duration,
124 const std::function<bool()>& callback) {
125 return AddEvent(-1, EV_PERSIST, &duration, callback) != nullptr;
126 }
127
AddEvent(int fd_or_sig,short events,timeval * timeout,const std::function<bool ()> & callback)128 IOEventRef IOEventLoop::AddEvent(int fd_or_sig, short events, timeval* timeout,
129 const std::function<bool()>& callback) {
130 if (!EnsureInit()) {
131 return nullptr;
132 }
133 std::unique_ptr<IOEvent> e(new IOEvent(this, callback));
134 e->e = event_new(ebase_, fd_or_sig, events, EventCallbackFn, e.get());
135 if (e->e == nullptr) {
136 LOG(ERROR) << "event_new() failed";
137 return nullptr;
138 }
139 if (event_add(e->e, timeout) != 0) {
140 LOG(ERROR) << "event_add() failed";
141 return nullptr;
142 }
143 e->enabled = true;
144 events_.push_back(std::move(e));
145 return events_.back().get();
146 }
147
RunLoop()148 bool IOEventLoop::RunLoop() {
149 if (event_base_dispatch(ebase_) == -1) {
150 LOG(ERROR) << "event_base_dispatch() failed";
151 return false;
152 }
153 if (has_error_) {
154 return false;
155 }
156 return true;
157 }
158
ExitLoop()159 bool IOEventLoop::ExitLoop() {
160 if (event_base_loopbreak(ebase_) == -1) {
161 LOG(ERROR) << "event_base_loopbreak() failed";
162 return false;
163 }
164 return true;
165 }
166
DisableEvent(IOEventRef ref)167 bool IOEventLoop::DisableEvent(IOEventRef ref) {
168 if (ref->enabled) {
169 if (event_del(ref->e) != 0) {
170 LOG(ERROR) << "event_del() failed";
171 return false;
172 }
173 ref->enabled = false;
174 }
175 return true;
176 }
177
EnableEvent(IOEventRef ref)178 bool IOEventLoop::EnableEvent(IOEventRef ref) {
179 if (!ref->enabled) {
180 if (event_add(ref->e, nullptr) != 0) {
181 LOG(ERROR) << "event_add() failed";
182 return false;
183 }
184 ref->enabled = true;
185 }
186 return true;
187 }
188
DelEvent(IOEventRef ref)189 bool IOEventLoop::DelEvent(IOEventRef ref) {
190 DisableEvent(ref);
191 IOEventLoop* loop = ref->loop;
192 for (auto it = loop->events_.begin(); it != loop->events_.end(); ++it) {
193 if (it->get() == ref) {
194 loop->events_.erase(it);
195 break;
196 }
197 }
198 return true;
199 }
200