| 
					
				 | 
			
			
				@@ -0,0 +1,461 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright 2015-2016, Google Inc. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * All rights reserved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Redistribution and use in source and binary forms, with or without 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * modification, are permitted provided that the following conditions are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * met: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Redistributions of source code must retain the above copyright 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * notice, this list of conditions and the following disclaimer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Redistributions in binary form must reproduce the above 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * copyright notice, this list of conditions and the following disclaimer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * in the documentation and/or other materials provided with the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * distribution. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Neither the name of Google Inc. nor the names of its 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * contributors may be used to endorse or promote products derived from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * this software without specific prior written permission. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/iomgr/ev_epoll_linux.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <errno.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <string.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <sys/epoll.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <unistd.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/alloc.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/atm.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/log.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/useful.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/iomgr/iomgr_internal.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* TODO(sreek) Remove this file */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//////////////////////////////////////////////////////////////////////////////// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Definitions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define STATE_NOT_READY ((gpr_atm)0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define STATE_READY ((gpr_atm)1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef enum { POLLABLE_FD, POLLABLE_EPOLL_SET } pollable_type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pollable_type type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_iomgr_object iomgr_object; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} pollable_object; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct polling_island { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pollable_object pollable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int refs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_fd *only_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct polling_island *became; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct polling_island *next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} polling_island; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct grpc_fd { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pollable_object pollable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // each event atomic is a tri state: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //   STATE_NOT_READY - no event received, nobody waiting for it either 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //   STATE_READY - event received, nobody waiting for it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //   closure pointer - no event received, upper layer is waiting for it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_atm on_readable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_atm on_writable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // mutex guarding set_ready & shutdown state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu set_ready_mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool shutdown; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // mutex protecting polling_island 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu polling_island_mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // current polling island 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *polling_island; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_fd *next_free; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct grpc_pollset_worker {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct grpc_pollset { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // current polling island 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *polling_island; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//////////////////////////////////////////////////////////////////////////////// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Polling island implementation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static gpr_mu g_pi_freelist_mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *g_first_free_pi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_pollable_to_epoll_set(pollable_object *pollable, int epoll_set, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      uint32_t events) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct epoll_event ev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ev.events = events; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ev.data.ptr = pollable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int err = epoll_ctl(epoll_set, EPOLL_CTL_ADD, pollable->fd, &ev); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (err < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_ERROR, "epoll_ctl add for %d faild: %s", pollable->fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            strerror(errno)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_fd_to_epoll_set(grpc_fd *fd, int epoll_set) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  add_pollable_to_epoll_set(&fd->pollable, epoll_set, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            EPOLLIN | EPOLLOUT | EPOLLET); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_island_to_epoll_set(polling_island *pi, int epoll_set) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  add_pollable_to_epoll_set(&pi->pollable, epoll_set, EPOLLIN | EPOLLET); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_create(grpc_fd *initial_fd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *r = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&g_pi_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (g_first_free_pi == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = gpr_malloc(sizeof(*r)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r->pollable.type = POLLABLE_EPOLL_SET; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_init(&r->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = g_first_free_pi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    g_first_free_pi = r->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&g_pi_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r->pollable.fd = epoll_create1(EPOLL_CLOEXEC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(r->pollable.fd >= 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&r->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r->only_fd = initial_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r->refs = 2;  // creation of a polling island => a referencing pollset & fd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&r->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  add_fd_to_epoll_set(initial_fd, r->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void polling_island_delete(polling_island *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&g_pi_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->next = g_first_free_pi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  g_first_free_pi = p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&g_pi_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_add(polling_island *p, grpc_fd *fd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->only_fd = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->refs++;  // new fd picks up a ref 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  add_fd_to_epoll_set(fd, p->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_siblings_to(polling_island *siblings, polling_island *dest) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *sibling_tail = dest; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (sibling_tail->next != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    sibling_tail = sibling_tail->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  sibling_tail->next = siblings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_merge(polling_island *a, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                            polling_island *b) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(a != b); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *out; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&GPR_MIN(a, b)->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&GPR_MAX(a, b)->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(a->became == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(b->became == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (a->only_fd == NULL && b->only_fd == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    b->became = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_siblings_to(b, a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_island_to_epoll_set(b, a->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    out = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (a->only_fd == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(b->only_fd != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_fd_to_epoll_set(b->only_fd, a->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    b->became = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    out = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (b->only_fd == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(a->only_fd != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_fd_to_epoll_set(a->only_fd, b->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    a->became = b; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    out = b; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_fd_to_epoll_set(b->only_fd, a->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    a->only_fd = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    b->only_fd = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    b->became = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    out = a; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&a->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&b->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return out; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_update_and_lock(polling_island *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->became != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    do { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      polling_island *from = p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p = p->became; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      bool delete_from = 0 == --from->refs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p->refs++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_mu_unlock(&from->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (delete_from) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        polling_island_delete(from); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } while (p->became != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_ref(polling_island *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void polling_island_drop(polling_island *p) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static polling_island *polling_island_update(polling_island *p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                             int updating_owner_count) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p = polling_island_update_and_lock(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->refs != 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->refs += updating_owner_count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//////////////////////////////////////////////////////////////////////////////// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// FD implementation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static gpr_mu g_fd_freelist_mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_fd *g_first_free_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_fd *fd_create(int fd, const char *name) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_fd *r = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&g_fd_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (g_first_free_fd == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = gpr_malloc(sizeof(*r)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r->pollable.type = POLLABLE_FD; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_atm_rel_store(&r->on_readable, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_atm_rel_store(&r->on_writable, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_init(&r->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_init(&r->set_ready_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = g_first_free_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    g_first_free_fd = r->next_free; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&g_fd_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r->pollable.fd = fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_iomgr_register_object(&r->pollable.iomgr_object, name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r->next_free = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int fd_wrapped_fd(grpc_fd *fd) { return fd->pollable.fd; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      grpc_closure *on_done, int *release_fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      const char *reason) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (release_fd != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    *release_fd = fd->pollable.fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    close(fd->pollable.fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&fd->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (fd->polling_island != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    polling_island_drop(fd->polling_island); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&fd->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&g_fd_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fd->next_free = g_first_free_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  g_first_free_fd = fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_iomgr_unregister_object(&fd->pollable.iomgr_object); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&g_fd_freelist_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_exec_ctx_enqueue(exec_ctx, on_done, true, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      grpc_closure *closure, gpr_atm *state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (gpr_atm_acq_cas(state, STATE_NOT_READY, (gpr_atm)closure)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // state was not ready, and is now the closure - we're done */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // cas failed - we MUST be in STATE_READY (can't request two notifications 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // for the same event) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // flip back to not ready, enqueue the closure directly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(gpr_atm_rel_cas(state, STATE_READY, STATE_NOT_READY)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              grpc_closure *closure) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  notify_on(exec_ctx, fd, closure, &fd->on_readable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               grpc_closure *closure) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  notify_on(exec_ctx, fd, closure, &fd->on_readable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void destroy_fd_freelist(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (g_first_free_fd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_fd *next = g_first_free_fd->next_free; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_destroy(&g_first_free_fd->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(next); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    g_first_free_fd = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             gpr_atm *state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (gpr_atm_acq_cas(state, STATE_NOT_READY, STATE_READY)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // state was not ready, and is now ready - we're done 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // cas failed - either there's a closure queued which we should consume OR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // the state was already STATE_READY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_atm cur_state = gpr_atm_acq_load(state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (cur_state != STATE_READY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // state wasn't STATE_READY - it *must* have been a closure 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // since it's illegal to ask for notification twice, it's safe to assume 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // that we'll resume being the closure 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(gpr_atm_rel_cas(state, cur_state, STATE_NOT_READY)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_exec_ctx_enqueue(exec_ctx, (grpc_closure *)cur_state, !fd->shutdown, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&fd->set_ready_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(!fd->shutdown); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fd->shutdown = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set_ready_locked(exec_ctx, fd, &fd->on_readable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  set_ready_locked(exec_ctx, fd, &fd->on_writable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&fd->set_ready_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//////////////////////////////////////////////////////////////////////////////// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Pollset implementation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_init(&pollset->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *mu = &pollset->mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pollset->polling_island = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void pollset_destroy(grpc_pollset *pollset) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_destroy(&pollset->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (pollset->polling_island) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    polling_island_drop(pollset->polling_island); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           struct grpc_fd *fd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&pollset->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&fd->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polling_island *new; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (fd->polling_island == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (pollset->polling_island == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      new = polling_island_create(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      new = polling_island_add(pollset->polling_island, fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (pollset->polling_island == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    new = polling_island_ref(fd->polling_island); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (pollset->polling_island != fd->polling_island) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    new = polling_island_merge(pollset->polling_island, fd->polling_island); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    new = polling_island_update(pollset->polling_island, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fd->polling_island = pollset->polling_island = new; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&fd->polling_island_mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&pollset->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//////////////////////////////////////////////////////////////////////////////// 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Engine binding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void shutdown_engine(void) { destroy_fd_freelist(); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const grpc_event_engine_vtable vtable = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_size = sizeof(grpc_pollset), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_create = fd_create, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_wrapped_fd = fd_wrapped_fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_orphan = fd_orphan, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_shutdown = fd_shutdown, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_notify_on_read = fd_notify_on_read, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .fd_notify_on_write = fd_notify_on_write, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_init = pollset_init, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_shutdown = pollset_shutdown, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_reset = pollset_reset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_destroy = pollset_destroy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_work = pollset_work, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_kick = pollset_kick, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_add_fd = pollset_add_fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_create = pollset_set_create, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_destroy = pollset_set_destroy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_add_pollset = pollset_set_add_pollset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_del_pollset = pollset_set_del_pollset, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_add_pollset_set = pollset_set_add_pollset_set, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_del_pollset_set = pollset_set_del_pollset_set, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_add_fd = pollset_set_add_fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .pollset_set_del_fd = pollset_set_del_fd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .kick_poller = kick_poller, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .shutdown_engine = shutdown_engine, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool is_epoll_available(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  abort(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const grpc_event_engine_vtable *grpc_init_poll_posix(void) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!is_epoll_available()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return &vtable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |