blob: 66ba601adb9bafe27da7a3852631b4af7f9c1eba [file] [log] [blame]
Craig Tillerc67cc992017-04-27 10:15:51 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2017 gRPC authors.
Craig Tillerc67cc992017-04-27 10:15:51 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
Craig Tillerc67cc992017-04-27 10:15:51 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tillerc67cc992017-04-27 10:15:51 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
Craig Tillerc67cc992017-04-27 10:15:51 -070016 *
17 */
18
19#include "src/core/lib/iomgr/port.h"
20
21/* This polling engine is only relevant on linux kernels supporting epoll() */
22#ifdef GRPC_LINUX_EPOLL
23
Craig Tiller4509c472017-04-27 19:05:13 +000024#include "src/core/lib/iomgr/ev_epoll1_linux.h"
Craig Tillerc67cc992017-04-27 10:15:51 -070025
26#include <assert.h>
27#include <errno.h>
28#include <poll.h>
29#include <pthread.h>
30#include <string.h>
31#include <sys/epoll.h>
32#include <sys/socket.h>
33#include <unistd.h>
34
35#include <grpc/support/alloc.h>
Craig Tiller6de05932017-04-28 09:17:38 -070036#include <grpc/support/cpu.h>
Craig Tillerc67cc992017-04-27 10:15:51 -070037#include <grpc/support/log.h>
38#include <grpc/support/string_util.h>
39#include <grpc/support/tls.h>
40#include <grpc/support/useful.h>
41
42#include "src/core/lib/iomgr/ev_posix.h"
43#include "src/core/lib/iomgr/iomgr_internal.h"
44#include "src/core/lib/iomgr/lockfree_event.h"
Craig Tillerc67cc992017-04-27 10:15:51 -070045#include "src/core/lib/iomgr/wakeup_fd_posix.h"
Craig Tillerc67cc992017-04-27 10:15:51 -070046#include "src/core/lib/profiling/timers.h"
47#include "src/core/lib/support/block_annotate.h"
48
Craig Tillerc67cc992017-04-27 10:15:51 -070049static grpc_wakeup_fd global_wakeup_fd;
50static int g_epfd;
51
52/*******************************************************************************
53 * Fd Declarations
54 */
55
56struct grpc_fd {
57 int fd;
58
Craig Tillerc67cc992017-04-27 10:15:51 -070059 gpr_atm read_closure;
60 gpr_atm write_closure;
61
62 struct grpc_fd *freelist_next;
Craig Tillerc67cc992017-04-27 10:15:51 -070063
64 /* The pollset that last noticed that the fd is readable. The actual type
65 * stored in this is (grpc_pollset *) */
66 gpr_atm read_notifier_pollset;
67
68 grpc_iomgr_object iomgr_object;
69};
70
71static void fd_global_init(void);
72static void fd_global_shutdown(void);
73
74/*******************************************************************************
75 * Pollset Declarations
76 */
77
Craig Tiller43bf2592017-04-28 23:21:01 +000078typedef enum { UNKICKED, KICKED, DESIGNATED_POLLER } kick_state;
Craig Tillerc67cc992017-04-27 10:15:51 -070079
80struct grpc_pollset_worker {
Craig Tiller32f90ee2017-04-28 12:46:41 -070081 kick_state kick_state;
Craig Tillerc67cc992017-04-27 10:15:51 -070082 bool initialized_cv;
Craig Tiller32f90ee2017-04-28 12:46:41 -070083 grpc_pollset_worker *next;
84 grpc_pollset_worker *prev;
Craig Tillerc67cc992017-04-27 10:15:51 -070085 gpr_cv cv;
Craig Tiller50da5ec2017-05-01 13:51:14 -070086 grpc_closure_list schedule_on_end_work;
Craig Tillerc67cc992017-04-27 10:15:51 -070087};
88
Craig Tillerba550da2017-05-01 14:26:31 +000089#define MAX_NEIGHBOURHOODS 1024
90
Craig Tiller6de05932017-04-28 09:17:38 -070091typedef struct pollset_neighbourhood {
92 gpr_mu mu;
93 grpc_pollset *active_root;
Craig Tiller6de05932017-04-28 09:17:38 -070094 char pad[GPR_CACHELINE_SIZE];
95} pollset_neighbourhood;
96
Craig Tillerc67cc992017-04-27 10:15:51 -070097struct grpc_pollset {
Craig Tiller6de05932017-04-28 09:17:38 -070098 gpr_mu mu;
99 pollset_neighbourhood *neighbourhood;
Craig Tillere00d7332017-05-01 15:43:51 +0000100 bool reassigning_neighbourhood;
Craig Tiller4509c472017-04-27 19:05:13 +0000101 grpc_pollset_worker *root_worker;
102 bool kicked_without_poller;
Craig Tiller6de05932017-04-28 09:17:38 -0700103 bool seen_inactive;
Craig Tillerc67cc992017-04-27 10:15:51 -0700104 bool shutting_down; /* Is the pollset shutting down ? */
105 bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
Craig Tiller4509c472017-04-27 19:05:13 +0000106 grpc_closure *shutdown_closure; /* Called after after shutdown is complete */
Craig Tillerba550da2017-05-01 14:26:31 +0000107 int begin_refs;
Craig Tiller6de05932017-04-28 09:17:38 -0700108
109 grpc_pollset *next;
110 grpc_pollset *prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700111};
112
113/*******************************************************************************
114 * Pollset-set Declarations
115 */
Craig Tiller6de05932017-04-28 09:17:38 -0700116
Craig Tiller61f96c12017-05-12 13:36:39 -0700117struct grpc_pollset_set {
118 char unused;
119};
Craig Tillerc67cc992017-04-27 10:15:51 -0700120
121/*******************************************************************************
122 * Common helpers
123 */
124
125static bool append_error(grpc_error **composite, grpc_error *error,
126 const char *desc) {
127 if (error == GRPC_ERROR_NONE) return true;
128 if (*composite == GRPC_ERROR_NONE) {
129 *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
130 }
131 *composite = grpc_error_add_child(*composite, error);
132 return false;
133}
134
135/*******************************************************************************
136 * Fd Definitions
137 */
138
139/* We need to keep a freelist not because of any concerns of malloc performance
140 * but instead so that implementations with multiple threads in (for example)
141 * epoll_wait deal with the race between pollset removal and incoming poll
142 * notifications.
143 *
144 * The problem is that the poller ultimately holds a reference to this
145 * object, so it is very difficult to know when is safe to free it, at least
146 * without some expensive synchronization.
147 *
148 * If we keep the object freelisted, in the worst case losing this race just
149 * becomes a spurious read notification on a reused fd.
150 */
151
152/* The alarm system needs to be able to wakeup 'some poller' sometimes
153 * (specifically when a new alarm needs to be triggered earlier than the next
154 * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
155 * case occurs. */
156
157static grpc_fd *fd_freelist = NULL;
158static gpr_mu fd_freelist_mu;
159
Craig Tillerc67cc992017-04-27 10:15:51 -0700160static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
161
162static void fd_global_shutdown(void) {
163 gpr_mu_lock(&fd_freelist_mu);
164 gpr_mu_unlock(&fd_freelist_mu);
165 while (fd_freelist != NULL) {
166 grpc_fd *fd = fd_freelist;
167 fd_freelist = fd_freelist->freelist_next;
Craig Tillerc67cc992017-04-27 10:15:51 -0700168 gpr_free(fd);
169 }
170 gpr_mu_destroy(&fd_freelist_mu);
171}
172
173static grpc_fd *fd_create(int fd, const char *name) {
174 grpc_fd *new_fd = NULL;
175
176 gpr_mu_lock(&fd_freelist_mu);
177 if (fd_freelist != NULL) {
178 new_fd = fd_freelist;
179 fd_freelist = fd_freelist->freelist_next;
180 }
181 gpr_mu_unlock(&fd_freelist_mu);
182
183 if (new_fd == NULL) {
184 new_fd = gpr_malloc(sizeof(grpc_fd));
Craig Tillerc67cc992017-04-27 10:15:51 -0700185 }
186
Craig Tillerc67cc992017-04-27 10:15:51 -0700187 new_fd->fd = fd;
Craig Tillerc67cc992017-04-27 10:15:51 -0700188 grpc_lfev_init(&new_fd->read_closure);
189 grpc_lfev_init(&new_fd->write_closure);
190 gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
191
192 new_fd->freelist_next = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700193
194 char *fd_name;
195 gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
196 grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
Noah Eisen264879f2017-06-20 17:14:47 -0700197#ifndef NDEBUG
198 if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
199 gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name);
200 }
Craig Tillerc67cc992017-04-27 10:15:51 -0700201#endif
202 gpr_free(fd_name);
Craig Tiller9ddb3152017-04-27 21:32:56 +0000203
204 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET),
205 .data.ptr = new_fd};
206 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
207 gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
208 }
209
Craig Tillerc67cc992017-04-27 10:15:51 -0700210 return new_fd;
211}
212
Craig Tiller4509c472017-04-27 19:05:13 +0000213static int fd_wrapped_fd(grpc_fd *fd) { return fd->fd; }
Craig Tillerc67cc992017-04-27 10:15:51 -0700214
Craig Tiller9ddb3152017-04-27 21:32:56 +0000215/* Might be called multiple times */
216static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
217 if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure,
218 GRPC_ERROR_REF(why))) {
219 shutdown(fd->fd, SHUT_RDWR);
220 grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why));
221 }
222 GRPC_ERROR_UNREF(why);
223}
224
Craig Tillerc67cc992017-04-27 10:15:51 -0700225static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
226 grpc_closure *on_done, int *release_fd,
227 const char *reason) {
Craig Tillerc67cc992017-04-27 10:15:51 -0700228 grpc_error *error = GRPC_ERROR_NONE;
Craig Tillerc67cc992017-04-27 10:15:51 -0700229
Craig Tiller9ddb3152017-04-27 21:32:56 +0000230 if (!grpc_lfev_is_shutdown(&fd->read_closure)) {
231 fd_shutdown(exec_ctx, fd, GRPC_ERROR_CREATE_FROM_COPIED_STRING(reason));
232 }
233
Craig Tillerc67cc992017-04-27 10:15:51 -0700234 /* If release_fd is not NULL, we should be relinquishing control of the file
235 descriptor fd->fd (but we still own the grpc_fd structure). */
236 if (release_fd != NULL) {
237 *release_fd = fd->fd;
238 } else {
239 close(fd->fd);
Craig Tillerc67cc992017-04-27 10:15:51 -0700240 }
241
ncteisen969b46e2017-06-08 14:57:11 -0700242 GRPC_CLOSURE_SCHED(exec_ctx, on_done, GRPC_ERROR_REF(error));
Craig Tillerc67cc992017-04-27 10:15:51 -0700243
Craig Tiller4509c472017-04-27 19:05:13 +0000244 grpc_iomgr_unregister_object(&fd->iomgr_object);
245 grpc_lfev_destroy(&fd->read_closure);
246 grpc_lfev_destroy(&fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700247
Craig Tiller4509c472017-04-27 19:05:13 +0000248 gpr_mu_lock(&fd_freelist_mu);
249 fd->freelist_next = fd_freelist;
250 fd_freelist = fd;
251 gpr_mu_unlock(&fd_freelist_mu);
Craig Tillerc67cc992017-04-27 10:15:51 -0700252}
253
254static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
255 grpc_fd *fd) {
256 gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset);
257 return (grpc_pollset *)notifier;
258}
259
260static bool fd_is_shutdown(grpc_fd *fd) {
261 return grpc_lfev_is_shutdown(&fd->read_closure);
262}
263
Craig Tillerc67cc992017-04-27 10:15:51 -0700264static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
265 grpc_closure *closure) {
266 grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure);
267}
268
269static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
270 grpc_closure *closure) {
271 grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure);
272}
273
Craig Tiller4509c472017-04-27 19:05:13 +0000274static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
275 grpc_pollset *notifier) {
276 grpc_lfev_set_ready(exec_ctx, &fd->read_closure);
277
278 /* Note, it is possible that fd_become_readable might be called twice with
279 different 'notifier's when an fd becomes readable and it is in two epoll
280 sets (This can happen briefly during polling island merges). In such cases
281 it does not really matter which notifer is set as the read_notifier_pollset
282 (They would both point to the same polling island anyway) */
283 /* Use release store to match with acquire load in fd_get_read_notifier */
284 gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier);
285}
286
287static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
288 grpc_lfev_set_ready(exec_ctx, &fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700289}
290
291/*******************************************************************************
292 * Pollset Definitions
293 */
294
Craig Tiller6de05932017-04-28 09:17:38 -0700295GPR_TLS_DECL(g_current_thread_pollset);
296GPR_TLS_DECL(g_current_thread_worker);
297static gpr_atm g_active_poller;
298static pollset_neighbourhood *g_neighbourhoods;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700299static size_t g_num_neighbourhoods;
Craig Tiller6de05932017-04-28 09:17:38 -0700300
Craig Tillerc67cc992017-04-27 10:15:51 -0700301/* Return true if first in list */
Craig Tiller32f90ee2017-04-28 12:46:41 -0700302static bool worker_insert(grpc_pollset *pollset, grpc_pollset_worker *worker) {
303 if (pollset->root_worker == NULL) {
304 pollset->root_worker = worker;
305 worker->next = worker->prev = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700306 return true;
307 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700308 worker->next = pollset->root_worker;
309 worker->prev = worker->next->prev;
310 worker->next->prev = worker;
311 worker->prev->next = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700312 return false;
313 }
314}
315
316/* Return true if last in list */
317typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result;
318
Craig Tiller32f90ee2017-04-28 12:46:41 -0700319static worker_remove_result worker_remove(grpc_pollset *pollset,
Craig Tillerc67cc992017-04-27 10:15:51 -0700320 grpc_pollset_worker *worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700321 if (worker == pollset->root_worker) {
322 if (worker == worker->next) {
323 pollset->root_worker = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700324 return EMPTIED;
325 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700326 pollset->root_worker = worker->next;
327 worker->prev->next = worker->next;
328 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700329 return NEW_ROOT;
330 }
331 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700332 worker->prev->next = worker->next;
333 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700334 return REMOVED;
335 }
336}
337
Craig Tillerba550da2017-05-01 14:26:31 +0000338static size_t choose_neighbourhood(void) {
339 return (size_t)gpr_cpu_current_cpu() % g_num_neighbourhoods;
340}
341
Craig Tiller4509c472017-04-27 19:05:13 +0000342static grpc_error *pollset_global_init(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000343 gpr_tls_init(&g_current_thread_pollset);
344 gpr_tls_init(&g_current_thread_worker);
Craig Tiller6de05932017-04-28 09:17:38 -0700345 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller375eb252017-04-27 23:29:12 +0000346 global_wakeup_fd.read_fd = -1;
347 grpc_error *err = grpc_wakeup_fd_init(&global_wakeup_fd);
348 if (err != GRPC_ERROR_NONE) return err;
Craig Tiller4509c472017-04-27 19:05:13 +0000349 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET),
350 .data.ptr = &global_wakeup_fd};
351 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd, &ev) != 0) {
352 return GRPC_OS_ERROR(errno, "epoll_ctl");
353 }
Craig Tillerba550da2017-05-01 14:26:31 +0000354 g_num_neighbourhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBOURHOODS);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700355 g_neighbourhoods =
356 gpr_zalloc(sizeof(*g_neighbourhoods) * g_num_neighbourhoods);
357 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
358 gpr_mu_init(&g_neighbourhoods[i].mu);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700359 }
Craig Tiller4509c472017-04-27 19:05:13 +0000360 return GRPC_ERROR_NONE;
361}
362
363static void pollset_global_shutdown(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000364 gpr_tls_destroy(&g_current_thread_pollset);
365 gpr_tls_destroy(&g_current_thread_worker);
Craig Tiller375eb252017-04-27 23:29:12 +0000366 if (global_wakeup_fd.read_fd != -1) grpc_wakeup_fd_destroy(&global_wakeup_fd);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700367 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
368 gpr_mu_destroy(&g_neighbourhoods[i].mu);
369 }
370 gpr_free(g_neighbourhoods);
Craig Tiller4509c472017-04-27 19:05:13 +0000371}
372
373static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
Craig Tiller6de05932017-04-28 09:17:38 -0700374 gpr_mu_init(&pollset->mu);
375 *mu = &pollset->mu;
Craig Tillerba550da2017-05-01 14:26:31 +0000376 pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
Craig Tiller6de05932017-04-28 09:17:38 -0700377 pollset->seen_inactive = true;
Craig Tiller6de05932017-04-28 09:17:38 -0700378}
379
Craig Tillerc6109852017-05-01 14:26:49 -0700380static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
Craig Tillere00d7332017-05-01 15:43:51 +0000381 gpr_mu_lock(&pollset->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000382 if (!pollset->seen_inactive) {
Craig Tillere00d7332017-05-01 15:43:51 +0000383 pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
384 gpr_mu_unlock(&pollset->mu);
Craig Tillera95bacf2017-05-01 12:51:24 -0700385 retry_lock_neighbourhood:
Craig Tillere00d7332017-05-01 15:43:51 +0000386 gpr_mu_lock(&neighbourhood->mu);
387 gpr_mu_lock(&pollset->mu);
388 if (!pollset->seen_inactive) {
389 if (pollset->neighbourhood != neighbourhood) {
390 gpr_mu_unlock(&neighbourhood->mu);
391 neighbourhood = pollset->neighbourhood;
392 gpr_mu_unlock(&pollset->mu);
393 goto retry_lock_neighbourhood;
394 }
395 pollset->prev->next = pollset->next;
396 pollset->next->prev = pollset->prev;
397 if (pollset == pollset->neighbourhood->active_root) {
398 pollset->neighbourhood->active_root =
399 pollset->next == pollset ? NULL : pollset->next;
400 }
Craig Tillerba550da2017-05-01 14:26:31 +0000401 }
402 gpr_mu_unlock(&pollset->neighbourhood->mu);
Craig Tiller6de05932017-04-28 09:17:38 -0700403 }
Craig Tillere00d7332017-05-01 15:43:51 +0000404 gpr_mu_unlock(&pollset->mu);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700405 gpr_mu_destroy(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000406}
407
408static grpc_error *pollset_kick_all(grpc_pollset *pollset) {
409 grpc_error *error = GRPC_ERROR_NONE;
410 if (pollset->root_worker != NULL) {
411 grpc_pollset_worker *worker = pollset->root_worker;
412 do {
413 if (worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700414 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000415 gpr_cv_signal(&worker->cv);
416 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700417 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000418 append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd),
419 "pollset_shutdown");
420 }
421
Craig Tiller32f90ee2017-04-28 12:46:41 -0700422 worker = worker->next;
Craig Tiller4509c472017-04-27 19:05:13 +0000423 } while (worker != pollset->root_worker);
424 }
425 return error;
426}
427
428static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
429 grpc_pollset *pollset) {
Craig Tillerba550da2017-05-01 14:26:31 +0000430 if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL &&
431 pollset->begin_refs == 0) {
ncteisen969b46e2017-06-08 14:57:11 -0700432 GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE);
Craig Tiller4509c472017-04-27 19:05:13 +0000433 pollset->shutdown_closure = NULL;
434 }
435}
436
437static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
438 grpc_closure *closure) {
439 GPR_ASSERT(pollset->shutdown_closure == NULL);
440 pollset->shutdown_closure = closure;
441 GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(pollset));
442 pollset_maybe_finish_shutdown(exec_ctx, pollset);
443}
444
Craig Tillera95bacf2017-05-01 12:51:24 -0700445#define MAX_EPOLL_EVENTS 100
Craig Tiller4509c472017-04-27 19:05:13 +0000446
447static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
448 gpr_timespec now) {
449 gpr_timespec timeout;
450 if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
451 return -1;
452 }
453
454 if (gpr_time_cmp(deadline, now) <= 0) {
455 return 0;
456 }
457
458 static const gpr_timespec round_up = {
459 .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1};
460 timeout = gpr_time_sub(deadline, now);
461 int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up));
462 return millis >= 1 ? millis : 1;
463}
464
465static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
466 gpr_timespec now, gpr_timespec deadline) {
467 struct epoll_event events[MAX_EPOLL_EVENTS];
468 static const char *err_desc = "pollset_poll";
469
470 int timeout = poll_deadline_to_millis_timeout(deadline, now);
471
472 if (timeout != 0) {
473 GRPC_SCHEDULING_START_BLOCKING_REGION;
474 }
475 int r;
476 do {
477 r = epoll_wait(g_epfd, events, MAX_EPOLL_EVENTS, timeout);
478 } while (r < 0 && errno == EINTR);
479 if (timeout != 0) {
480 GRPC_SCHEDULING_END_BLOCKING_REGION;
481 }
482
483 if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
484
485 grpc_error *error = GRPC_ERROR_NONE;
486 for (int i = 0; i < r; i++) {
487 void *data_ptr = events[i].data.ptr;
488 if (data_ptr == &global_wakeup_fd) {
Craig Tiller4509c472017-04-27 19:05:13 +0000489 append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
490 err_desc);
491 } else {
492 grpc_fd *fd = (grpc_fd *)(data_ptr);
493 bool cancel = (events[i].events & (EPOLLERR | EPOLLHUP)) != 0;
494 bool read_ev = (events[i].events & (EPOLLIN | EPOLLPRI)) != 0;
495 bool write_ev = (events[i].events & EPOLLOUT) != 0;
496 if (read_ev || cancel) {
497 fd_become_readable(exec_ctx, fd, pollset);
498 }
499 if (write_ev || cancel) {
500 fd_become_writable(exec_ctx, fd);
501 }
502 }
503 }
504
505 return error;
506}
507
508static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker,
509 grpc_pollset_worker **worker_hdl, gpr_timespec *now,
510 gpr_timespec deadline) {
Craig Tiller4509c472017-04-27 19:05:13 +0000511 if (worker_hdl != NULL) *worker_hdl = worker;
512 worker->initialized_cv = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700513 worker->kick_state = UNKICKED;
Craig Tiller50da5ec2017-05-01 13:51:14 -0700514 worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT;
Craig Tillerba550da2017-05-01 14:26:31 +0000515 pollset->begin_refs++;
Craig Tiller4509c472017-04-27 19:05:13 +0000516
Craig Tiller32f90ee2017-04-28 12:46:41 -0700517 if (pollset->seen_inactive) {
518 // pollset has been observed to be inactive, we need to move back to the
519 // active list
Craig Tillere00d7332017-05-01 15:43:51 +0000520 bool is_reassigning = false;
521 if (!pollset->reassigning_neighbourhood) {
522 is_reassigning = true;
523 pollset->reassigning_neighbourhood = true;
524 pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
525 }
526 pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700527 gpr_mu_unlock(&pollset->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000528 // pollset unlocked: state may change (even worker->kick_state)
529 retry_lock_neighbourhood:
Craig Tiller32f90ee2017-04-28 12:46:41 -0700530 gpr_mu_lock(&neighbourhood->mu);
531 gpr_mu_lock(&pollset->mu);
532 if (pollset->seen_inactive) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000533 if (neighbourhood != pollset->neighbourhood) {
534 gpr_mu_unlock(&neighbourhood->mu);
535 neighbourhood = pollset->neighbourhood;
536 gpr_mu_unlock(&pollset->mu);
537 goto retry_lock_neighbourhood;
538 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700539 pollset->seen_inactive = false;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000540 if (neighbourhood->active_root == NULL) {
541 neighbourhood->active_root = pollset->next = pollset->prev = pollset;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700542 if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) {
Craig Tiller43bf2592017-04-28 23:21:01 +0000543 worker->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700544 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000545 } else {
546 pollset->next = neighbourhood->active_root;
547 pollset->prev = pollset->next->prev;
548 pollset->next->prev = pollset->prev->next = pollset;
Craig Tiller4509c472017-04-27 19:05:13 +0000549 }
550 }
Craig Tillere00d7332017-05-01 15:43:51 +0000551 if (is_reassigning) {
552 GPR_ASSERT(pollset->reassigning_neighbourhood);
553 pollset->reassigning_neighbourhood = false;
554 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700555 gpr_mu_unlock(&neighbourhood->mu);
556 }
557 worker_insert(pollset, worker);
Craig Tillerba550da2017-05-01 14:26:31 +0000558 pollset->begin_refs--;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700559 if (worker->kick_state == UNKICKED) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000560 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700561 worker->initialized_cv = true;
562 gpr_cv_init(&worker->cv);
Craig Tillerba550da2017-05-01 14:26:31 +0000563 while (worker->kick_state == UNKICKED &&
564 pollset->shutdown_closure == NULL) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700565 if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) &&
566 worker->kick_state == UNKICKED) {
567 worker->kick_state = KICKED;
568 }
Craig Tillerba550da2017-05-01 14:26:31 +0000569 }
Craig Tiller4509c472017-04-27 19:05:13 +0000570 *now = gpr_now(now->clock_type);
571 }
572
Craig Tiller43bf2592017-04-28 23:21:01 +0000573 return worker->kick_state == DESIGNATED_POLLER &&
Craig Tiller32f90ee2017-04-28 12:46:41 -0700574 pollset->shutdown_closure == NULL;
Craig Tiller4509c472017-04-27 19:05:13 +0000575}
576
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700577static bool check_neighbourhood_for_available_poller(
Craig Tillera4b8eb02017-04-29 00:13:52 +0000578 pollset_neighbourhood *neighbourhood) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700579 bool found_worker = false;
580 do {
581 grpc_pollset *inspect = neighbourhood->active_root;
582 if (inspect == NULL) {
583 break;
584 }
585 gpr_mu_lock(&inspect->mu);
586 GPR_ASSERT(!inspect->seen_inactive);
587 grpc_pollset_worker *inspect_worker = inspect->root_worker;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700588 if (inspect_worker != NULL) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000589 do {
Craig Tillerba550da2017-05-01 14:26:31 +0000590 switch (inspect_worker->kick_state) {
591 case UNKICKED:
592 if (gpr_atm_no_barrier_cas(&g_active_poller, 0,
593 (gpr_atm)inspect_worker)) {
594 inspect_worker->kick_state = DESIGNATED_POLLER;
595 if (inspect_worker->initialized_cv) {
596 gpr_cv_signal(&inspect_worker->cv);
597 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000598 }
Craig Tillerba550da2017-05-01 14:26:31 +0000599 // even if we didn't win the cas, there's a worker, we can stop
600 found_worker = true;
601 break;
602 case KICKED:
603 break;
604 case DESIGNATED_POLLER:
605 found_worker = true; // ok, so someone else found the worker, but
606 // we'll accept that
607 break;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700608 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000609 inspect_worker = inspect_worker->next;
610 } while (inspect_worker != inspect->root_worker);
611 }
612 if (!found_worker) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700613 inspect->seen_inactive = true;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000614 if (inspect == neighbourhood->active_root) {
Craig Tillera95bacf2017-05-01 12:51:24 -0700615 neighbourhood->active_root =
616 inspect->next == inspect ? NULL : inspect->next;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000617 }
618 inspect->next->prev = inspect->prev;
619 inspect->prev->next = inspect->next;
Craig Tillere00d7332017-05-01 15:43:51 +0000620 inspect->next = inspect->prev = NULL;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700621 }
622 gpr_mu_unlock(&inspect->mu);
623 } while (!found_worker);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700624 return found_worker;
625}
626
Craig Tiller4509c472017-04-27 19:05:13 +0000627static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
628 grpc_pollset_worker *worker,
629 grpc_pollset_worker **worker_hdl) {
Craig Tiller8502ecb2017-04-28 14:22:01 -0700630 if (worker_hdl != NULL) *worker_hdl = NULL;
Craig Tillera4b8eb02017-04-29 00:13:52 +0000631 worker->kick_state = KICKED;
Craig Tiller50da5ec2017-05-01 13:51:14 -0700632 grpc_closure_list_move(&worker->schedule_on_end_work,
633 &exec_ctx->closure_list);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700634 if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000635 if (worker->next != worker && worker->next->kick_state == UNKICKED) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000636 GPR_ASSERT(worker->next->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700637 gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next);
Craig Tiller43bf2592017-04-28 23:21:01 +0000638 worker->next->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700639 gpr_cv_signal(&worker->next->cv);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700640 if (grpc_exec_ctx_has_work(exec_ctx)) {
641 gpr_mu_unlock(&pollset->mu);
642 grpc_exec_ctx_flush(exec_ctx);
643 gpr_mu_lock(&pollset->mu);
644 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700645 } else {
646 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700647 gpr_mu_unlock(&pollset->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700648 size_t poller_neighbourhood_idx =
649 (size_t)(pollset->neighbourhood - g_neighbourhoods);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700650 bool found_worker = false;
Craig Tillerba550da2017-05-01 14:26:31 +0000651 bool scan_state[MAX_NEIGHBOURHOODS];
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700652 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
653 pollset_neighbourhood *neighbourhood =
654 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
655 g_num_neighbourhoods];
656 if (gpr_mu_trylock(&neighbourhood->mu)) {
657 found_worker =
Craig Tillera4b8eb02017-04-29 00:13:52 +0000658 check_neighbourhood_for_available_poller(neighbourhood);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700659 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000660 scan_state[i] = true;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700661 } else {
Craig Tillerba550da2017-05-01 14:26:31 +0000662 scan_state[i] = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700663 }
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700664 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000665 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
Craig Tillerba550da2017-05-01 14:26:31 +0000666 if (scan_state[i]) continue;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000667 pollset_neighbourhood *neighbourhood =
668 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
669 g_num_neighbourhoods];
670 gpr_mu_lock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000671 found_worker = check_neighbourhood_for_available_poller(neighbourhood);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000672 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700673 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700674 grpc_exec_ctx_flush(exec_ctx);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700675 gpr_mu_lock(&pollset->mu);
676 }
Craig Tiller50da5ec2017-05-01 13:51:14 -0700677 } else if (grpc_exec_ctx_has_work(exec_ctx)) {
678 gpr_mu_unlock(&pollset->mu);
679 grpc_exec_ctx_flush(exec_ctx);
680 gpr_mu_lock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000681 }
682 if (worker->initialized_cv) {
683 gpr_cv_destroy(&worker->cv);
684 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700685 if (EMPTIED == worker_remove(pollset, worker)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000686 pollset_maybe_finish_shutdown(exec_ctx, pollset);
687 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000688 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller4509c472017-04-27 19:05:13 +0000689}
690
691/* pollset->po.mu lock must be held by the caller before calling this.
692 The function pollset_work() may temporarily release the lock (pollset->po.mu)
693 during the course of its execution but it will always re-acquire the lock and
694 ensure that it is held by the time the function returns */
695static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
696 grpc_pollset_worker **worker_hdl,
697 gpr_timespec now, gpr_timespec deadline) {
698 grpc_pollset_worker worker;
699 grpc_error *error = GRPC_ERROR_NONE;
700 static const char *err_desc = "pollset_work";
701 if (pollset->kicked_without_poller) {
702 pollset->kicked_without_poller = false;
703 return GRPC_ERROR_NONE;
704 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700705 gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
Craig Tiller4509c472017-04-27 19:05:13 +0000706 if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000707 gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
708 GPR_ASSERT(!pollset->shutdown_closure);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000709 GPR_ASSERT(!pollset->seen_inactive);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700710 gpr_mu_unlock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000711 append_error(&error, pollset_epoll(exec_ctx, pollset, now, deadline),
712 err_desc);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700713 gpr_mu_lock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000714 gpr_tls_set(&g_current_thread_worker, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000715 }
716 end_worker(exec_ctx, pollset, &worker, worker_hdl);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700717 gpr_tls_set(&g_current_thread_pollset, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000718 return error;
719}
720
721static grpc_error *pollset_kick(grpc_pollset *pollset,
722 grpc_pollset_worker *specific_worker) {
723 if (specific_worker == NULL) {
724 if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) {
Craig Tiller375eb252017-04-27 23:29:12 +0000725 grpc_pollset_worker *root_worker = pollset->root_worker;
726 if (root_worker == NULL) {
Craig Tiller4509c472017-04-27 19:05:13 +0000727 pollset->kicked_without_poller = true;
728 return GRPC_ERROR_NONE;
Craig Tiller375eb252017-04-27 23:29:12 +0000729 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700730 grpc_pollset_worker *next_worker = root_worker->next;
731 if (root_worker == next_worker &&
732 root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(
733 &g_active_poller)) {
734 root_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000735 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700736 } else if (next_worker->kick_state == UNKICKED) {
737 GPR_ASSERT(next_worker->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700738 next_worker->kick_state = KICKED;
Craig Tiller375eb252017-04-27 23:29:12 +0000739 gpr_cv_signal(&next_worker->cv);
740 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700741 } else {
742 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000743 }
744 } else {
745 return GRPC_ERROR_NONE;
746 }
Craig Tiller43bf2592017-04-28 23:21:01 +0000747 } else if (specific_worker->kick_state == KICKED) {
Craig Tiller4509c472017-04-27 19:05:13 +0000748 return GRPC_ERROR_NONE;
749 } else if (gpr_tls_get(&g_current_thread_worker) ==
750 (intptr_t)specific_worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700751 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000752 return GRPC_ERROR_NONE;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700753 } else if (specific_worker ==
754 (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) {
755 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000756 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700757 } else if (specific_worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700758 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000759 gpr_cv_signal(&specific_worker->cv);
760 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700761 } else {
762 specific_worker->kick_state = KICKED;
763 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000764 }
765}
766
767static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
768 grpc_fd *fd) {}
769
Craig Tiller4509c472017-04-27 19:05:13 +0000770/*******************************************************************************
Craig Tillerc67cc992017-04-27 10:15:51 -0700771 * Pollset-set Definitions
772 */
773
774static grpc_pollset_set *pollset_set_create(void) {
775 return (grpc_pollset_set *)((intptr_t)0xdeafbeef);
776}
777
778static void pollset_set_destroy(grpc_exec_ctx *exec_ctx,
779 grpc_pollset_set *pss) {}
780
781static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
782 grpc_fd *fd) {}
783
784static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
785 grpc_fd *fd) {}
786
787static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
788 grpc_pollset_set *pss, grpc_pollset *ps) {}
789
790static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
791 grpc_pollset_set *pss, grpc_pollset *ps) {}
792
793static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
794 grpc_pollset_set *bag,
795 grpc_pollset_set *item) {}
796
797static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
798 grpc_pollset_set *bag,
799 grpc_pollset_set *item) {}
800
801/*******************************************************************************
802 * Event engine binding
803 */
804
805static void shutdown_engine(void) {
806 fd_global_shutdown();
807 pollset_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700808}
809
810static const grpc_event_engine_vtable vtable = {
811 .pollset_size = sizeof(grpc_pollset),
812
813 .fd_create = fd_create,
814 .fd_wrapped_fd = fd_wrapped_fd,
815 .fd_orphan = fd_orphan,
816 .fd_shutdown = fd_shutdown,
817 .fd_is_shutdown = fd_is_shutdown,
818 .fd_notify_on_read = fd_notify_on_read,
819 .fd_notify_on_write = fd_notify_on_write,
820 .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
Craig Tillerc67cc992017-04-27 10:15:51 -0700821
822 .pollset_init = pollset_init,
823 .pollset_shutdown = pollset_shutdown,
824 .pollset_destroy = pollset_destroy,
825 .pollset_work = pollset_work,
826 .pollset_kick = pollset_kick,
827 .pollset_add_fd = pollset_add_fd,
828
829 .pollset_set_create = pollset_set_create,
830 .pollset_set_destroy = pollset_set_destroy,
831 .pollset_set_add_pollset = pollset_set_add_pollset,
832 .pollset_set_del_pollset = pollset_set_del_pollset,
833 .pollset_set_add_pollset_set = pollset_set_add_pollset_set,
834 .pollset_set_del_pollset_set = pollset_set_del_pollset_set,
835 .pollset_set_add_fd = pollset_set_add_fd,
836 .pollset_set_del_fd = pollset_set_del_fd,
837
Craig Tillerc67cc992017-04-27 10:15:51 -0700838 .shutdown_engine = shutdown_engine,
839};
840
841/* It is possible that GLIBC has epoll but the underlying kernel doesn't.
842 * Create a dummy epoll_fd to make sure epoll support is available */
Craig Tiller6f0af492017-04-27 19:26:16 +0000843const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
Craig Tiller924353a2017-05-05 17:36:31 +0000844 /* TODO(ctiller): temporary, until this stabilizes */
845 if (!explicit_request) return NULL;
846
Craig Tillerc67cc992017-04-27 10:15:51 -0700847 if (!grpc_has_wakeup_fd()) {
848 return NULL;
849 }
850
Craig Tiller4509c472017-04-27 19:05:13 +0000851 g_epfd = epoll_create1(EPOLL_CLOEXEC);
852 if (g_epfd < 0) {
853 gpr_log(GPR_ERROR, "epoll unavailable");
Craig Tillerc67cc992017-04-27 10:15:51 -0700854 return NULL;
855 }
856
Craig Tillerc67cc992017-04-27 10:15:51 -0700857 fd_global_init();
858
859 if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
Craig Tiller4509c472017-04-27 19:05:13 +0000860 close(g_epfd);
861 fd_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700862 return NULL;
863 }
864
865 return &vtable;
866}
867
868#else /* defined(GRPC_LINUX_EPOLL) */
869#if defined(GRPC_POSIX_SOCKET)
870#include "src/core/lib/iomgr/ev_posix.h"
871/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return
872 * NULL */
Craig Tiller9ddb3152017-04-27 21:32:56 +0000873const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
874 return NULL;
875}
Craig Tillerc67cc992017-04-27 10:15:51 -0700876#endif /* defined(GRPC_POSIX_SOCKET) */
877#endif /* !defined(GRPC_LINUX_EPOLL) */