• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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