blob: 99e4441a6c70c963ce63bd2481edcda66ac3bcee [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 Tillere00d7332017-05-01 15:43:51 +0000120 bool reassigning_neighbourhood;
Craig Tiller4509c472017-04-27 19:05:13 +0000121 grpc_pollset_worker *root_worker;
122 bool kicked_without_poller;
Craig Tiller6de05932017-04-28 09:17:38 -0700123 bool seen_inactive;
Craig Tillerc67cc992017-04-27 10:15:51 -0700124 bool shutting_down; /* Is the pollset shutting down ? */
125 bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
Craig Tiller4509c472017-04-27 19:05:13 +0000126 grpc_closure *shutdown_closure; /* Called after after shutdown is complete */
Craig Tillerba550da2017-05-01 14:26:31 +0000127 int begin_refs;
Craig Tiller6de05932017-04-28 09:17:38 -0700128
129 grpc_pollset *next;
130 grpc_pollset *prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700131};
132
133/*******************************************************************************
134 * Pollset-set Declarations
135 */
Craig Tiller6de05932017-04-28 09:17:38 -0700136
Craig Tillerc67cc992017-04-27 10:15:51 -0700137struct grpc_pollset_set {};
138
139/*******************************************************************************
140 * Common helpers
141 */
142
143static bool append_error(grpc_error **composite, grpc_error *error,
144 const char *desc) {
145 if (error == GRPC_ERROR_NONE) return true;
146 if (*composite == GRPC_ERROR_NONE) {
147 *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
148 }
149 *composite = grpc_error_add_child(*composite, error);
150 return false;
151}
152
153/*******************************************************************************
154 * Fd Definitions
155 */
156
157/* We need to keep a freelist not because of any concerns of malloc performance
158 * but instead so that implementations with multiple threads in (for example)
159 * epoll_wait deal with the race between pollset removal and incoming poll
160 * notifications.
161 *
162 * The problem is that the poller ultimately holds a reference to this
163 * object, so it is very difficult to know when is safe to free it, at least
164 * without some expensive synchronization.
165 *
166 * If we keep the object freelisted, in the worst case losing this race just
167 * becomes a spurious read notification on a reused fd.
168 */
169
170/* The alarm system needs to be able to wakeup 'some poller' sometimes
171 * (specifically when a new alarm needs to be triggered earlier than the next
172 * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
173 * case occurs. */
174
175static grpc_fd *fd_freelist = NULL;
176static gpr_mu fd_freelist_mu;
177
Craig Tillerc67cc992017-04-27 10:15:51 -0700178static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
179
180static void fd_global_shutdown(void) {
181 gpr_mu_lock(&fd_freelist_mu);
182 gpr_mu_unlock(&fd_freelist_mu);
183 while (fd_freelist != NULL) {
184 grpc_fd *fd = fd_freelist;
185 fd_freelist = fd_freelist->freelist_next;
Craig Tillerc67cc992017-04-27 10:15:51 -0700186 gpr_free(fd);
187 }
188 gpr_mu_destroy(&fd_freelist_mu);
189}
190
191static grpc_fd *fd_create(int fd, const char *name) {
192 grpc_fd *new_fd = NULL;
193
194 gpr_mu_lock(&fd_freelist_mu);
195 if (fd_freelist != NULL) {
196 new_fd = fd_freelist;
197 fd_freelist = fd_freelist->freelist_next;
198 }
199 gpr_mu_unlock(&fd_freelist_mu);
200
201 if (new_fd == NULL) {
202 new_fd = gpr_malloc(sizeof(grpc_fd));
Craig Tillerc67cc992017-04-27 10:15:51 -0700203 }
204
Craig Tillerc67cc992017-04-27 10:15:51 -0700205 new_fd->fd = fd;
Craig Tillerc67cc992017-04-27 10:15:51 -0700206 grpc_lfev_init(&new_fd->read_closure);
207 grpc_lfev_init(&new_fd->write_closure);
208 gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
209
210 new_fd->freelist_next = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700211
212 char *fd_name;
213 gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
214 grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
215#ifdef GRPC_FD_REF_COUNT_DEBUG
216 gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, (void *)new_fd, fd_name);
217#endif
218 gpr_free(fd_name);
Craig Tiller9ddb3152017-04-27 21:32:56 +0000219
220 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET),
221 .data.ptr = new_fd};
222 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
223 gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
224 }
225
Craig Tillerc67cc992017-04-27 10:15:51 -0700226 return new_fd;
227}
228
Craig Tiller4509c472017-04-27 19:05:13 +0000229static int fd_wrapped_fd(grpc_fd *fd) { return fd->fd; }
Craig Tillerc67cc992017-04-27 10:15:51 -0700230
Craig Tiller9ddb3152017-04-27 21:32:56 +0000231/* Might be called multiple times */
232static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
233 if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure,
234 GRPC_ERROR_REF(why))) {
235 shutdown(fd->fd, SHUT_RDWR);
236 grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why));
237 }
238 GRPC_ERROR_UNREF(why);
239}
240
Craig Tillerc67cc992017-04-27 10:15:51 -0700241static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
242 grpc_closure *on_done, int *release_fd,
243 const char *reason) {
Craig Tillerc67cc992017-04-27 10:15:51 -0700244 grpc_error *error = GRPC_ERROR_NONE;
Craig Tillerc67cc992017-04-27 10:15:51 -0700245
Craig Tiller9ddb3152017-04-27 21:32:56 +0000246 if (!grpc_lfev_is_shutdown(&fd->read_closure)) {
247 fd_shutdown(exec_ctx, fd, GRPC_ERROR_CREATE_FROM_COPIED_STRING(reason));
248 }
249
Craig Tillerc67cc992017-04-27 10:15:51 -0700250 /* If release_fd is not NULL, we should be relinquishing control of the file
251 descriptor fd->fd (but we still own the grpc_fd structure). */
252 if (release_fd != NULL) {
253 *release_fd = fd->fd;
254 } else {
255 close(fd->fd);
Craig Tillerc67cc992017-04-27 10:15:51 -0700256 }
257
Craig Tiller4509c472017-04-27 19:05:13 +0000258 grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_REF(error));
Craig Tillerc67cc992017-04-27 10:15:51 -0700259
Craig Tiller4509c472017-04-27 19:05:13 +0000260 grpc_iomgr_unregister_object(&fd->iomgr_object);
261 grpc_lfev_destroy(&fd->read_closure);
262 grpc_lfev_destroy(&fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700263
Craig Tiller4509c472017-04-27 19:05:13 +0000264 gpr_mu_lock(&fd_freelist_mu);
265 fd->freelist_next = fd_freelist;
266 fd_freelist = fd;
267 gpr_mu_unlock(&fd_freelist_mu);
Craig Tillerc67cc992017-04-27 10:15:51 -0700268}
269
270static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
271 grpc_fd *fd) {
272 gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset);
273 return (grpc_pollset *)notifier;
274}
275
276static bool fd_is_shutdown(grpc_fd *fd) {
277 return grpc_lfev_is_shutdown(&fd->read_closure);
278}
279
Craig Tillerc67cc992017-04-27 10:15:51 -0700280static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
281 grpc_closure *closure) {
282 grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure);
283}
284
285static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
286 grpc_closure *closure) {
287 grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure);
288}
289
290static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
Craig Tiller4509c472017-04-27 19:05:13 +0000291 return NULL; /* TODO(ctiller): add a global workqueue */
292}
293
294static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
295 grpc_pollset *notifier) {
296 grpc_lfev_set_ready(exec_ctx, &fd->read_closure);
297
298 /* Note, it is possible that fd_become_readable might be called twice with
299 different 'notifier's when an fd becomes readable and it is in two epoll
300 sets (This can happen briefly during polling island merges). In such cases
301 it does not really matter which notifer is set as the read_notifier_pollset
302 (They would both point to the same polling island anyway) */
303 /* Use release store to match with acquire load in fd_get_read_notifier */
304 gpr_atm_rel_store(&fd->read_notifier_pollset, (gpr_atm)notifier);
305}
306
307static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
308 grpc_lfev_set_ready(exec_ctx, &fd->write_closure);
Craig Tillerc67cc992017-04-27 10:15:51 -0700309}
310
311/*******************************************************************************
312 * Pollset Definitions
313 */
314
Craig Tiller6de05932017-04-28 09:17:38 -0700315GPR_TLS_DECL(g_current_thread_pollset);
316GPR_TLS_DECL(g_current_thread_worker);
317static gpr_atm g_active_poller;
318static pollset_neighbourhood *g_neighbourhoods;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700319static size_t g_num_neighbourhoods;
Craig Tiller6de05932017-04-28 09:17:38 -0700320
Craig Tillerc67cc992017-04-27 10:15:51 -0700321/* Return true if first in list */
Craig Tiller32f90ee2017-04-28 12:46:41 -0700322static bool worker_insert(grpc_pollset *pollset, grpc_pollset_worker *worker) {
323 if (pollset->root_worker == NULL) {
324 pollset->root_worker = worker;
325 worker->next = worker->prev = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700326 return true;
327 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700328 worker->next = pollset->root_worker;
329 worker->prev = worker->next->prev;
330 worker->next->prev = worker;
331 worker->prev->next = worker;
Craig Tillerc67cc992017-04-27 10:15:51 -0700332 return false;
333 }
334}
335
336/* Return true if last in list */
337typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result;
338
Craig Tiller32f90ee2017-04-28 12:46:41 -0700339static worker_remove_result worker_remove(grpc_pollset *pollset,
Craig Tillerc67cc992017-04-27 10:15:51 -0700340 grpc_pollset_worker *worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700341 if (worker == pollset->root_worker) {
342 if (worker == worker->next) {
343 pollset->root_worker = NULL;
Craig Tillerc67cc992017-04-27 10:15:51 -0700344 return EMPTIED;
345 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700346 pollset->root_worker = worker->next;
347 worker->prev->next = worker->next;
348 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700349 return NEW_ROOT;
350 }
351 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700352 worker->prev->next = worker->next;
353 worker->next->prev = worker->prev;
Craig Tillerc67cc992017-04-27 10:15:51 -0700354 return REMOVED;
355 }
356}
357
Craig Tillerba550da2017-05-01 14:26:31 +0000358static size_t choose_neighbourhood(void) {
359 return (size_t)gpr_cpu_current_cpu() % g_num_neighbourhoods;
360}
361
Craig Tiller4509c472017-04-27 19:05:13 +0000362static grpc_error *pollset_global_init(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000363 gpr_tls_init(&g_current_thread_pollset);
364 gpr_tls_init(&g_current_thread_worker);
Craig Tiller6de05932017-04-28 09:17:38 -0700365 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller375eb252017-04-27 23:29:12 +0000366 global_wakeup_fd.read_fd = -1;
367 grpc_error *err = grpc_wakeup_fd_init(&global_wakeup_fd);
368 if (err != GRPC_ERROR_NONE) return err;
Craig Tiller4509c472017-04-27 19:05:13 +0000369 struct epoll_event ev = {.events = (uint32_t)(EPOLLIN | EPOLLET),
370 .data.ptr = &global_wakeup_fd};
371 if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd, &ev) != 0) {
372 return GRPC_OS_ERROR(errno, "epoll_ctl");
373 }
Craig Tillerba550da2017-05-01 14:26:31 +0000374 g_num_neighbourhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBOURHOODS);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700375 g_neighbourhoods =
376 gpr_zalloc(sizeof(*g_neighbourhoods) * g_num_neighbourhoods);
377 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
378 gpr_mu_init(&g_neighbourhoods[i].mu);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700379 }
Craig Tiller4509c472017-04-27 19:05:13 +0000380 return GRPC_ERROR_NONE;
381}
382
383static void pollset_global_shutdown(void) {
Craig Tiller4509c472017-04-27 19:05:13 +0000384 gpr_tls_destroy(&g_current_thread_pollset);
385 gpr_tls_destroy(&g_current_thread_worker);
Craig Tiller375eb252017-04-27 23:29:12 +0000386 if (global_wakeup_fd.read_fd != -1) grpc_wakeup_fd_destroy(&global_wakeup_fd);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700387 for (size_t i = 0; i < g_num_neighbourhoods; i++) {
388 gpr_mu_destroy(&g_neighbourhoods[i].mu);
389 }
390 gpr_free(g_neighbourhoods);
Craig Tiller4509c472017-04-27 19:05:13 +0000391}
392
393static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
Craig Tiller6de05932017-04-28 09:17:38 -0700394 gpr_mu_init(&pollset->mu);
395 *mu = &pollset->mu;
Craig Tillerba550da2017-05-01 14:26:31 +0000396 pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
Craig Tiller6de05932017-04-28 09:17:38 -0700397 pollset->seen_inactive = true;
Craig Tiller6de05932017-04-28 09:17:38 -0700398}
399
400static void pollset_destroy(grpc_pollset *pollset) {
Craig Tillere00d7332017-05-01 15:43:51 +0000401 gpr_mu_lock(&pollset->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000402 if (!pollset->seen_inactive) {
Craig Tillere00d7332017-05-01 15:43:51 +0000403 pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
404 gpr_mu_unlock(&pollset->mu);
405retry_lock_neighbourhood:
406 gpr_mu_lock(&neighbourhood->mu);
407 gpr_mu_lock(&pollset->mu);
408 if (!pollset->seen_inactive) {
409 if (pollset->neighbourhood != neighbourhood) {
410 gpr_mu_unlock(&neighbourhood->mu);
411 neighbourhood = pollset->neighbourhood;
412 gpr_mu_unlock(&pollset->mu);
413 goto retry_lock_neighbourhood;
414 }
415 pollset->prev->next = pollset->next;
416 pollset->next->prev = pollset->prev;
417 if (pollset == pollset->neighbourhood->active_root) {
418 pollset->neighbourhood->active_root =
419 pollset->next == pollset ? NULL : pollset->next;
420 }
Craig Tillerba550da2017-05-01 14:26:31 +0000421 }
422 gpr_mu_unlock(&pollset->neighbourhood->mu);
Craig Tiller6de05932017-04-28 09:17:38 -0700423 }
Craig Tillere00d7332017-05-01 15:43:51 +0000424 gpr_mu_unlock(&pollset->mu);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700425 gpr_mu_destroy(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000426}
427
428static grpc_error *pollset_kick_all(grpc_pollset *pollset) {
429 grpc_error *error = GRPC_ERROR_NONE;
430 if (pollset->root_worker != NULL) {
431 grpc_pollset_worker *worker = pollset->root_worker;
432 do {
433 if (worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700434 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000435 gpr_cv_signal(&worker->cv);
436 } else {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700437 worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000438 append_error(&error, grpc_wakeup_fd_wakeup(&global_wakeup_fd),
439 "pollset_shutdown");
440 }
441
Craig Tiller32f90ee2017-04-28 12:46:41 -0700442 worker = worker->next;
Craig Tiller4509c472017-04-27 19:05:13 +0000443 } while (worker != pollset->root_worker);
444 }
445 return error;
446}
447
448static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
449 grpc_pollset *pollset) {
Craig Tillerba550da2017-05-01 14:26:31 +0000450 if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL &&
451 pollset->begin_refs == 0) {
Craig Tiller4509c472017-04-27 19:05:13 +0000452 grpc_closure_sched(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE);
453 pollset->shutdown_closure = NULL;
454 }
455}
456
457static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
458 grpc_closure *closure) {
459 GPR_ASSERT(pollset->shutdown_closure == NULL);
460 pollset->shutdown_closure = closure;
461 GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(pollset));
462 pollset_maybe_finish_shutdown(exec_ctx, pollset);
463}
464
Craig Tiller7cb26982017-04-28 23:05:37 +0000465#define MAX_EPOLL_EVENTS 10
Craig Tiller4509c472017-04-27 19:05:13 +0000466
467static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
468 gpr_timespec now) {
469 gpr_timespec timeout;
470 if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
471 return -1;
472 }
473
474 if (gpr_time_cmp(deadline, now) <= 0) {
475 return 0;
476 }
477
478 static const gpr_timespec round_up = {
479 .clock_type = GPR_TIMESPAN, .tv_sec = 0, .tv_nsec = GPR_NS_PER_MS - 1};
480 timeout = gpr_time_sub(deadline, now);
481 int millis = gpr_time_to_millis(gpr_time_add(timeout, round_up));
482 return millis >= 1 ? millis : 1;
483}
484
485static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
486 gpr_timespec now, gpr_timespec deadline) {
487 struct epoll_event events[MAX_EPOLL_EVENTS];
488 static const char *err_desc = "pollset_poll";
489
490 int timeout = poll_deadline_to_millis_timeout(deadline, now);
491
492 if (timeout != 0) {
493 GRPC_SCHEDULING_START_BLOCKING_REGION;
494 }
495 int r;
496 do {
497 r = epoll_wait(g_epfd, events, MAX_EPOLL_EVENTS, timeout);
498 } while (r < 0 && errno == EINTR);
499 if (timeout != 0) {
500 GRPC_SCHEDULING_END_BLOCKING_REGION;
501 }
502
503 if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
504
505 grpc_error *error = GRPC_ERROR_NONE;
506 for (int i = 0; i < r; i++) {
507 void *data_ptr = events[i].data.ptr;
508 if (data_ptr == &global_wakeup_fd) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700509 if (gpr_atm_no_barrier_cas(&g_timer_kick, 1, 0)) {
Craig Tiller375eb252017-04-27 23:29:12 +0000510 grpc_timer_consume_kick();
511 }
Craig Tiller4509c472017-04-27 19:05:13 +0000512 append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
513 err_desc);
514 } else {
515 grpc_fd *fd = (grpc_fd *)(data_ptr);
516 bool cancel = (events[i].events & (EPOLLERR | EPOLLHUP)) != 0;
517 bool read_ev = (events[i].events & (EPOLLIN | EPOLLPRI)) != 0;
518 bool write_ev = (events[i].events & EPOLLOUT) != 0;
519 if (read_ev || cancel) {
520 fd_become_readable(exec_ctx, fd, pollset);
521 }
522 if (write_ev || cancel) {
523 fd_become_writable(exec_ctx, fd);
524 }
525 }
526 }
527
528 return error;
529}
530
Craig Tiller32f90ee2017-04-28 12:46:41 -0700531#if 0
532static void verify_all_entries_in_neighbourhood_list(
533 grpc_pollset *root, bool should_be_seen_inactive) {
534 if (root == NULL) return;
535 grpc_pollset *p = root;
536 do {
537 GPR_ASSERT(p->seen_inactive == should_be_seen_inactive);
538 p = p->next;
539 } while (p != root);
540}
541
542static void verify_neighbourhood_lists(pollset_neighbourhood *neighbourhood) {
543 // assumes neighbourhood->mu locked
544 verify_all_entries_in_neighbourhood_list(neighbourhood->active_root, false);
545 verify_all_entries_in_neighbourhood_list(neighbourhood->inactive_root, true);
546}
547#endif
548
Craig Tiller4509c472017-04-27 19:05:13 +0000549static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker,
550 grpc_pollset_worker **worker_hdl, gpr_timespec *now,
551 gpr_timespec deadline) {
Craig Tiller4509c472017-04-27 19:05:13 +0000552 if (worker_hdl != NULL) *worker_hdl = worker;
553 worker->initialized_cv = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700554 worker->kick_state = UNKICKED;
Craig Tillerba550da2017-05-01 14:26:31 +0000555 pollset->begin_refs++;
Craig Tiller4509c472017-04-27 19:05:13 +0000556
Craig Tiller32f90ee2017-04-28 12:46:41 -0700557 if (pollset->seen_inactive) {
558 // pollset has been observed to be inactive, we need to move back to the
559 // active list
Craig Tillere00d7332017-05-01 15:43:51 +0000560 bool is_reassigning = false;
561 if (!pollset->reassigning_neighbourhood) {
562 is_reassigning = true;
563 pollset->reassigning_neighbourhood = true;
564 pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()];
565 }
566 pollset_neighbourhood *neighbourhood = pollset->neighbourhood;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700567 gpr_mu_unlock(&pollset->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000568 // pollset unlocked: state may change (even worker->kick_state)
569 retry_lock_neighbourhood:
Craig Tiller32f90ee2017-04-28 12:46:41 -0700570 gpr_mu_lock(&neighbourhood->mu);
571 gpr_mu_lock(&pollset->mu);
572 if (pollset->seen_inactive) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000573 if (neighbourhood != pollset->neighbourhood) {
574 gpr_mu_unlock(&neighbourhood->mu);
575 neighbourhood = pollset->neighbourhood;
576 gpr_mu_unlock(&pollset->mu);
577 goto retry_lock_neighbourhood;
578 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700579 pollset->seen_inactive = false;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000580 if (neighbourhood->active_root == NULL) {
581 neighbourhood->active_root = pollset->next = pollset->prev = pollset;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700582 if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)worker)) {
Craig Tiller43bf2592017-04-28 23:21:01 +0000583 worker->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700584 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000585 } else {
586 pollset->next = neighbourhood->active_root;
587 pollset->prev = pollset->next->prev;
588 pollset->next->prev = pollset->prev->next = pollset;
Craig Tiller4509c472017-04-27 19:05:13 +0000589 }
590 }
Craig Tillere00d7332017-05-01 15:43:51 +0000591 if (is_reassigning) {
592 GPR_ASSERT(pollset->reassigning_neighbourhood);
593 pollset->reassigning_neighbourhood = false;
594 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700595 gpr_mu_unlock(&neighbourhood->mu);
596 }
597 worker_insert(pollset, worker);
Craig Tillerba550da2017-05-01 14:26:31 +0000598 pollset->begin_refs--;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700599 if (worker->kick_state == UNKICKED) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000600 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700601 worker->initialized_cv = true;
602 gpr_cv_init(&worker->cv);
Craig Tillerba550da2017-05-01 14:26:31 +0000603 while (worker->kick_state == UNKICKED &&
604 pollset->shutdown_closure == NULL) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700605 if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) &&
606 worker->kick_state == UNKICKED) {
607 worker->kick_state = KICKED;
608 }
Craig Tillerba550da2017-05-01 14:26:31 +0000609 }
Craig Tiller4509c472017-04-27 19:05:13 +0000610 *now = gpr_now(now->clock_type);
611 }
612
Craig Tiller43bf2592017-04-28 23:21:01 +0000613 return worker->kick_state == DESIGNATED_POLLER &&
Craig Tiller32f90ee2017-04-28 12:46:41 -0700614 pollset->shutdown_closure == NULL;
Craig Tiller4509c472017-04-27 19:05:13 +0000615}
616
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700617static bool check_neighbourhood_for_available_poller(
Craig Tillera4b8eb02017-04-29 00:13:52 +0000618 pollset_neighbourhood *neighbourhood) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700619 bool found_worker = false;
620 do {
621 grpc_pollset *inspect = neighbourhood->active_root;
622 if (inspect == NULL) {
623 break;
624 }
625 gpr_mu_lock(&inspect->mu);
626 GPR_ASSERT(!inspect->seen_inactive);
627 grpc_pollset_worker *inspect_worker = inspect->root_worker;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700628 if (inspect_worker != NULL) {
Craig Tillera4b8eb02017-04-29 00:13:52 +0000629 do {
Craig Tillerba550da2017-05-01 14:26:31 +0000630 switch (inspect_worker->kick_state) {
631 case UNKICKED:
632 if (gpr_atm_no_barrier_cas(&g_active_poller, 0,
633 (gpr_atm)inspect_worker)) {
634 inspect_worker->kick_state = DESIGNATED_POLLER;
635 if (inspect_worker->initialized_cv) {
636 gpr_cv_signal(&inspect_worker->cv);
637 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000638 }
Craig Tillerba550da2017-05-01 14:26:31 +0000639 // even if we didn't win the cas, there's a worker, we can stop
640 found_worker = true;
641 break;
642 case KICKED:
643 break;
644 case DESIGNATED_POLLER:
645 found_worker = true; // ok, so someone else found the worker, but
646 // we'll accept that
647 break;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700648 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000649 inspect_worker = inspect_worker->next;
650 } while (inspect_worker != inspect->root_worker);
651 }
652 if (!found_worker) {
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700653 inspect->seen_inactive = true;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000654 if (inspect == neighbourhood->active_root) {
Craig Tillere00d7332017-05-01 15:43:51 +0000655 neighbourhood->active_root = inspect->next == inspect ? NULL : inspect->next;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000656 }
657 inspect->next->prev = inspect->prev;
658 inspect->prev->next = inspect->next;
Craig Tillere00d7332017-05-01 15:43:51 +0000659 inspect->next = inspect->prev = NULL;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700660 }
661 gpr_mu_unlock(&inspect->mu);
662 } while (!found_worker);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700663 return found_worker;
664}
665
Craig Tiller4509c472017-04-27 19:05:13 +0000666static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
667 grpc_pollset_worker *worker,
668 grpc_pollset_worker **worker_hdl) {
Craig Tiller8502ecb2017-04-28 14:22:01 -0700669 if (worker_hdl != NULL) *worker_hdl = NULL;
Craig Tillera4b8eb02017-04-29 00:13:52 +0000670 worker->kick_state = KICKED;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700671 if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700672 GPR_ASSERT(!pollset->seen_inactive);
Craig Tillera4b8eb02017-04-29 00:13:52 +0000673 if (worker->next != worker && worker->next->kick_state == UNKICKED) {
Craig Tiller2acab6e2017-04-30 23:06:33 +0000674 GPR_ASSERT(worker->next->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700675 gpr_atm_no_barrier_store(&g_active_poller, (gpr_atm)worker->next);
Craig Tiller43bf2592017-04-28 23:21:01 +0000676 worker->next->kick_state = DESIGNATED_POLLER;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700677 gpr_cv_signal(&worker->next->cv);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700678 if (grpc_exec_ctx_has_work(exec_ctx)) {
679 gpr_mu_unlock(&pollset->mu);
680 grpc_exec_ctx_flush(exec_ctx);
681 gpr_mu_lock(&pollset->mu);
682 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700683 } else {
684 gpr_atm_no_barrier_store(&g_active_poller, 0);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700685 gpr_mu_unlock(&pollset->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700686 size_t poller_neighbourhood_idx =
687 (size_t)(pollset->neighbourhood - g_neighbourhoods);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700688 bool found_worker = false;
Craig Tillerba550da2017-05-01 14:26:31 +0000689 bool scan_state[MAX_NEIGHBOURHOODS];
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700690 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
691 pollset_neighbourhood *neighbourhood =
692 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
693 g_num_neighbourhoods];
694 if (gpr_mu_trylock(&neighbourhood->mu)) {
695 found_worker =
Craig Tillera4b8eb02017-04-29 00:13:52 +0000696 check_neighbourhood_for_available_poller(neighbourhood);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700697 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000698 scan_state[i] = true;
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700699 } else {
Craig Tillerba550da2017-05-01 14:26:31 +0000700 scan_state[i] = false;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700701 }
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700702 }
Craig Tiller2acab6e2017-04-30 23:06:33 +0000703 for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) {
Craig Tillerba550da2017-05-01 14:26:31 +0000704 if (scan_state[i]) continue;
Craig Tiller2acab6e2017-04-30 23:06:33 +0000705 pollset_neighbourhood *neighbourhood =
706 &g_neighbourhoods[(poller_neighbourhood_idx + i) %
707 g_num_neighbourhoods];
708 gpr_mu_lock(&neighbourhood->mu);
Craig Tillerba550da2017-05-01 14:26:31 +0000709 found_worker = check_neighbourhood_for_available_poller(neighbourhood);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000710 gpr_mu_unlock(&neighbourhood->mu);
Craig Tillerbbf4c7a2017-04-28 15:12:10 -0700711 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700712 grpc_exec_ctx_flush(exec_ctx);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700713 gpr_mu_lock(&pollset->mu);
714 }
Craig Tiller4509c472017-04-27 19:05:13 +0000715 }
716 if (worker->initialized_cv) {
717 gpr_cv_destroy(&worker->cv);
718 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700719 if (EMPTIED == worker_remove(pollset, worker)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000720 pollset_maybe_finish_shutdown(exec_ctx, pollset);
721 }
Craig Tillera4b8eb02017-04-29 00:13:52 +0000722 GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker);
Craig Tiller4509c472017-04-27 19:05:13 +0000723}
724
725/* pollset->po.mu lock must be held by the caller before calling this.
726 The function pollset_work() may temporarily release the lock (pollset->po.mu)
727 during the course of its execution but it will always re-acquire the lock and
728 ensure that it is held by the time the function returns */
729static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
730 grpc_pollset_worker **worker_hdl,
731 gpr_timespec now, gpr_timespec deadline) {
732 grpc_pollset_worker worker;
733 grpc_error *error = GRPC_ERROR_NONE;
734 static const char *err_desc = "pollset_work";
735 if (pollset->kicked_without_poller) {
736 pollset->kicked_without_poller = false;
737 return GRPC_ERROR_NONE;
738 }
Craig Tiller8502ecb2017-04-28 14:22:01 -0700739 gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
Craig Tiller4509c472017-04-27 19:05:13 +0000740 if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) {
Craig Tiller4509c472017-04-27 19:05:13 +0000741 gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
742 GPR_ASSERT(!pollset->shutdown_closure);
Craig Tiller2acab6e2017-04-30 23:06:33 +0000743 GPR_ASSERT(!pollset->seen_inactive);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700744 gpr_mu_unlock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000745 append_error(&error, pollset_epoll(exec_ctx, pollset, now, deadline),
746 err_desc);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700747 gpr_mu_lock(&pollset->mu);
Craig Tiller4509c472017-04-27 19:05:13 +0000748 gpr_tls_set(&g_current_thread_worker, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000749 }
750 end_worker(exec_ctx, pollset, &worker, worker_hdl);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700751 gpr_tls_set(&g_current_thread_pollset, 0);
Craig Tiller4509c472017-04-27 19:05:13 +0000752 return error;
753}
754
755static grpc_error *pollset_kick(grpc_pollset *pollset,
756 grpc_pollset_worker *specific_worker) {
757 if (specific_worker == NULL) {
758 if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) {
Craig Tiller375eb252017-04-27 23:29:12 +0000759 grpc_pollset_worker *root_worker = pollset->root_worker;
760 if (root_worker == NULL) {
Craig Tiller4509c472017-04-27 19:05:13 +0000761 pollset->kicked_without_poller = true;
762 return GRPC_ERROR_NONE;
Craig Tiller375eb252017-04-27 23:29:12 +0000763 }
Craig Tiller32f90ee2017-04-28 12:46:41 -0700764 grpc_pollset_worker *next_worker = root_worker->next;
765 if (root_worker == next_worker &&
766 root_worker == (grpc_pollset_worker *)gpr_atm_no_barrier_load(
767 &g_active_poller)) {
768 root_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000769 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700770 } else if (next_worker->kick_state == UNKICKED) {
771 GPR_ASSERT(next_worker->initialized_cv);
Craig Tiller32f90ee2017-04-28 12:46:41 -0700772 next_worker->kick_state = KICKED;
Craig Tiller375eb252017-04-27 23:29:12 +0000773 gpr_cv_signal(&next_worker->cv);
774 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700775 } else {
776 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000777 }
778 } else {
779 return GRPC_ERROR_NONE;
780 }
Craig Tiller43bf2592017-04-28 23:21:01 +0000781 } else if (specific_worker->kick_state == KICKED) {
Craig Tiller4509c472017-04-27 19:05:13 +0000782 return GRPC_ERROR_NONE;
783 } else if (gpr_tls_get(&g_current_thread_worker) ==
784 (intptr_t)specific_worker) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700785 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000786 return GRPC_ERROR_NONE;
Craig Tiller32f90ee2017-04-28 12:46:41 -0700787 } else if (specific_worker ==
788 (grpc_pollset_worker *)gpr_atm_no_barrier_load(&g_active_poller)) {
789 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000790 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
Craig Tiller8502ecb2017-04-28 14:22:01 -0700791 } else if (specific_worker->initialized_cv) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700792 specific_worker->kick_state = KICKED;
Craig Tiller4509c472017-04-27 19:05:13 +0000793 gpr_cv_signal(&specific_worker->cv);
794 return GRPC_ERROR_NONE;
Craig Tiller8502ecb2017-04-28 14:22:01 -0700795 } else {
796 specific_worker->kick_state = KICKED;
797 return GRPC_ERROR_NONE;
Craig Tiller4509c472017-04-27 19:05:13 +0000798 }
799}
800
801static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
802 grpc_fd *fd) {}
803
804static grpc_error *kick_poller(void) {
Craig Tiller32f90ee2017-04-28 12:46:41 -0700805 gpr_atm_no_barrier_store(&g_timer_kick, 1);
Craig Tiller4509c472017-04-27 19:05:13 +0000806 return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
807}
808
809/*******************************************************************************
810 * Workqueue Definitions
811 */
812
813#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
814static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue,
815 const char *file, int line,
816 const char *reason) {
817 return workqueue;
818}
819
820static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
821 const char *file, int line, const char *reason) {}
822#else
823static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) {
824 return workqueue;
825}
826
827static void workqueue_unref(grpc_exec_ctx *exec_ctx,
828 grpc_workqueue *workqueue) {}
829#endif
830
831static grpc_closure_scheduler *workqueue_scheduler(grpc_workqueue *workqueue) {
832 return grpc_schedule_on_exec_ctx;
833}
Craig Tillerc67cc992017-04-27 10:15:51 -0700834
835/*******************************************************************************
836 * Pollset-set Definitions
837 */
838
839static grpc_pollset_set *pollset_set_create(void) {
840 return (grpc_pollset_set *)((intptr_t)0xdeafbeef);
841}
842
843static void pollset_set_destroy(grpc_exec_ctx *exec_ctx,
844 grpc_pollset_set *pss) {}
845
846static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
847 grpc_fd *fd) {}
848
849static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
850 grpc_fd *fd) {}
851
852static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
853 grpc_pollset_set *pss, grpc_pollset *ps) {}
854
855static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
856 grpc_pollset_set *pss, grpc_pollset *ps) {}
857
858static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
859 grpc_pollset_set *bag,
860 grpc_pollset_set *item) {}
861
862static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
863 grpc_pollset_set *bag,
864 grpc_pollset_set *item) {}
865
866/*******************************************************************************
867 * Event engine binding
868 */
869
870static void shutdown_engine(void) {
871 fd_global_shutdown();
872 pollset_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700873}
874
875static const grpc_event_engine_vtable vtable = {
876 .pollset_size = sizeof(grpc_pollset),
877
878 .fd_create = fd_create,
879 .fd_wrapped_fd = fd_wrapped_fd,
880 .fd_orphan = fd_orphan,
881 .fd_shutdown = fd_shutdown,
882 .fd_is_shutdown = fd_is_shutdown,
883 .fd_notify_on_read = fd_notify_on_read,
884 .fd_notify_on_write = fd_notify_on_write,
885 .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
886 .fd_get_workqueue = fd_get_workqueue,
887
888 .pollset_init = pollset_init,
889 .pollset_shutdown = pollset_shutdown,
890 .pollset_destroy = pollset_destroy,
891 .pollset_work = pollset_work,
892 .pollset_kick = pollset_kick,
893 .pollset_add_fd = pollset_add_fd,
894
895 .pollset_set_create = pollset_set_create,
896 .pollset_set_destroy = pollset_set_destroy,
897 .pollset_set_add_pollset = pollset_set_add_pollset,
898 .pollset_set_del_pollset = pollset_set_del_pollset,
899 .pollset_set_add_pollset_set = pollset_set_add_pollset_set,
900 .pollset_set_del_pollset_set = pollset_set_del_pollset_set,
901 .pollset_set_add_fd = pollset_set_add_fd,
902 .pollset_set_del_fd = pollset_set_del_fd,
903
904 .kick_poller = kick_poller,
905
906 .workqueue_ref = workqueue_ref,
907 .workqueue_unref = workqueue_unref,
908 .workqueue_scheduler = workqueue_scheduler,
909
910 .shutdown_engine = shutdown_engine,
911};
912
913/* It is possible that GLIBC has epoll but the underlying kernel doesn't.
914 * Create a dummy epoll_fd to make sure epoll support is available */
Craig Tiller6f0af492017-04-27 19:26:16 +0000915const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
Craig Tillerc67cc992017-04-27 10:15:51 -0700916 if (!grpc_has_wakeup_fd()) {
917 return NULL;
918 }
919
Craig Tiller4509c472017-04-27 19:05:13 +0000920 g_epfd = epoll_create1(EPOLL_CLOEXEC);
921 if (g_epfd < 0) {
922 gpr_log(GPR_ERROR, "epoll unavailable");
Craig Tillerc67cc992017-04-27 10:15:51 -0700923 return NULL;
924 }
925
Craig Tillerc67cc992017-04-27 10:15:51 -0700926 fd_global_init();
927
928 if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
Craig Tiller4509c472017-04-27 19:05:13 +0000929 close(g_epfd);
930 fd_global_shutdown();
Craig Tillerc67cc992017-04-27 10:15:51 -0700931 return NULL;
932 }
933
934 return &vtable;
935}
936
937#else /* defined(GRPC_LINUX_EPOLL) */
938#if defined(GRPC_POSIX_SOCKET)
939#include "src/core/lib/iomgr/ev_posix.h"
940/* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return
941 * NULL */
Craig Tiller9ddb3152017-04-27 21:32:56 +0000942const grpc_event_engine_vtable *grpc_init_epoll1_linux(bool explicit_request) {
943 return NULL;
944}
Craig Tillerc67cc992017-04-27 10:15:51 -0700945#endif /* defined(GRPC_POSIX_SOCKET) */
946#endif /* !defined(GRPC_LINUX_EPOLL) */