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 30 IOEvent(IOEventLoop* loop, const std::function<bool()>& callback) 31 : loop(loop), e(nullptr), callback(callback), enabled(false) {} 32 33 ~IOEvent() { 34 if (e != nullptr) { 35 event_free(e); 36 } 37 } 38 }; 39 40 IOEventLoop::IOEventLoop() : ebase_(nullptr), has_error_(false), use_precise_timer_(false) {} 41 42 IOEventLoop::~IOEventLoop() { 43 events_.clear(); 44 if (ebase_ != nullptr) { 45 event_base_free(ebase_); 46 } 47 } 48 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 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 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 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 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 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 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 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 123 bool IOEventLoop::AddPeriodicEvent(timeval duration, 124 const std::function<bool()>& callback) { 125 return AddEvent(-1, EV_PERSIST, &duration, callback) != nullptr; 126 } 127 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 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 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 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 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 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