Make most implicit integer truncations and sign conversions explicit
[folly.git] / folly / io / async / EventHandler.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements. See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership. The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License. You may obtain a copy of the License at
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied. See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21 #include <folly/io/async/EventHandler.h>
22 #include <folly/io/async/EventBase.h>
23
24 #include <assert.h>
25
26 namespace folly {
27
28 EventHandler::EventHandler(EventBase* eventBase, int fd) {
29   folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
30   if (eventBase != nullptr) {
31     setEventBase(eventBase);
32   } else {
33     // Callers must set the EventBase and fd before using this timeout.
34     // Set event_->ev_base to nullptr to ensure that this happens.
35     // (otherwise libevent will initialize it to the "default" event_base)
36     event_.ev_base = nullptr;
37     eventBase_ = nullptr;
38   }
39 }
40
41 EventHandler::~EventHandler() {
42   unregisterHandler();
43 }
44
45 bool EventHandler::registerImpl(uint16_t events, bool internal) {
46   assert(event_.ev_base != nullptr);
47
48   // We have to unregister the event before we can change the event flags
49   if (isHandlerRegistered()) {
50     // If the new events are the same are the same as the already registered
51     // flags, we don't have to do anything.  Just return.
52     auto flags = event_ref_flags(&event_);
53     if (events == event_.ev_events &&
54         static_cast<bool>(flags & EVLIST_INTERNAL) == internal) {
55       return true;
56     }
57
58     event_del(&event_);
59   }
60
61   // Update the event flags
62   // Unfortunately, event_set() resets the event_base, so we have to remember
63   // it before hand, then pass it back into event_base_set() afterwards
64   struct event_base* evb = event_.ev_base;
65   event_set(
66       &event_,
67       event_.ev_fd,
68       short(events),
69       &EventHandler::libeventCallback,
70       this);
71   event_base_set(evb, &event_);
72
73   // Set EVLIST_INTERNAL if this is an internal event
74   if (internal) {
75     event_ref_flags(&event_) |= EVLIST_INTERNAL;
76   }
77
78   // Add the event.
79   //
80   // Although libevent allows events to wait on both I/O and a timeout,
81   // we intentionally don't allow an EventHandler to also use a timeout.
82   // Callers must maintain a separate AsyncTimeout object if they want a
83   // timeout.
84   //
85   // Otherwise, it is difficult to handle persistent events properly.  (The I/O
86   // event and timeout may both fire together the same time around the event
87   // loop.  Normally we would want to inform the caller of the I/O event first,
88   // then the timeout.  However, it is difficult to do this properly since the
89   // I/O callback could delete the EventHandler.)  Additionally, if a caller
90   // uses the same struct event for both I/O and timeout, and they just want to
91   // reschedule the timeout, libevent currently makes an epoll_ctl() call even
92   // if the I/O event flags haven't changed.  Using a separate event struct is
93   // therefore slightly more efficient in this case (although it does take up
94   // more space).
95   if (event_add(&event_, nullptr) < 0) {
96     LOG(ERROR) << "EventBase: failed to register event handler for fd "
97                << event_.ev_fd << ": " << strerror(errno);
98     // Call event_del() to make sure the event is completely uninstalled
99     event_del(&event_);
100     return false;
101   }
102
103   return true;
104 }
105
106 void EventHandler::unregisterHandler() {
107   if (isHandlerRegistered()) {
108     event_del(&event_);
109   }
110 }
111
112 void EventHandler::attachEventBase(EventBase* eventBase) {
113   // attachEventBase() may only be called on detached handlers
114   assert(event_.ev_base == nullptr);
115   assert(!isHandlerRegistered());
116   // This must be invoked from the EventBase's thread
117   assert(eventBase->isInEventBaseThread());
118
119   setEventBase(eventBase);
120 }
121
122 void EventHandler::detachEventBase() {
123   ensureNotRegistered(__func__);
124   event_.ev_base = nullptr;
125 }
126
127 void EventHandler::changeHandlerFD(int fd) {
128   ensureNotRegistered(__func__);
129   // event_set() resets event_base.ev_base, so manually restore it afterwards
130   struct event_base* evb = event_.ev_base;
131   folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
132   event_.ev_base = evb; // don't use event_base_set(), since evb may be nullptr
133 }
134
135 void EventHandler::initHandler(EventBase* eventBase, int fd) {
136   ensureNotRegistered(__func__);
137   folly_event_set(&event_, fd, 0, &EventHandler::libeventCallback, this);
138   setEventBase(eventBase);
139 }
140
141 void EventHandler::ensureNotRegistered(const char* fn) {
142   // Neither the EventBase nor file descriptor may be changed while the
143   // handler is registered.  Treat it as a programmer bug and abort the program
144   // if this requirement is violated.
145   if (isHandlerRegistered()) {
146     LOG(ERROR) << fn << " called on registered handler; aborting";
147     abort();
148   }
149 }
150
151 void EventHandler::libeventCallback(libevent_fd_t fd, short events, void* arg) {
152   EventHandler* handler = reinterpret_cast<EventHandler*>(arg);
153   assert(fd == handler->event_.ev_fd);
154   (void)fd; // prevent unused variable warnings
155
156   auto observer = handler->eventBase_->getExecutionObserver();
157   if (observer) {
158     observer->starting(reinterpret_cast<uintptr_t>(handler));
159   }
160
161   // this can't possibly fire if handler->eventBase_ is nullptr
162   handler->eventBase_->bumpHandlingTime();
163
164   handler->handlerReady(uint16_t(events));
165
166   if (observer) {
167     observer->stopped(reinterpret_cast<uintptr_t>(handler));
168   }
169 }
170
171 void EventHandler::setEventBase(EventBase* eventBase) {
172   event_base_set(eventBase->getLibeventBase(), &event_);
173   eventBase_ = eventBase;
174 }
175
176 bool EventHandler::isPending() const {
177   if (event_ref_flags(&event_) & EVLIST_ACTIVE) {
178     if (event_.ev_res & EV_READ) {
179       return true;
180     }
181   }
182   return false;
183 }
184
185 } // folly