Home | History | Annotate | Download | only in simpleperf
      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