void EventHandler::ensureNotRegistered(const char* fn) { // Neither the EventBase nor file descriptor may be changed while the // handler is registered. Treat it as a programmer bug and abort the program // if this requirement is violated. if (isHandlerRegistered()) { LOG(ERROR) << fn << " called on registered handler; aborting"; abort(); } }
void EventHandler::attachEventBase(EventBase* eventBase) { // attachEventBase() may only be called on detached handlers assert(event_.ev_base == nullptr); assert(!isHandlerRegistered()); // This must be invoked from the EventBase's thread assert(eventBase->isInEventBaseThread()); setEventBase(eventBase); }
void AsyncPipeWriter::closeOnEmpty() { VLOG(5) << "close on empty"; if (queue_.empty()) { closeNow(); } else { closeOnEmpty_ = true; CHECK(isHandlerRegistered()); } }
bool EventHandler::registerImpl(uint16_t events, bool internal) { assert(event_.ev_base != nullptr); // We have to unregister the event before we can change the event flags if (isHandlerRegistered()) { // If the new events are the same are the same as the already registered // flags, we don't have to do anything. Just return. auto flags = event_ref_flags(&event_); if (events == event_.ev_events && static_cast<bool>(flags & EVLIST_INTERNAL) == internal) { return true; } event_del(&event_); } // Update the event flags // Unfortunately, event_set() resets the event_base, so we have to remember // it before hand, then pass it back into event_base_set() afterwards struct event_base* evb = event_.ev_base; event_set(&event_, event_.ev_fd, events, &EventHandler::libeventCallback, this); event_base_set(evb, &event_); // Set EVLIST_INTERNAL if this is an internal event if (internal) { event_ref_flags(&event_) |= EVLIST_INTERNAL; } // Add the event. // // Although libevent allows events to wait on both I/O and a timeout, // we intentionally don't allow an EventHandler to also use a timeout. // Callers must maintain a separate AsyncTimeout object if they want a // timeout. // // Otherwise, it is difficult to handle persistent events properly. (The I/O // event and timeout may both fire together the same time around the event // loop. Normally we would want to inform the caller of the I/O event first, // then the timeout. However, it is difficult to do this properly since the // I/O callback could delete the EventHandler.) Additionally, if a caller // uses the same struct event for both I/O and timeout, and they just want to // reschedule the timeout, libevent currently makes an epoll_ctl() call even // if the I/O event flags haven't changed. Using a separate event struct is // therefore slightly more efficient in this case (although it does take up // more space). if (event_add(&event_, nullptr) < 0) { LOG(ERROR) << "EventBase: failed to register event handler for fd " << event_.ev_fd << ": " << strerror(errno); // Call event_del() to make sure the event is completely uninstalled event_del(&event_); return false; } return true; }
void AsyncPipeWriter::write(unique_ptr<folly::IOBuf> buf, AsyncWriter::WriteCallback* callback) { if (closed()) { if (callback) { AsyncSocketException ex(AsyncSocketException::NOT_OPEN, "attempt to write to closed pipe"); callback->writeErr(0, ex); } return; } bool wasEmpty = (queue_.empty()); folly::IOBufQueue iobq; iobq.append(std::move(buf)); std::pair<folly::IOBufQueue, AsyncWriter::WriteCallback*> p( std::move(iobq), callback); queue_.emplace_back(std::move(p)); if (wasEmpty) { handleWrite(); } else { CHECK(!queue_.empty()); CHECK(isHandlerRegistered()); } }
void EventHandler::unregisterHandler() { if (isHandlerRegistered()) { event_del(&event_); } }
void TunIntf::start() { if (fd_ != -1 && !isHandlerRegistered()) { changeHandlerFD(fd_); registerHandler(TEventHandler::READ|TEventHandler::PERSIST); } }