Example #1
0
EventBase::~EventBase() {
  // Delete any unfired CobTimeout objects, so that we don't leak memory
  // (Note that we don't fire them.  The caller is responsible for cleaning up
  // its own data structures if it destroys the EventBase with unfired events
  // remaining.)
  while (!pendingCobTimeouts_.empty()) {
    CobTimeout* timeout = &pendingCobTimeouts_.front();
    delete timeout;
  }

  (void) runLoopCallbacks(false);

  // Stop consumer before deleting NotificationQueue
  fnRunner_->stopConsuming();
  event_base_free(evb_);
  VLOG(5) << "EventBase(): Destroyed.";
}
Example #2
0
// enters the event_base loop -- will only exit when forced to
bool EventBase::loop() {
  VLOG(5) << "EventBase(): Starting loop.";
  int res = 0;
  bool ranLoopCallbacks;
  int nonBlocking;

  loopThread_.store(pthread_self(), std::memory_order_release);

#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 12)
  if (!name_.empty()) {
    pthread_setname_np(pthread_self(), name_.c_str());
  }
#endif

  int64_t prev = std::chrono::duration_cast<std::chrono::milliseconds>(
    std::chrono::steady_clock::now().time_since_epoch()).count();
  int64_t idleStart = std::chrono::duration_cast<std::chrono::microseconds>(
    std::chrono::steady_clock::now().time_since_epoch()).count();

  // TODO: Read stop_ atomically with an acquire barrier.
  while (!stop_) {
    ++nextLoopCnt_;

    // nobody can add loop callbacks from within this thread if
    // we don't have to handle anything to start with...
    nonBlocking = (loopCallbacks_.empty() ? 0 : EVLOOP_NONBLOCK);
    res = event_base_loop(evb_, EVLOOP_ONCE | nonBlocking);
    ranLoopCallbacks = runLoopCallbacks();

    int64_t busy = std::chrono::duration_cast<std::chrono::microseconds>(
      std::chrono::steady_clock::now().time_since_epoch()).count() - startWork_;
    int64_t idle = startWork_ - idleStart;

    avgLoopTime_.addSample(idle, busy);
    maxLatencyLoopTime_.addSample(idle, busy);

    if (observer_) {
      if (observerSampleCount_++ == observer_->getSampleRate()) {
        observerSampleCount_ = 0;
        observer_->loopSample(busy, idle);
      }
    }

    VLOG(11) << "EventBase " << this         << " did not timeout "
     " loop time guess: "    << busy + idle  <<
     " idle time: "          << idle         <<
     " busy time: "          << busy         <<
     " avgLoopTime: "        << avgLoopTime_.get() <<
     " maxLatencyLoopTime: " << maxLatencyLoopTime_.get() <<
     " maxLatency_: "        << maxLatency_ <<
     " nothingHandledYet(): "<< nothingHandledYet();

    // see if our average loop time has exceeded our limit
    if ((maxLatency_ > 0) &&
        (maxLatencyLoopTime_.get() > double(maxLatency_))) {
      maxLatencyCob_();
      // back off temporarily -- don't keep spamming maxLatencyCob_
      // if we're only a bit over the limit
      maxLatencyLoopTime_.dampen(0.9);
    }

    // Our loop run did real work; reset the idle timer
    idleStart = std::chrono::duration_cast<std::chrono::microseconds>(
      std::chrono::steady_clock::now().time_since_epoch()).count();

    // If the event loop indicate that there were no more events, and
    // we also didn't have any loop callbacks to run, there is nothing left to
    // do.
    if (res != 0 && !ranLoopCallbacks) {
      // Since Notification Queue is marked 'internal' some events may not have
      // run.  Run them manually if so, and continue looping.
      //
      if (getNotificationQueueSize() > 0) {
        fnRunner_->handlerReady(0);
      } else {
        break;
      }
    }

    VLOG(5) << "EventBase " << this << " loop time: " << getTimeDelta(&prev);
  }
  // Reset stop_ so loop() can be called again
  stop_ = false;

  if (res < 0) {
    LOG(ERROR) << "EventBase: -- error in event loop, res = " << res;
    return false;
  } else if (res == 1) {
    VLOG(5) << "EventBase: ran out of events (exiting loop)!";
  } else if (res > 1) {
    LOG(ERROR) << "EventBase: unknown event loop result = " << res;
    return false;
  }

  loopThread_.store(0, std::memory_order_release);

  VLOG(5) << "EventBase(): Done with loop.";
  return true;
}
Example #3
0
bool EventBase::loopBody(int flags) {
    VLOG(5) << "EventBase(): Starting loop.";

    DCHECK(!invokingLoop_)
            << "Your code just tried to loop over an event base from inside another "
            << "event base loop. Since libevent is not reentrant, this leads to "
            << "undefined behavior in opt builds. Please fix immediately. For the "
            << "common case of an inner function that needs to do some synchronous "
            << "computation on an event-base, replace getEventBase() by a new, "
            << "stack-allocated EvenBase.";
    invokingLoop_ = true;
    SCOPE_EXIT {
        invokingLoop_ = false;
    };

    int res = 0;
    bool ranLoopCallbacks;
    bool blocking = !(flags & EVLOOP_NONBLOCK);
    bool once = (flags & EVLOOP_ONCE);

    // time-measurement variables.
    std::chrono::steady_clock::time_point prev;
    int64_t idleStart = 0;
    int64_t busy;
    int64_t idle;

    loopThread_.store(pthread_self(), std::memory_order_release);

    if (!name_.empty()) {
        setThreadName(name_);
    }

    if (enableTimeMeasurement_) {
        prev = std::chrono::steady_clock::now();
        idleStart = std::chrono::duration_cast<std::chrono::microseconds>(
                        std::chrono::steady_clock::now().time_since_epoch()).count();
    }

    while (!stop_.load(std::memory_order_acquire)) {
        applyLoopKeepAlive();
        ++nextLoopCnt_;

        // Run the before loop callbacks
        LoopCallbackList callbacks;
        callbacks.swap(runBeforeLoopCallbacks_);

        while(!callbacks.empty()) {
            auto* item = &callbacks.front();
            callbacks.pop_front();
            item->runLoopCallback();
        }

        // nobody can add loop callbacks from within this thread if
        // we don't have to handle anything to start with...
        if (blocking && loopCallbacks_.empty()) {
            res = event_base_loop(evb_, EVLOOP_ONCE);
        } else {
            res = event_base_loop(evb_, EVLOOP_ONCE | EVLOOP_NONBLOCK);
        }

        ranLoopCallbacks = runLoopCallbacks();

        if (enableTimeMeasurement_) {
            busy = std::chrono::duration_cast<std::chrono::microseconds>(
                       std::chrono::steady_clock::now().time_since_epoch()).count() -
                   startWork_;
            idle = startWork_ - idleStart;

            avgLoopTime_.addSample(idle, busy);
            maxLatencyLoopTime_.addSample(idle, busy);

            if (observer_) {
                if (observerSampleCount_++ == observer_->getSampleRate()) {
                    observerSampleCount_ = 0;
                    observer_->loopSample(busy, idle);
                }
            }

            VLOG(11) << "EventBase "  << this         << " did not timeout "
                     " loop time guess: "    << busy + idle  <<
                     " idle time: "          << idle         <<
                     " busy time: "          << busy         <<
                     " avgLoopTime: "        << avgLoopTime_.get() <<
                     " maxLatencyLoopTime: " << maxLatencyLoopTime_.get() <<
                     " maxLatency_: "        << maxLatency_ <<
                     " notificationQueueSize: " << getNotificationQueueSize() <<
                     " nothingHandledYet(): "<< nothingHandledYet();

            // see if our average loop time has exceeded our limit
            if ((maxLatency_ > 0) &&
                    (maxLatencyLoopTime_.get() > double(maxLatency_))) {
                maxLatencyCob_();
                // back off temporarily -- don't keep spamming maxLatencyCob_
                // if we're only a bit over the limit
                maxLatencyLoopTime_.dampen(0.9);
            }

            // Our loop run did real work; reset the idle timer
            idleStart = std::chrono::duration_cast<std::chrono::microseconds>(
                            std::chrono::steady_clock::now().time_since_epoch()).count();
        } else {
            VLOG(11) << "EventBase " << this << " did not timeout";
        }

        // If the event loop indicate that there were no more events, and
        // we also didn't have any loop callbacks to run, there is nothing left to
        // do.
        if (res != 0 && !ranLoopCallbacks) {
            // Since Notification Queue is marked 'internal' some events may not have
            // run.  Run them manually if so, and continue looping.
            //
            if (getNotificationQueueSize() > 0) {
                fnRunner_->handlerReady(0);
            } else {
                break;
            }
        }

        if (enableTimeMeasurement_) {
            VLOG(5) << "EventBase " << this << " loop time: " <<
                    getTimeDelta(&prev).count();
        }

        if (once) {
            break;
        }
    }
    // Reset stop_ so loop() can be called again
    stop_ = false;

    if (res < 0) {
        LOG(ERROR) << "EventBase: -- error in event loop, res = " << res;
        return false;
    } else if (res == 1) {
        VLOG(5) << "EventBase: ran out of events (exiting loop)!";
    } else if (res > 1) {
        LOG(ERROR) << "EventBase: unknown event loop result = " << res;
        return false;
    }

    loopThread_.store({}, std::memory_order_release);

    VLOG(5) << "EventBase(): Done with loop.";
    return true;
}