2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
19 #include <folly/io/async/EventHandler.h>
20 #include <folly/io/async/EventBase.h>
26 EventHandler::EventHandler(EventBase* eventBase, int fd) {
27 event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
28 if (eventBase != nullptr) {
29 setEventBase(eventBase);
31 // Callers must set the EventBase and fd before using this timeout.
32 // Set event_->ev_base to nullptr to ensure that this happens.
33 // (otherwise libevent will initialize it to the "default" event_base)
34 event_.ev_base = nullptr;
39 EventHandler::~EventHandler() {
43 bool EventHandler::registerImpl(uint16_t events, bool internal) {
44 assert(event_.ev_base != nullptr);
46 // We have to unregister the event before we can change the event flags
47 if (isHandlerRegistered()) {
48 // If the new events are the same are the same as the already registered
49 // flags, we don't have to do anything. Just return.
50 if (events == event_.ev_events &&
51 static_cast<bool>(event_.ev_flags & EVLIST_INTERNAL) == internal) {
58 // Update the event flags
59 // Unfortunately, event_set() resets the event_base, so we have to remember
60 // it before hand, then pass it back into event_base_set() afterwards
61 struct event_base* evb = event_.ev_base;
62 event_set(&event_, event_.ev_fd, events,
63 &EventHandler::libeventCallback, this);
64 event_base_set(evb, &event_);
66 // Set EVLIST_INTERNAL if this is an internal event
68 event_.ev_flags |= EVLIST_INTERNAL;
73 // Although libevent allows events to wait on both I/O and a timeout,
74 // we intentionally don't allow an EventHandler to also use a timeout.
75 // Callers must maintain a separate AsyncTimeout object if they want a
78 // Otherwise, it is difficult to handle persistent events properly. (The I/O
79 // event and timeout may both fire together the same time around the event
80 // loop. Normally we would want to inform the caller of the I/O event first,
81 // then the timeout. However, it is difficult to do this properly since the
82 // I/O callback could delete the EventHandler.) Additionally, if a caller
83 // uses the same struct event for both I/O and timeout, and they just want to
84 // reschedule the timeout, libevent currently makes an epoll_ctl() call even
85 // if the I/O event flags haven't changed. Using a separate event struct is
86 // therefore slightly more efficient in this case (although it does take up
88 if (event_add(&event_, nullptr) < 0) {
89 LOG(ERROR) << "EventBase: failed to register event handler for fd "
90 << event_.ev_fd << ": " << strerror(errno);
91 // Call event_del() to make sure the event is completely uninstalled
99 void EventHandler::unregisterHandler() {
100 if (isHandlerRegistered()) {
105 void EventHandler::attachEventBase(EventBase* eventBase) {
106 // attachEventBase() may only be called on detached handlers
107 assert(event_.ev_base == nullptr);
108 assert(!isHandlerRegistered());
109 // This must be invoked from the EventBase's thread
110 assert(eventBase->isInEventBaseThread());
112 setEventBase(eventBase);
115 void EventHandler::detachEventBase() {
116 ensureNotRegistered(__func__);
117 event_.ev_base = nullptr;
120 void EventHandler::changeHandlerFD(int fd) {
121 ensureNotRegistered(__func__);
122 // event_set() resets event_base.ev_base, so manually restore it afterwards
123 struct event_base* evb = event_.ev_base;
124 event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
125 event_.ev_base = evb; // don't use event_base_set(), since evb may be nullptr
128 void EventHandler::initHandler(EventBase* eventBase, int fd) {
129 ensureNotRegistered(__func__);
130 event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
131 setEventBase(eventBase);
134 void EventHandler::ensureNotRegistered(const char* fn) {
135 // Neither the EventBase nor file descriptor may be changed while the
136 // handler is registered. Treat it as a programmer bug and abort the program
137 // if this requirement is violated.
138 if (isHandlerRegistered()) {
139 LOG(ERROR) << fn << " called on registered handler; aborting";
144 void EventHandler::libeventCallback(int fd, short events, void* arg) {
145 EventHandler* handler = reinterpret_cast<EventHandler*>(arg);
146 assert(fd == handler->event_.ev_fd);
148 // this can't possibly fire if handler->eventBase_ is nullptr
149 (void) handler->eventBase_->bumpHandlingTime();
151 handler->handlerReady(events);
154 void EventHandler::setEventBase(EventBase* eventBase) {
155 event_base_set(eventBase->getLibeventBase(), &event_);
156 eventBase_ = eventBase;
159 bool EventHandler::isPending() const {
160 if (event_.ev_flags & EVLIST_ACTIVE) {
161 if (event_.ev_res & EV_READ) {