proxygen
EventHandler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
18 #include <folly/String.h>
20 
21 #include <assert.h>
22 
23 namespace folly {
24 
27  if (eventBase != nullptr) {
28  setEventBase(eventBase);
29  } else {
30  // Callers must set the EventBase and fd before using this timeout.
31  // Set event_->ev_base to nullptr to ensure that this happens.
32  // (otherwise libevent will initialize it to the "default" event_base)
33  event_.ev_base = nullptr;
34  eventBase_ = nullptr;
35  }
36 }
37 
40 }
41 
42 bool EventHandler::registerImpl(uint16_t events, bool internal) {
43  assert(event_.ev_base != nullptr);
44 
45  // We have to unregister the event before we can change the event flags
46  if (isHandlerRegistered()) {
47  // If the new events are the same are the same as the already registered
48  // flags, we don't have to do anything. Just return.
49  auto flags = event_ref_flags(&event_);
50  if (events == event_.ev_events &&
51  static_cast<bool>(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(
63  &event_,
64  event_.ev_fd,
65  short(events),
67  this);
68  event_base_set(evb, &event_);
69 
70  // Set EVLIST_INTERNAL if this is an internal event
71  if (internal) {
72  event_ref_flags(&event_) |= EVLIST_INTERNAL;
73  }
74 
75  // Add the event.
76  //
77  // Although libevent allows events to wait on both I/O and a timeout,
78  // we intentionally don't allow an EventHandler to also use a timeout.
79  // Callers must maintain a separate AsyncTimeout object if they want a
80  // timeout.
81  //
82  // Otherwise, it is difficult to handle persistent events properly. (The I/O
83  // event and timeout may both fire together the same time around the event
84  // loop. Normally we would want to inform the caller of the I/O event first,
85  // then the timeout. However, it is difficult to do this properly since the
86  // I/O callback could delete the EventHandler.) Additionally, if a caller
87  // uses the same struct event for both I/O and timeout, and they just want to
88  // reschedule the timeout, libevent currently makes an epoll_ctl() call even
89  // if the I/O event flags haven't changed. Using a separate event struct is
90  // therefore slightly more efficient in this case (although it does take up
91  // more space).
92  if (event_add(&event_, nullptr) < 0) {
93  LOG(ERROR) << "EventBase: failed to register event handler for fd "
94  << event_.ev_fd << ": " << errnoStr(errno);
95  // Call event_del() to make sure the event is completely uninstalled
96  event_del(&event_);
97  return false;
98  }
99 
100  return true;
101 }
102 
104  if (isHandlerRegistered()) {
105  event_del(&event_);
106  }
107 }
108 
110  // attachEventBase() may only be called on detached handlers
111  assert(event_.ev_base == nullptr);
112  assert(!isHandlerRegistered());
113  // This must be invoked from the EventBase's thread
114  eventBase->dcheckIsInEventBaseThread();
115 
116  setEventBase(eventBase);
117 }
118 
120  ensureNotRegistered(__func__);
121  event_.ev_base = nullptr;
122 }
123 
125  ensureNotRegistered(__func__);
126  // event_set() resets event_base.ev_base, so manually restore it afterwards
127  struct event_base* evb = event_.ev_base;
129  event_.ev_base = evb; // don't use event_base_set(), since evb may be nullptr
130 }
131 
133  ensureNotRegistered(__func__);
135  setEventBase(eventBase);
136 }
137 
138 void EventHandler::ensureNotRegistered(const char* fn) {
139  // Neither the EventBase nor file descriptor may be changed while the
140  // handler is registered. Treat it as a programmer bug and abort the program
141  // if this requirement is violated.
142  if (isHandlerRegistered()) {
143  LOG(ERROR) << fn << " called on registered handler; aborting";
144  abort();
145  }
146 }
147 
148 void EventHandler::libeventCallback(libevent_fd_t fd, short events, void* arg) {
149  EventHandler* handler = reinterpret_cast<EventHandler*>(arg);
150  assert(fd == handler->event_.ev_fd);
151  (void)fd; // prevent unused variable warnings
152 
153  auto observer = handler->eventBase_->getExecutionObserver();
154  if (observer) {
155  observer->starting(reinterpret_cast<uintptr_t>(handler));
156  }
157 
158  // this can't possibly fire if handler->eventBase_ is nullptr
159  handler->eventBase_->bumpHandlingTime();
160 
161  handler->handlerReady(uint16_t(events));
162 
163  if (observer) {
164  observer->stopped(reinterpret_cast<uintptr_t>(handler));
165  }
166 }
167 
169  event_base_set(eventBase->getLibeventBase(), &event_);
170  eventBase_ = eventBase;
171 }
172 
174  if (event_ref_flags(&event_) & EVLIST_ACTIVE) {
175  if (event_.ev_res & EV_READ) {
176  return true;
177  }
178  }
179  return false;
180 }
181 
182 } // namespace folly
flags
Definition: http_parser.h:127
struct event event_
Definition: EventHandler.h:197
bool registerImpl(uint16_t events, bool internal)
static void libeventCallback(libevent_fd_t fd, short events, void *arg)
void initHandler(EventBase *eventBase, int fd)
Definition: EventHandler.h:156
bool isPending() const
void setEventBase(EventBase *eventBase)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void attachEventBase(EventBase *eventBase)
virtual void handlerReady(uint16_t events) noexcept=0
auto event_ref_flags(struct event *ev) -> decltype(std::ref(ev->ev_flags))
Definition: EventUtil.h:41
void folly_event_set(event *e, int fd, short s, EventSetCallback f, void *arg)
Definition: Event.h:50
void handler(int, siginfo_t *, void *)
void bumpHandlingTime() final
Definition: EventBase.cpp:476
EventBase * eventBase_
Definition: EventHandler.h:198
event_base * getLibeventBase() const
Definition: EventBase.h:537
void dcheckIsInEventBaseThread() const
Definition: EventBase.h:520
void changeHandlerFD(int fd)
Definition: EventHandler.h:143
fbstring errnoStr(int err)
Definition: String.cpp:463
virtual void starting(uintptr_t id) noexcept=0
EventHandler(EventBase *eventBase, int fd)
Definition: EventHandler.h:65
void ensureNotRegistered(const char *fn)
ExecutionObserver * getExecutionObserver()
Definition: EventBase.h:609
int libevent_fd_t
Definition: Event.h:37
bool isHandlerRegistered() const
Definition: EventHandler.h:112