Codemod: use #include angle brackets in folly and thrift
[folly.git] / folly / io / async / EventHandler.cpp
1 /*
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
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  * under the License.
18  */
19 #include <folly/io/async/EventHandler.h>
20 #include <folly/io/async/EventBase.h>
21
22 #include <assert.h>
23
24 namespace folly {
25
26 EventHandler::EventHandler(EventBase* eventBase, int fd) {
27   event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
28   if (eventBase != nullptr) {
29     setEventBase(eventBase);
30   } else {
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;
35     eventBase_ = nullptr;
36   }
37 }
38
39 EventHandler::~EventHandler() {
40   unregisterHandler();
41 }
42
43 bool EventHandler::registerImpl(uint16_t events, bool internal) {
44   assert(event_.ev_base != nullptr);
45
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) {
52       return true;
53     }
54
55     event_del(&event_);
56   }
57
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_);
65
66   // Set EVLIST_INTERNAL if this is an internal event
67   if (internal) {
68     event_.ev_flags |= EVLIST_INTERNAL;
69   }
70
71   // Add the event.
72   //
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
76   // timeout.
77   //
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
87   // more space).
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
92     event_del(&event_);
93     return false;
94   }
95
96   return true;
97 }
98
99 void EventHandler::unregisterHandler() {
100   if (isHandlerRegistered()) {
101     event_del(&event_);
102   }
103 }
104
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());
111
112   setEventBase(eventBase);
113 }
114
115 void EventHandler::detachEventBase() {
116   ensureNotRegistered(__func__);
117   event_.ev_base = nullptr;
118 }
119
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
126 }
127
128 void EventHandler::initHandler(EventBase* eventBase, int fd) {
129   ensureNotRegistered(__func__);
130   event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
131   setEventBase(eventBase);
132 }
133
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";
140     abort();
141   }
142 }
143
144 void EventHandler::libeventCallback(int fd, short events, void* arg) {
145   EventHandler* handler = reinterpret_cast<EventHandler*>(arg);
146   assert(fd == handler->event_.ev_fd);
147
148   // this can't possibly fire if handler->eventBase_ is nullptr
149   (void) handler->eventBase_->bumpHandlingTime();
150
151   handler->handlerReady(events);
152 }
153
154 void EventHandler::setEventBase(EventBase* eventBase) {
155   event_base_set(eventBase->getLibeventBase(), &event_);
156   eventBase_ = eventBase;
157 }
158
159 bool EventHandler::isPending() const {
160   if (event_.ev_flags & EVLIST_ACTIVE) {
161     if (event_.ev_res & EV_READ) {
162       return true;
163     }
164   }
165   return false;
166 }
167
168 } // folly