2 * Copyright 2004-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/io/async/EventHandler.h>
18 #include <folly/io/async/EventBase.h>
24 EventHandler::EventHandler(EventBase* eventBase, int fd) {
25 folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
26 if (eventBase != nullptr) {
27 setEventBase(eventBase);
29 // Callers must set the EventBase and fd before using this timeout.
30 // Set event_->ev_base to nullptr to ensure that this happens.
31 // (otherwise libevent will initialize it to the "default" event_base)
32 event_.ev_base = nullptr;
37 EventHandler::~EventHandler() {
41 bool EventHandler::registerImpl(uint16_t events, bool internal) {
42 assert(event_.ev_base != nullptr);
44 // We have to unregister the event before we can change the event flags
45 if (isHandlerRegistered()) {
46 // If the new events are the same are the same as the already registered
47 // flags, we don't have to do anything. Just return.
48 auto flags = event_ref_flags(&event_);
49 if (events == event_.ev_events &&
50 static_cast<bool>(flags & EVLIST_INTERNAL) == internal) {
57 // Update the event flags
58 // Unfortunately, event_set() resets the event_base, so we have to remember
59 // it before hand, then pass it back into event_base_set() afterwards
60 struct event_base* evb = event_.ev_base;
65 &EventHandler::libeventCallback,
67 event_base_set(evb, &event_);
69 // Set EVLIST_INTERNAL if this is an internal event
71 event_ref_flags(&event_) |= EVLIST_INTERNAL;
76 // Although libevent allows events to wait on both I/O and a timeout,
77 // we intentionally don't allow an EventHandler to also use a timeout.
78 // Callers must maintain a separate AsyncTimeout object if they want a
81 // Otherwise, it is difficult to handle persistent events properly. (The I/O
82 // event and timeout may both fire together the same time around the event
83 // loop. Normally we would want to inform the caller of the I/O event first,
84 // then the timeout. However, it is difficult to do this properly since the
85 // I/O callback could delete the EventHandler.) Additionally, if a caller
86 // uses the same struct event for both I/O and timeout, and they just want to
87 // reschedule the timeout, libevent currently makes an epoll_ctl() call even
88 // if the I/O event flags haven't changed. Using a separate event struct is
89 // therefore slightly more efficient in this case (although it does take up
91 if (event_add(&event_, nullptr) < 0) {
92 LOG(ERROR) << "EventBase: failed to register event handler for fd "
93 << event_.ev_fd << ": " << strerror(errno);
94 // Call event_del() to make sure the event is completely uninstalled
102 void EventHandler::unregisterHandler() {
103 if (isHandlerRegistered()) {
108 void EventHandler::attachEventBase(EventBase* eventBase) {
109 // attachEventBase() may only be called on detached handlers
110 assert(event_.ev_base == nullptr);
111 assert(!isHandlerRegistered());
112 // This must be invoked from the EventBase's thread
113 assert(eventBase->isInEventBaseThread());
115 setEventBase(eventBase);
118 void EventHandler::detachEventBase() {
119 ensureNotRegistered(__func__);
120 event_.ev_base = nullptr;
123 void EventHandler::changeHandlerFD(int fd) {
124 ensureNotRegistered(__func__);
125 // event_set() resets event_base.ev_base, so manually restore it afterwards
126 struct event_base* evb = event_.ev_base;
127 folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
128 event_.ev_base = evb; // don't use event_base_set(), since evb may be nullptr
131 void EventHandler::initHandler(EventBase* eventBase, int fd) {
132 ensureNotRegistered(__func__);
133 folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
134 setEventBase(eventBase);
137 void EventHandler::ensureNotRegistered(const char* fn) {
138 // Neither the EventBase nor file descriptor may be changed while the
139 // handler is registered. Treat it as a programmer bug and abort the program
140 // if this requirement is violated.
141 if (isHandlerRegistered()) {
142 LOG(ERROR) << fn << " called on registered handler; aborting";
147 void EventHandler::libeventCallback(libevent_fd_t fd, short events, void* arg) {
148 EventHandler* handler = reinterpret_cast<EventHandler*>(arg);
149 assert(fd == handler->event_.ev_fd);
150 (void)fd; // prevent unused variable warnings
152 auto observer = handler->eventBase_->getExecutionObserver();
154 observer->starting(reinterpret_cast<uintptr_t>(handler));
157 // this can't possibly fire if handler->eventBase_ is nullptr
158 handler->eventBase_->bumpHandlingTime();
160 handler->handlerReady(uint16_t(events));
163 observer->stopped(reinterpret_cast<uintptr_t>(handler));
167 void EventHandler::setEventBase(EventBase* eventBase) {
168 event_base_set(eventBase->getLibeventBase(), &event_);
169 eventBase_ = eventBase;
172 bool EventHandler::isPending() const {
173 if (event_ref_flags(&event_) & EVLIST_ACTIVE) {
174 if (event_.ev_res & EV_READ) {