1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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
17 #include <folly/io/async/EventBaseBackendBase.h>
18
19 #include <folly/io/async/EventBase.h>
20
21 #if defined(__linux__) && !FOLLY_MOBILE
22 #define FOLLY_USE_EPOLLET
23
24 #include <sys/epoll.h>
25
26 struct event_base {
27 void* evsel;
28 void* evbase;
29 };
30
31 struct epollop {
32 void* fds;
33 int nfds;
34 void* events;
35 int nevents;
36 int epfd;
37 };
38 #endif
39
40 namespace folly {
eb_ev_base(EventBase * evb)41 void EventBaseEvent::eb_ev_base(EventBase* evb) {
42 evb_ = evb;
43 event_.ev_base = evb ? evb->getLibeventBase() : nullptr;
44 }
45
eb_event_base_set(EventBase * evb)46 int EventBaseEvent::eb_event_base_set(EventBase* evb) {
47 evb_ = evb;
48 auto* base = evb_ ? (evb_->getLibeventBase()) : nullptr;
49 if (base) {
50 return ::event_base_set(base, &event_);
51 }
52
53 return 0;
54 }
55
eb_event_add(const struct timeval * timeout)56 int EventBaseEvent::eb_event_add(const struct timeval* timeout) {
57 auto* backend = evb_ ? (evb_->getBackend()) : nullptr;
58 if (backend) {
59 return backend->eb_event_add(*this, timeout);
60 }
61
62 return -1;
63 }
64
eb_event_del()65 int EventBaseEvent::eb_event_del() {
66 auto* backend = evb_ ? (evb_->getBackend()) : nullptr;
67 if (backend) {
68 return backend->eb_event_del(*this);
69 }
70
71 return -1;
72 }
73
eb_event_active(int res)74 bool EventBaseEvent::eb_event_active(int res) {
75 auto* backend = evb_ ? (evb_->getBackend()) : nullptr;
76 if (backend) {
77 return backend->eb_event_active(*this, res);
78 }
79
80 return false;
81 }
82
setEdgeTriggered()83 bool EventBaseEvent::setEdgeTriggered() {
84 #ifdef FOLLY_USE_EPOLLET
85 // Until v2 libevent doesn't expose API to set edge-triggered flag for events.
86 // If epoll backend is used by libevent, we can enable it though epoll_ctl
87 // directly.
88 // Note that this code depends on internal event_base and epollop layout, so
89 // we have to validate libevent version.
90 static const bool supportedVersion =
91 !strcmp(event_get_version(), "1.4.14b-stable");
92 if (!supportedVersion) {
93 return false;
94 }
95 auto* base = evb_ ? (evb_->getLibeventBase()) : nullptr;
96 if (!base || strcmp(event_base_get_method(base), "epoll")) {
97 return false;
98 }
99
100 auto epfd = static_cast<epollop*>(base->evbase)->epfd;
101 epoll_event epev = {0, {0}};
102 epev.data.fd = eb_ev_fd();
103 epev.events = EPOLLET;
104 if (eb_ev_events() & EV_READ) {
105 epev.events |= EPOLLIN;
106 }
107 if (eb_ev_events() & EV_WRITE) {
108 epev.events |= EPOLLOUT;
109 }
110 if (::epoll_ctl(epfd, EPOLL_CTL_MOD, eb_ev_fd(), &epev) == -1) {
111 LOG(DFATAL) << "epoll_ctl failed: " << errno;
112 return false;
113 }
114 return true;
115 #else
116 return false;
117 #endif
118 }
119 } // namespace folly
120