blob: fccccccd093acf2b0390e5bf48c5e766f4d2ebe8 [file] [log] [blame]
Craig Tillerc67cc992017-04-27 10:15:51 -07001/*
2 *
Craig Tillerd4838a92017-04-27 12:08:18 -07003 * Copyright 2017, Google Inc.
Craig Tillerc67cc992017-04-27 10:15:51 -07004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/lib/iomgr/port.h"
35
36/* This polling engine is only relevant on linux kernels supporting epoll() */
37#ifdef GRPC_LINUX_EPOLL
38
Craig Tiller4509c472017-04-27 19:05:13 +000039#include "src/core/lib/iomgr/ev_epoll1_linux.h"
Craig Tillerc67cc992017-04-27 10:15:51 -070040
41#include <assert.h>
42#include <errno.h>
43#include <poll.h>
44#include <pthread.h>
45#include <string.h>
46#include <sys/epoll.h>
47#include <sys/socket.h>
48#include <unistd.h>
49
50#include <grpc/support/alloc.h>
Craig Tiller6de05932017-04-28 09:17:38 -070051#include <grpc/support/cpu.h>
Craig Tillerc67cc992017-04-27 10:15:51 -070052#include <grpc/support/log.h>
53#include <grpc/support/string_util.h>
54#include <grpc/support/tls.h>
55#include <grpc/support/useful.h>
56
57#include "src/core/lib/iomgr/ev_posix.h"
58#include "src/core/lib/iomgr/iomgr_internal.h"
59#include "src/core/lib/iomgr/lockfree_event.h"
60#include "src/core/lib/iomgr/timer.h"
61#include "src/core/lib/iomgr/wakeup_fd_posix.h"
62#include "src/core/lib/iomgr/workqueue.h"
63#include "src/core/lib/profiling/timers.h"
64#include "src/core/lib/support/block_annotate.h"
65
66/* TODO: sreek: Right now, this wakes up all pollers. In future we should make
67 * sure to wake up one polling thread (which can wake up other threads if
68 * needed) */
69static grpc_wakeup_fd global_wakeup_fd;
70static int g_epfd;
Craig Tiller32f90ee2017-04-28 12:46:41 -070071static gpr_atm g_timer_kick;
Craig Tillerc67cc992017-04-27 10:15:51 -070072
73/*******************************************************************************
74 * Fd Declarations
75 */
76
77struct grpc_fd {
78 int fd;
79
Craig Tillerc67cc992017-04-27 10:15:51 -070080 gpr_atm read_closure;
81 gpr_atm write_closure;
82
83 struct grpc_fd *freelist_next;
Craig Tillerc67cc992017-04-27 10:15:51 -070084
85 /* The pollset that last noticed that the fd is readable. The actual type
86 * stored in this is (grpc_pollset *) */
87 gpr_atm read_notifier_pollset;
88
89 grpc_iomgr_object iomgr_object;
90};
91
92static void fd_global_init(void);
93static void fd_global_shutdown(void);
94
95/*******************************************************************************
96 * Pollset Declarations
97 */
98
Craig Tiller43bf2592017-04-28 23:21:01 +000099typedef enum { UNKICKED, KICKED, DESIGNATED_POLLER } kick_state;
Craig Tillerc67cc992017-04-27 10:15:51 -0700100
101struct grpc_pollset_worker {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700102 kick_state kick_state;
Craig Tillerc67cc992017-04-27 10:15:51 -0700103 bool initialized_cv;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700104 grpc_pollset_worker *next;
105 grpc_pollset_worker *prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700106 gpr_cv cv;
107};
108
Craig Tillerba550da2017-05-01 14:26:31 +0000109#define MAX_NEIGHBOURHOODS 1024
110
Craig Tiller6de05932017-04-28 09:17:38 -0700111typedef struct pollset_neighbourhood {
112 gpr_mu mu;
113 grpc_pollset *active_root;
Craig Tiller6de05932017-04-28 09:17:38 -0700114 char pad[GPR_CACHELINE_SIZE];
115} pollset_neighbourhood;
116
Craig Tillerc67cc992017-04-27 10:15:51 -0700117struct grpc_pollset {
Craig Tiller6de05932017-04-28 09:17:38 -0700118 gpr_mu mu;
119 pollset_neighbourhood *neighbourhood;
Craig Tiller4509c472017-04-27 19:05:13 +0000120 grpc_pollset_worker *root_worker;
121 bool kicked_without_poller;
Craig Tiller6de05932017-04-28 09:17:38 -0700122 bool seen_inactive;
Craig Tillerc67cc992017-04-27 10:15:51 -0700123 bool shutting_down; /* Is the pollset shutting down ? */
124 bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
Craig Tiller4509c472017-04-27 19:05:13 +0000125 grpc_closure *shutdown_closure; /* Called after after shutdown is complete */
Craig Tillerba550da2017-05-01 14:26:31 +0000126 int begin_refs;
Craig Tiller6de05932017-04-28 09:17:38 -0700127
128 grpc_pollset *next;
129 grpc_pollset *prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700130};
131
132/*******************************************************************************
133 * Pollset-set Declarations
134 */
Craig Tiller6de05932017-04-28 09:17:38 -0700135
Craig Tillerc67cc992017-04-27 10:15:51 -0700136struct grpc_pollset_set {};
137
138/*******************************************************************************
139 * Common helpers
140 */
141
142static bool append_error(grpc_error **composite, grpc_error *error,
143 const char *desc) {
144 if (error == GRPC_ERROR_NONE) return true;
145 if (*composite == GRPC_ERROR_NONE) {
146 *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
147 }
148 *composite = grpc_error_add_child(*composite, error);
149 return false;
150}
151
152/*******************************************************************************
153 * Fd Definitions
154 */
155
156/* We need to keep a freelist not because of any concerns of malloc performance
157 * but instead so that implementations with multiple threads in (for example)
158 * epoll_wait deal with the race between pollset removal and incoming poll
159 * notifications.
160 *
161 * The problem is that the poller ultimately holds a reference to this
162 * object, so it is very difficult to know when is safe to free it, at least
163 * without some expensive synchronization.
164 *
165 * If we keep the object freelisted, in the worst case losing this race just
166 * becomes a spurious read notification on a reused fd.
167 */
168
169/* The alarm system needs to be able to wakeup 'some poller' sometimes
170 * (specifically when a new alarm needs to be triggered earlier than the next
171 * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
172 * case occurs. */
173
174static grpc_fd *fd_freelist = NULL;
175static gpr_mu fd_freelist_mu;
176
Craig Tillerc67cc992017-04-27 10:15:51 -0700177static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
178
179static void fd_global_shutdown(void) {
180 gpr_mu_lock(&fd_freelist_mu);
181 gpr_mu_unlock(&fd_freelist_mu);
182 while (fd_freelist != NULL) {
183 grpc_fd *fd = fd_freelist;
184 fd_freelist = fd_freelist->freelist_next;
Craig Tillerc67cc992017-04-27 10:15:51 -0700185 gpr_free(fd);
186 }
187 gpr_mu_destroy(&fd_freelist_mu);
188}
189
190static grpc_fd *fd_create(int fd, const char *name) {
191 grpc_fd *new_fd = NULL;
192
193 gpr_mu_lock(&fd_freelist_mu);
194 if (fd_freelist != NULL) {
195 new_fd = fd_freelist;
196 fd_freelist = fd_freelist->freelist_next;
197 }
198 gpr_mu_unlock(&fd_freelist_mu);
199
200 if (new_fd == NULL) {
201 new_fd = gpr_malloc(sizeof(grpc_fd));
Craig Tillerc67cc992017-04-27 10:15:51 -0700202 }
203
Craig Tillerc67cc992017-04-27 10:15:51 -0700204 new_fd->fd = fd;
Craig Tillerc67cc992017-04-27 10:15:51 -0700205 grpc_lfev_init(&new_fd->read_closure);
206 grpc_lfev_init(&new_fd->write_closure);
207 gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
208
209 new_fd->freelist_next = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700210
211 char *fd_name;
212 gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
213 grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
214#ifdef GRPC_FD_REF_COUNT_DEBUG
215 gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, (void *)new_fd, fd_name);
216#endif
217 gpr_free(fd_name);
Craig Tiller9ddb3152017-04-27 21:32:56 +0000218
219 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET),
220 .data.ptr = new_fd};
221 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
222 gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
223 }
224
Craig Tillerc67cc992017-04-27 10:15:51 -0700225 return new_fd;
226}
227
Craig Tiller4509c472017-04-27 19:05:13 +0000228static int fd_wrapped_fd(grpc_fd *fd) { return fd->fd; }
Craig Tillerc67cc992017-04-27 10:15:51 -0700229
Craig Tiller9ddb3152017-04-27 21:32:56 +0000230/* Might be called multiple times */
231static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
232 if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure,
233 GRPC_ERROR_REF(why))) {
234 shutdown(fd->fd, SHUT_RDWR);
235 grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why));
236 }
237 GRPC_ERROR_UNREF(why);
238}
239
Craig Tillerc67cc992017-04-27 10:15:51 -0700240static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
241 grpc_closure *on_done, int *release_fd,
242 const char *reason) {
Craig Tillerc67cc992017-04-27 10:15:51 -0700243 grpc_error *error = GRPC_ERROR_NONE;
Craig Tillerc67cc992017-04-27 10:15:51 -0700244
Craig Tiller9ddb3152017-04-27 21:32:56 +0000245 if (!grpc_lfev_is_shutdown(&fd->read_closure)) {
246 fd_shutdown(exec_ctx, fd, GRPC_ERROR_CREATE_FROM_COPIED_STRING(reason));
247 }
248
Craig Tillerc67cc992017-04-27 10:15:51 -0700249 /* If release_fd is not NULL, we should be relinquishing control of the file
250 descriptor fd->fd (but we still own the grpc_fd structure). */
251 if (release_fd != NULL) {
252 *release_fd = fd->fd;
253 } else {
254 close(fd->fd);
Craig Tillerc67cc992017-04-27 10:15:51 -0700255 }
256
Craig Tiller4509c472017-04-27 19:05:13 +0000257 grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_REF(error));
Craig Tillerc67cc992017-04-27 10:15:51 -0700258
Craig Tiller4509c472017-04-27 19:05:13 +0000259 grpc_iomgr_unregister_object(&fd->iomgr_object);
260 grpc_lfev_destroy(&fd->read_closure);
261 grpc_lfev_destroy(&fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700262
Craig Tiller4509c472017-04-27 19:05:13 +0000263 gpr_mu_lock(&fd_freelist_mu);
264 fd->freelist_next = fd_freelist;
265 fd_freelist = fd;
266 gpr_mu_unlock(&fd_freelist_mu);
Craig Tillerc67cc992017-04-27 10:15:51 -0700267}
268
269static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
270 grpc_fd *fd) {
271 gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset);
272 return (grpc_pollset *)notifier;
273}
274
275static bool fd_is_shutdown(grpc_fd *fd) {
276 return grpc_lfev_is_shutdown(&fd->read_closure);
277}
278
Craig Tillerc67cc992017-04-27 10:15:51 -0700279static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
280 grpc_closure *closure) {
281 grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure);
282}
283
284static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
285 grpc_closure *closure) {
286 grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure);
287}
288
289static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
Craig Tiller4509c472017-04-27 19:05:13 +0000290 return NULL; /* TODO(ctiller): add a global workqueue */
291}
292
293static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
294 grpc_pollset *notifier) {
295 grpc_lfev_set_ready(exec_ctx, &fd->read_closure);
296
297 /* Note, it is possible that fd_become_readable might be called twice with
298 different 'notifier's when an fd becomes readable and it is in two epoll
299 sets (This can happen briefly during polling island merges). In such cases
300 it does not really matter which notifer is set as the read_notifier_pollset
301 (They would both point to the same polling island anyway) */
302 /* Use release store to match with acquire load in fd_get_read_notifier */
303 gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier);
304}
305
306static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
307 grpc_lfev_set_ready(exec_ctx, &fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700308}
309
310/*******************************************************************************
311 * Pollset Definitions
312 */
313
Craig Tiller6de05932017-04-28 09:17:38 -0700314GPR_TLS_DECL(g_current_thread_pollset);
315GPR_TLS_DECL(g_current_thread_worker);
316static gpr_atm g_active_poller;
317static pollset_neighbourhood *g_neighbourhoods;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700318static size_t g_num_neighbourhoods;
Craig Tiller6de05932017-04-28 09:17:38 -0700319
Craig Tillerc67cc992017-04-27 10:15:51 -0700320/* Return true if first in list */
Craig Tiller32f90ee2017-04-28 12:46:41 -0700321static bool worker_insert(grpc_pollset *pollset, grpc_pollset_worker *worker) {
322 if (pollset->root_worker == NULL) {
323 pollset->root_worker = worker;
324 worker->next = worker->prev = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700325 return true;
326 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700327 worker->next = pollset->root_worker;
328 worker->prev = worker->next->prev;
329 worker->next->prev = worker;
330 worker->prev->next = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700331 return false;
332 }
333}
334
335/* Return true if last in list */
336typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result;
337
Craig Tiller32f90ee2017-04-28 12:46:41 -0700338static worker_remove_result worker_remove(grpc_pollset *pollset,
Craig Tillerc67cc992017-04-27 10:15:51 -0700339 grpc_pollset_worker *worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700340 if (worker == pollset->root_worker) {
341 if (worker == worker->next) {
342 pollset->root_worker = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700343 return EMPTIED;
344 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700345 pollset->root_worker = worker->next;
346 worker->prev->next = worker->next;
347 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700348 return NEW_ROOT;
349 }
350 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700351 worker->prev->next = worker->next;
352 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700353 return REMOVED;
354 }
355}
356
Craig Tillerba550da2017-05-01 14:26:31 +0000357static size_t choose_neighbourhood(void) {
358 return (size_t)gpr_cpu_current_cpu() % g_num_neighbourhoods;
359}
360
Craig Tiller4509c472017-04-27 19:05:13 +0000361static grpc_error *pollset_global_init(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000362 gpr_tls_init(&g_current_thread_pollset);
363 gpr_tls_init(&g_current_thread_worker);
Craig Tiller6de05932017-04-28 09:17:38 -0700364 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller375eb252017-04-27 23:29:12 +0000365 global_wakeup_fd.read_fd = -1;
366 grpc_error *err = grpc_wakeup_fd_init(&global_wakeup_fd);
367 if (err != GRPC_ERROR_NONE) return err;
Craig Tiller4509c472017-04-27 19:05:13 +0000368 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET),
369 .data.ptr = &global_wakeup_fd};
370 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd, &ev) != 0) {
371 return GRPC_OS_ERROR(errno, "epoll_ctl");
372 }
Craig Tillerba550da2017-05-01 14:26:31 +0000373 g_num_neighbourhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBOURHOODS);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700374 g_neighbourhoods =
375 gpr_zalloc(sizeof(*g_neighbourhoods) * g_num_neighbourhoods);
376 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
377 gpr_mu_init(&g_neighbourhoods[i].mu);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700378 }
Craig Tiller4509c472017-04-27 19:05:13 +0000379 return GRPC_ERROR_NONE;
380}
381
382static void pollset_global_shutdown(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000383 gpr_tls_destroy(&g_current_thread_pollset);
384 gpr_tls_destroy(&g_current_thread_worker);
Craig Tiller375eb252017-04-27 23:29:12 +0000385 if (global_wakeup_fd.read_fd != -1) grpc_wakeup_fd_destroy(&global_wakeup_fd);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700386 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
387 gpr_mu_destroy(&g_neighbourhoods[i].mu);
388 }
389 gpr_free(g_neighbourhoods);
Craig Tiller4509c472017-04-27 19:05:13 +0000390}
391
392static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
Craig Tiller6de05932017-04-28 09:17:38 -0700393 gpr_mu_init(&pollset->mu);
394 *mu = &pollset->mu;
Craig Tillerba550da2017-05-01 14:26:31 +0000395 pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
Craig Tiller6de05932017-04-28 09:17:38 -0700396 pollset->seen_inactive = true;
397 pollset->next = pollset->prev = pollset;
398}
399
400static void pollset_destroy(grpc_pollset *pollset) {
Craig Tillerba550da2017-05-01 14:26:31 +0000401 if (!pollset->seen_inactive) {
402 gpr_mu_lock(&pollset->neighbourhood->mu);
403 pollset->prev->next = pollset->next;
404 pollset->next->prev = pollset->prev;
405 if (pollset == pollset->neighbourhood->active_root) {
406 pollset->neighbourhood->active_root =
407 pollset->next == pollset ? NULL : pollset->next;
408 }
409 gpr_mu_unlock(&pollset->neighbourhood->mu);
Craig Tiller6de05932017-04-28 09:17:38 -0700410 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700411 gpr_mu_destroy(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000412}
413
414static grpc_error *pollset_kick_all(grpc_pollset *pollset) {
415 grpc_error *error = GRPC_ERROR_NONE;
416 if (pollset->root_worker != NULL) {
417 grpc_pollset_worker *worker = pollset->root_worker;
418 do {
419 if (worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700420 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000421 gpr_cv_signal(&worker->cv);
422 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700423 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000424 append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd),
425 "pollset_shutdown");
426 }
427
Craig Tiller32f90ee2017-04-28 12:46:41 -0700428 worker = worker->next;
Craig Tiller4509c472017-04-27 19:05:13 +0000429 } while (worker != pollset->root_worker);
430 }
431 return error;
432}
433
434static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
435 grpc_pollset *pollset) {
Craig Tillerba550da2017-05-01 14:26:31 +0000436 if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL &&
437 pollset->begin_refs == 0) {
Craig Tiller4509c472017-04-27 19:05:13 +0000438 grpc_closure_sched(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE);
439 pollset->shutdown_closure = NULL;
440 }
441}
442
443static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
444 grpc_closure *closure) {
445 GPR_ASSERT(pollset->shutdown_closure == NULL);
446 pollset->shutdown_closure = closure;
447 GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(pollset));
448 pollset_maybe_finish_shutdown(exec_ctx, pollset);
449}
450
Craig Tiller7cb26982017-04-28 23:05:37 +0000451#define MAX_EPOLL_EVENTS 10
Craig Tiller4509c472017-04-27 19:05:13 +0000452
453static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
454 gpr_timespec now) {
455 gpr_timespec timeout;
456 if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
457 return -1;
458 }
459
460 if (gpr_time_cmp(deadline, now) <= 0) {
461 return 0;
462 }
463
464 static const gpr_timespec round_up = {
465 .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1};
466 timeout = gpr_time_sub(deadline, now);
467 int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up));
468 return millis >= 1 ? millis : 1;
469}
470
471static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
472 gpr_timespec now, gpr_timespec deadline) {
473 struct epoll_event events[MAX_EPOLL_EVENTS];
474 static const char *err_desc = "pollset_poll";
475
476 int timeout = poll_deadline_to_millis_timeout(deadline, now);
477
478 if (timeout != 0) {
479 GRPC_SCHEDULING_START_BLOCKING_REGION;
480 }
481 int r;
482 do {
483 r = epoll_wait(g_epfd, events, MAX_EPOLL_EVENTS, timeout);
484 } while (r < 0 && errno == EINTR);
485 if (timeout != 0) {
486 GRPC_SCHEDULING_END_BLOCKING_REGION;
487 }
488
489 if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
490
491 grpc_error *error = GRPC_ERROR_NONE;
492 for (int i = 0; i < r; i++) {
493 void *data_ptr = events[i].data.ptr;
494 if (data_ptr == &global_wakeup_fd) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700495 if (gpr_atm_no_barrier_cas(&g_timer_kick, 1, 0)) {
Craig Tiller375eb252017-04-27 23:29:12 +0000496 grpc_timer_consume_kick();
497 }
Craig Tiller4509c472017-04-27 19:05:13 +0000498 append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
499 err_desc);
500 } else {
501 grpc_fd *fd = (grpc_fd *)(data_ptr);
502 bool cancel = (events[i].events & (EPOLLERR | EPOLLHUP)) != 0;
503 bool read_ev = (events[i].events & (EPOLLIN | EPOLLPRI)) != 0;
504 bool write_ev = (events[i].events & EPOLLOUT) != 0;
505 if (read_ev || cancel) {
506 fd_become_readable(exec_ctx, fd, pollset);
507 }
508 if (write_ev || cancel) {
509 fd_become_writable(exec_ctx, fd);
510 }
511 }
512 }
513
514 return error;
515}
516
Craig Tiller32f90ee2017-04-28 12:46:41 -0700517#if 0
518static void verify_all_entries_in_neighbourhood_list(
519 grpc_pollset *root, bool should_be_seen_inactive) {
520 if (root == NULL) return;
521 grpc_pollset *p = root;
522 do {
523 GPR_ASSERT(p->seen_inactive == should_be_seen_inactive);
524 p = p->next;
525 } while (p != root);
526}
527
528static void verify_neighbourhood_lists(pollset_neighbourhood *neighbourhood) {
529 // assumes neighbourhood->mu locked
530 verify_all_entries_in_neighbourhood_list(neighbourhood->active_root, false);
531 verify_all_entries_in_neighbourhood_list(neighbourhood->inactive_root, true);
532}
533#endif
534
Craig Tiller4509c472017-04-27 19:05:13 +0000535static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker,
536 grpc_pollset_worker **worker_hdl, gpr_timespec *now,
537 gpr_timespec deadline) {
Craig Tiller4509c472017-04-27 19:05:13 +0000538 if (worker_hdl != NULL) *worker_hdl = worker;
539 worker->initialized_cv = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700540 worker->kick_state = UNKICKED;
Craig Tillerba550da2017-05-01 14:26:31 +0000541 pollset->begin_refs++;
Craig Tiller4509c472017-04-27 19:05:13 +0000542
Craig Tiller32f90ee2017-04-28 12:46:41 -0700543 if (pollset->seen_inactive) {
544 // pollset has been observed to be inactive, we need to move back to the
545 // active list
Craig Tillerba550da2017-05-01 14:26:31 +0000546 pollset_neighbourhood *neighbourhood = pollset->neighbourhood =
547 &g_neighbourhoods[choose_neighbourhood()];
Craig Tiller32f90ee2017-04-28 12:46:41 -0700548 gpr_mu_unlock(&pollset->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000549 // pollset unlocked: state may change (even worker->kick_state)
550 retry_lock_neighbourhood:
Craig Tiller32f90ee2017-04-28 12:46:41 -0700551 gpr_mu_lock(&neighbourhood->mu);
552 gpr_mu_lock(&pollset->mu);
553 if (pollset->seen_inactive) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000554 if (neighbourhood != pollset->neighbourhood) {
555 gpr_mu_unlock(&neighbourhood->mu);
556 neighbourhood = pollset->neighbourhood;
557 gpr_mu_unlock(&pollset->mu);
558 goto retry_lock_neighbourhood;
559 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700560 pollset->seen_inactive = false;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000561 if (neighbourhood->active_root == NULL) {
562 neighbourhood->active_root = pollset->next = pollset->prev = pollset;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700563 if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) {
Craig Tiller43bf2592017-04-28 23:21:01 +0000564 worker->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700565 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000566 } else {
567 pollset->next = neighbourhood->active_root;
568 pollset->prev = pollset->next->prev;
569 pollset->next->prev = pollset->prev->next = pollset;
Craig Tiller4509c472017-04-27 19:05:13 +0000570 }
571 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700572 gpr_mu_unlock(&neighbourhood->mu);
573 }
574 worker_insert(pollset, worker);
Craig Tillerba550da2017-05-01 14:26:31 +0000575 pollset->begin_refs--;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700576 if (worker->kick_state == UNKICKED) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000577 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700578 worker->initialized_cv = true;
579 gpr_cv_init(&worker->cv);
Craig Tillerba550da2017-05-01 14:26:31 +0000580 while (worker->kick_state == UNKICKED &&
581 pollset->shutdown_closure == NULL) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700582 if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) &&
583 worker->kick_state == UNKICKED) {
584 worker->kick_state = KICKED;
585 }
Craig Tillerba550da2017-05-01 14:26:31 +0000586 }
Craig Tiller4509c472017-04-27 19:05:13 +0000587 *now = gpr_now(now->clock_type);
588 }
589
Craig Tiller43bf2592017-04-28 23:21:01 +0000590 return worker->kick_state == DESIGNATED_POLLER &&
Craig Tiller32f90ee2017-04-28 12:46:41 -0700591 pollset->shutdown_closure == NULL;
Craig Tiller4509c472017-04-27 19:05:13 +0000592}
593
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700594static bool check_neighbourhood_for_available_poller(
Craig Tillera4b8eb02017-04-29 00:13:52 +0000595 pollset_neighbourhood *neighbourhood) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700596 bool found_worker = false;
597 do {
598 grpc_pollset *inspect = neighbourhood->active_root;
599 if (inspect == NULL) {
600 break;
601 }
602 gpr_mu_lock(&inspect->mu);
603 GPR_ASSERT(!inspect->seen_inactive);
604 grpc_pollset_worker *inspect_worker = inspect->root_worker;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700605 if (inspect_worker != NULL) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000606 do {
Craig Tillerba550da2017-05-01 14:26:31 +0000607 switch (inspect_worker->kick_state) {
608 case UNKICKED:
609 if (gpr_atm_no_barrier_cas(&g_active_poller, 0,
610 (gpr_atm)inspect_worker)) {
611 inspect_worker->kick_state = DESIGNATED_POLLER;
612 if (inspect_worker->initialized_cv) {
613 gpr_cv_signal(&inspect_worker->cv);
614 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000615 }
Craig Tillerba550da2017-05-01 14:26:31 +0000616 // even if we didn't win the cas, there's a worker, we can stop
617 found_worker = true;
618 break;
619 case KICKED:
620 break;
621 case DESIGNATED_POLLER:
622 found_worker = true; // ok, so someone else found the worker, but
623 // we'll accept that
624 break;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700625 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000626 inspect_worker = inspect_worker->next;
627 } while (inspect_worker != inspect->root_worker);
628 }
629 if (!found_worker) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700630 inspect->seen_inactive = true;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000631 if (inspect == neighbourhood->active_root) {
632 if (inspect->next == neighbourhood->active_root) {
633 neighbourhood->active_root = NULL;
634 } else {
635 neighbourhood->active_root = inspect->next;
636 }
637 }
638 inspect->next->prev = inspect->prev;
639 inspect->prev->next = inspect->next;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700640 }
641 gpr_mu_unlock(&inspect->mu);
642 } while (!found_worker);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700643 return found_worker;
644}
645
Craig Tiller4509c472017-04-27 19:05:13 +0000646static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
647 grpc_pollset_worker *worker,
648 grpc_pollset_worker **worker_hdl) {
Craig Tiller8502ecb2017-04-28 14:22:01 -0700649 if (worker_hdl != NULL) *worker_hdl = NULL;
Craig Tillera4b8eb02017-04-29 00:13:52 +0000650 worker->kick_state = KICKED;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700651 if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700652 GPR_ASSERT(!pollset->seen_inactive);
Craig Tillera4b8eb02017-04-29 00:13:52 +0000653 if (worker->next != worker && worker->next->kick_state == UNKICKED) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000654 GPR_ASSERT(worker->next->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700655 gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next);
Craig Tiller43bf2592017-04-28 23:21:01 +0000656 worker->next->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700657 gpr_cv_signal(&worker->next->cv);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700658 if (grpc_exec_ctx_has_work(exec_ctx)) {
659 gpr_mu_unlock(&pollset->mu);
660 grpc_exec_ctx_flush(exec_ctx);
661 gpr_mu_lock(&pollset->mu);
662 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700663 } else {
664 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700665 gpr_mu_unlock(&pollset->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700666 size_t poller_neighbourhood_idx =
667 (size_t)(pollset->neighbourhood - g_neighbourhoods);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700668 bool found_worker = false;
Craig Tillerba550da2017-05-01 14:26:31 +0000669 bool scan_state[MAX_NEIGHBOURHOODS];
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700670 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
671 pollset_neighbourhood *neighbourhood =
672 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
673 g_num_neighbourhoods];
674 if (gpr_mu_trylock(&neighbourhood->mu)) {
675 found_worker =
Craig Tillera4b8eb02017-04-29 00:13:52 +0000676 check_neighbourhood_for_available_poller(neighbourhood);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700677 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000678 scan_state[i] = true;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700679 } else {
Craig Tillerba550da2017-05-01 14:26:31 +0000680 scan_state[i] = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700681 }
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700682 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000683 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
Craig Tillerba550da2017-05-01 14:26:31 +0000684 if (scan_state[i]) continue;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000685 pollset_neighbourhood *neighbourhood =
686 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
687 g_num_neighbourhoods];
688 gpr_mu_lock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000689 found_worker = check_neighbourhood_for_available_poller(neighbourhood);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000690 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700691 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700692 grpc_exec_ctx_flush(exec_ctx);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700693 gpr_mu_lock(&pollset->mu);
694 }
Craig Tiller4509c472017-04-27 19:05:13 +0000695 }
696 if (worker->initialized_cv) {
697 gpr_cv_destroy(&worker->cv);
698 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700699 if (EMPTIED == worker_remove(pollset, worker)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000700 pollset_maybe_finish_shutdown(exec_ctx, pollset);
701 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000702 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller4509c472017-04-27 19:05:13 +0000703}
704
705/* pollset->po.mu lock must be held by the caller before calling this.
706 The function pollset_work() may temporarily release the lock (pollset->po.mu)
707 during the course of its execution but it will always re-acquire the lock and
708 ensure that it is held by the time the function returns */
709static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
710 grpc_pollset_worker **worker_hdl,
711 gpr_timespec now, gpr_timespec deadline) {
712 grpc_pollset_worker worker;
713 grpc_error *error = GRPC_ERROR_NONE;
714 static const char *err_desc = "pollset_work";
715 if (pollset->kicked_without_poller) {
716 pollset->kicked_without_poller = false;
717 return GRPC_ERROR_NONE;
718 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700719 gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
Craig Tiller4509c472017-04-27 19:05:13 +0000720 if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000721 gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
722 GPR_ASSERT(!pollset->shutdown_closure);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000723 GPR_ASSERT(!pollset->seen_inactive);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700724 gpr_mu_unlock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000725 append_error(&error, pollset_epoll(exec_ctx, pollset, now, deadline),
726 err_desc);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700727 gpr_mu_lock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000728 gpr_tls_set(&g_current_thread_worker, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000729 }
730 end_worker(exec_ctx, pollset, &worker, worker_hdl);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700731 gpr_tls_set(&g_current_thread_pollset, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000732 return error;
733}
734
735static grpc_error *pollset_kick(grpc_pollset *pollset,
736 grpc_pollset_worker *specific_worker) {
737 if (specific_worker == NULL) {
738 if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) {
Craig Tiller375eb252017-04-27 23:29:12 +0000739 grpc_pollset_worker *root_worker = pollset->root_worker;
740 if (root_worker == NULL) {
Craig Tiller4509c472017-04-27 19:05:13 +0000741 pollset->kicked_without_poller = true;
742 return GRPC_ERROR_NONE;
Craig Tiller375eb252017-04-27 23:29:12 +0000743 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700744 grpc_pollset_worker *next_worker = root_worker->next;
745 if (root_worker == next_worker &&
746 root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(
747 &g_active_poller)) {
748 root_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000749 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700750 } else if (next_worker->kick_state == UNKICKED) {
751 GPR_ASSERT(next_worker->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700752 next_worker->kick_state = KICKED;
Craig Tiller375eb252017-04-27 23:29:12 +0000753 gpr_cv_signal(&next_worker->cv);
754 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700755 } else {
756 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000757 }
758 } else {
759 return GRPC_ERROR_NONE;
760 }
Craig Tiller43bf2592017-04-28 23:21:01 +0000761 } else if (specific_worker->kick_state == KICKED) {
Craig Tiller4509c472017-04-27 19:05:13 +0000762 return GRPC_ERROR_NONE;
763 } else if (gpr_tls_get(&g_current_thread_worker) ==
764 (intptr_t)specific_worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700765 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000766 return GRPC_ERROR_NONE;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700767 } else if (specific_worker ==
768 (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) {
769 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000770 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700771 } else if (specific_worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700772 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000773 gpr_cv_signal(&specific_worker->cv);
774 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700775 } else {
776 specific_worker->kick_state = KICKED;
777 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000778 }
779}
780
781static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
782 grpc_fd *fd) {}
783
784static grpc_error *kick_poller(void) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700785 gpr_atm_no_barrier_store(&g_timer_kick, 1);
Craig Tiller4509c472017-04-27 19:05:13 +0000786 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
787}
788
789/*******************************************************************************
790 * Workqueue Definitions
791 */
792
793#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
794static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue,
795 const char *file, int line,
796 const char *reason) {
797 return workqueue;
798}
799
800static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
801 const char *file, int line, const char *reason) {}
802#else
803static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) {
804 return workqueue;
805}
806
807static void workqueue_unref(grpc_exec_ctx *exec_ctx,
808 grpc_workqueue *workqueue) {}
809#endif
810
811static grpc_closure_scheduler *workqueue_scheduler(grpc_workqueue *workqueue) {
812 return grpc_schedule_on_exec_ctx;
813}
Craig Tillerc67cc992017-04-27 10:15:51 -0700814
815/*******************************************************************************
816 * Pollset-set Definitions
817 */
818
819static grpc_pollset_set *pollset_set_create(void) {
820 return (grpc_pollset_set *)((intptr_t)0xdeafbeef);
821}
822
823static void pollset_set_destroy(grpc_exec_ctx *exec_ctx,
824 grpc_pollset_set *pss) {}
825
826static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
827 grpc_fd *fd) {}
828
829static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
830 grpc_fd *fd) {}
831
832static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
833 grpc_pollset_set *pss, grpc_pollset *ps) {}
834
835static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
836 grpc_pollset_set *pss, grpc_pollset *ps) {}
837
838static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
839 grpc_pollset_set *bag,
840 grpc_pollset_set *item) {}
841
842static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
843 grpc_pollset_set *bag,
844 grpc_pollset_set *item) {}
845
846/*******************************************************************************
847 * Event engine binding
848 */
849
850static void shutdown_engine(void) {
851 fd_global_shutdown();
852 pollset_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700853}
854
855static const grpc_event_engine_vtable vtable = {
856 .pollset_size = sizeof(grpc_pollset),
857
858 .fd_create = fd_create,
859 .fd_wrapped_fd = fd_wrapped_fd,
860 .fd_orphan = fd_orphan,
861 .fd_shutdown = fd_shutdown,
862 .fd_is_shutdown = fd_is_shutdown,
863 .fd_notify_on_read = fd_notify_on_read,
864 .fd_notify_on_write = fd_notify_on_write,
865 .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
866 .fd_get_workqueue = fd_get_workqueue,
867
868 .pollset_init = pollset_init,
869 .pollset_shutdown = pollset_shutdown,
870 .pollset_destroy = pollset_destroy,
871 .pollset_work = pollset_work,
872 .pollset_kick = pollset_kick,
873 .pollset_add_fd = pollset_add_fd,
874
875 .pollset_set_create = pollset_set_create,
876 .pollset_set_destroy = pollset_set_destroy,
877 .pollset_set_add_pollset = pollset_set_add_pollset,
878 .pollset_set_del_pollset = pollset_set_del_pollset,
879 .pollset_set_add_pollset_set = pollset_set_add_pollset_set,
880 .pollset_set_del_pollset_set = pollset_set_del_pollset_set,
881 .pollset_set_add_fd = pollset_set_add_fd,
882 .pollset_set_del_fd = pollset_set_del_fd,
883
884 .kick_poller = kick_poller,
885
886 .workqueue_ref = workqueue_ref,
887 .workqueue_unref = workqueue_unref,
888 .workqueue_scheduler = workqueue_scheduler,
889
890 .shutdown_engine = shutdown_engine,
891};
892
893/* It is possible that GLIBC has epoll but the underlying kernel doesn't.
894 * Create a dummy epoll_fd to make sure epoll support is available */
Craig Tiller6f0af492017-04-27 19:26:16 +0000895const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
Craig Tillerc67cc992017-04-27 10:15:51 -0700896 if (!grpc_has_wakeup_fd()) {
897 return NULL;
898 }
899
Craig Tiller4509c472017-04-27 19:05:13 +0000900 g_epfd = epoll_create1(EPOLL_CLOEXEC);
901 if (g_epfd < 0) {
902 gpr_log(GPR_ERROR, "epoll unavailable");
Craig Tillerc67cc992017-04-27 10:15:51 -0700903 return NULL;
904 }
905
Craig Tillerc67cc992017-04-27 10:15:51 -0700906 fd_global_init();
907
908 if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
Craig Tiller4509c472017-04-27 19:05:13 +0000909 close(g_epfd);
910 fd_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700911 return NULL;
912 }
913
914 return &vtable;
915}
916
917#else /* defined(GRPC_LINUX_EPOLL) */
918#if defined(GRPC_POSIX_SOCKET)
919#include "src/core/lib/iomgr/ev_posix.h"
920/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return
921 * NULL */
Craig Tiller9ddb3152017-04-27 21:32:56 +0000922const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
923 return NULL;
924}
Craig Tillerc67cc992017-04-27 10:15:51 -0700925#endif /* defined(GRPC_POSIX_SOCKET) */
926#endif /* !defined(GRPC_LINUX_EPOLL) */