1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/iomgr/port.h"
22 
23 #include "src/core/lib/iomgr/is_epollexclusive_available.h"
24 
25 #ifdef GRPC_LINUX_EPOLL_CREATE1
26 
27 #include <grpc/support/log.h>
28 
29 #include <errno.h>
30 #include <sys/epoll.h>
31 #include <sys/eventfd.h>
32 #include <unistd.h>
33 
34 #include "src/core/lib/iomgr/sys_epoll_wrapper.h"
35 
36 /* This polling engine is only relevant on linux kernels supporting epoll() */
grpc_is_epollexclusive_available(void)37 bool grpc_is_epollexclusive_available(void) {
38   static bool logged_why_not = false;
39 
40   int fd = epoll_create1(EPOLL_CLOEXEC);
41   if (fd < 0) {
42     if (!logged_why_not) {
43       gpr_log(GPR_DEBUG,
44               "epoll_create1 failed with error: %d. Not using epollex polling "
45               "engine.",
46               fd);
47       logged_why_not = true;
48     }
49     return false;
50   }
51   int evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
52   if (evfd < 0) {
53     if (!logged_why_not) {
54       gpr_log(GPR_DEBUG,
55               "eventfd failed with error: %d. Not using epollex polling "
56               "engine.",
57               fd);
58       logged_why_not = true;
59     }
60     close(fd);
61     return false;
62   }
63   struct epoll_event ev;
64   /* choose events that should cause an error on
65      EPOLLEXCLUSIVE enabled kernels - specifically the combination of
66      EPOLLONESHOT and EPOLLEXCLUSIVE */
67   ev.events =
68       static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLEXCLUSIVE | EPOLLONESHOT);
69   ev.data.ptr = nullptr;
70   if (epoll_ctl(fd, EPOLL_CTL_ADD, evfd, &ev) != 0) {
71     if (errno != EINVAL) {
72       if (!logged_why_not) {
73         gpr_log(
74             GPR_ERROR,
75             "epoll_ctl with EPOLLEXCLUSIVE | EPOLLONESHOT failed with error: "
76             "%d. Not using epollex polling engine.",
77             errno);
78         logged_why_not = true;
79       }
80       close(fd);
81       close(evfd);
82       return false;
83     }
84   } else {
85     if (!logged_why_not) {
86       gpr_log(GPR_DEBUG,
87               "epoll_ctl with EPOLLEXCLUSIVE | EPOLLONESHOT succeeded. This is "
88               "evidence of no EPOLLEXCLUSIVE support. Not using "
89               "epollex polling engine.");
90       logged_why_not = true;
91     }
92     close(fd);
93     close(evfd);
94     return false;
95   }
96   close(evfd);
97   close(fd);
98   return true;
99 }
100 
101 #else
102 
grpc_is_epollexclusive_available(void)103 bool grpc_is_epollexclusive_available(void) { return false; }
104 
105 #endif
106