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) {} 41 42 IOEventLoop::~IOEventLoop() { 43 events_.clear(); 44 if (ebase_ != nullptr) { 45 event_base_free(ebase_); 46 } 47 } 48 49 bool IOEventLoop::EnsureInit() { 50 if (ebase_ == nullptr) { 51 ebase_ = event_base_new(); 52 if (ebase_ == nullptr) { 53 LOG(ERROR) << "failed to call event_base_new()"; 54 return false; 55 } 56 } 57 return true; 58 } 59 60 void IOEventLoop::EventCallbackFn(int, short, void* arg) { 61 IOEvent* e = static_cast<IOEvent*>(arg); 62 if (!e->callback()) { 63 e->loop->has_error_ = true; 64 e->loop->ExitLoop(); 65 } 66 } 67 68 static bool MakeFdNonBlocking(int fd) { 69 int flags = fcntl(fd, F_GETFL, 0); 70 if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 71 PLOG(ERROR) << "fcntl() failed"; 72 return false; 73 } 74 return true; 75 } 76 77 IOEventRef IOEventLoop::AddReadEvent(int fd, 78 const std::function<bool()>& callback) { 79 if (!MakeFdNonBlocking(fd)) { 80 return nullptr; 81 } 82 return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback); 83 } 84 85 IOEventRef IOEventLoop::AddWriteEvent(int fd, 86 const std::function<bool()>& callback) { 87 if (!MakeFdNonBlocking(fd)) { 88 return nullptr; 89 } 90 return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback); 91 } 92 93 bool IOEventLoop::AddSignalEvent(int sig, 94 const std::function<bool()>& callback) { 95 return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback) != nullptr; 96 } 97 98 bool IOEventLoop::AddSignalEvents(std::vector<int> sigs, 99 const std::function<bool()>& callback) { 100 for (auto sig : sigs) { 101 if (!AddSignalEvent(sig, callback)) { 102 return false; 103 } 104 } 105 return true; 106 } 107 108 bool IOEventLoop::AddPeriodicEvent(timeval duration, 109 const std::function<bool()>& callback) { 110 return AddEvent(-1, EV_PERSIST, &duration, callback) != nullptr; 111 } 112 113 IOEventRef IOEventLoop::AddEvent(int fd_or_sig, short events, timeval* timeout, 114 const std::function<bool()>& callback) { 115 if (!EnsureInit()) { 116 return nullptr; 117 } 118 std::unique_ptr<IOEvent> e(new IOEvent(this, callback)); 119 e->e = event_new(ebase_, fd_or_sig, events, EventCallbackFn, e.get()); 120 if (e->e == nullptr) { 121 LOG(ERROR) << "event_new() failed"; 122 return nullptr; 123 } 124 if (event_add(e->e, timeout) != 0) { 125 LOG(ERROR) << "event_add() failed"; 126 return nullptr; 127 } 128 e->enabled = true; 129 events_.push_back(std::move(e)); 130 return events_.back().get(); 131 } 132 133 bool IOEventLoop::RunLoop() { 134 if (event_base_dispatch(ebase_) == -1) { 135 LOG(ERROR) << "event_base_dispatch() failed"; 136 return false; 137 } 138 if (has_error_) { 139 return false; 140 } 141 return true; 142 } 143 144 bool IOEventLoop::ExitLoop() { 145 if (event_base_loopbreak(ebase_) == -1) { 146 LOG(ERROR) << "event_base_loopbreak() failed"; 147 return false; 148 } 149 return true; 150 } 151 152 bool IOEventLoop::DisableEvent(IOEventRef ref) { 153 if (ref->enabled) { 154 if (event_del(ref->e) != 0) { 155 LOG(ERROR) << "event_del() failed"; 156 return false; 157 } 158 ref->enabled = false; 159 } 160 return true; 161 } 162 163 bool IOEventLoop::EnableEvent(IOEventRef ref) { 164 if (!ref->enabled) { 165 if (event_add(ref->e, nullptr) != 0) { 166 LOG(ERROR) << "event_add() failed"; 167 return false; 168 } 169 ref->enabled = true; 170 } 171 return true; 172 } 173 174 bool IOEventLoop::DelEvent(IOEventRef ref) { 175 DisableEvent(ref); 176 IOEventLoop* loop = ref->loop; 177 for (auto it = loop->events_.begin(); it != loop->events_.end(); ++it) { 178 if (it->get() == ref) { 179 loop->events_.erase(it); 180 break; 181 } 182 } 183 return true; 184 } 185