|  | @@ -69,6 +69,9 @@ static int grpc_polling_trace = 0; /* Disabled by default */
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, (fmt), __VA_ARGS__); \
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Uncomment the following enable extra checks on poll_object operations */
 | 
	
		
			
				|  |  | +/* #define PO_DEBUG */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static int grpc_wakeup_signal = -1;
 | 
	
		
			
				|  |  |  static bool is_grpc_wakeup_signal_initialized = false;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -95,10 +98,42 @@ void grpc_use_signal(int signum) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct polling_island;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +typedef enum {
 | 
	
		
			
				|  |  | +  POLL_OBJ_FD,
 | 
	
		
			
				|  |  | +  POLL_OBJ_POLLSET,
 | 
	
		
			
				|  |  | +  POLL_OBJ_POLLSET_SET
 | 
	
		
			
				|  |  | +} poll_obj_type;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef struct poll_obj {
 | 
	
		
			
				|  |  | +#ifdef PO_DEBUG
 | 
	
		
			
				|  |  | +  poll_obj_type obj_type;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +  gpr_mu mu;
 | 
	
		
			
				|  |  | +  struct polling_island *pi;
 | 
	
		
			
				|  |  | +} poll_obj;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const char *poll_obj_string(poll_obj_type po_type) {
 | 
	
		
			
				|  |  | +  switch (po_type) {
 | 
	
		
			
				|  |  | +    case POLL_OBJ_FD:
 | 
	
		
			
				|  |  | +      return "fd";
 | 
	
		
			
				|  |  | +    case POLL_OBJ_POLLSET:
 | 
	
		
			
				|  |  | +      return "pollset";
 | 
	
		
			
				|  |  | +    case POLL_OBJ_POLLSET_SET:
 | 
	
		
			
				|  |  | +      return "pollset_set";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  GPR_UNREACHABLE_CODE(return "UNKNOWN");
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
		
			
				|  |  |   * Fd Declarations
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define FD_FROM_PO(po) ((grpc_fd *)(po))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  struct grpc_fd {
 | 
	
		
			
				|  |  | +  poll_obj po;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    int fd;
 | 
	
		
			
				|  |  |    /* refst format:
 | 
	
		
			
				|  |  |         bit 0    : 1=Active / 0=Orphaned
 | 
	
	
		
			
				|  | @@ -106,8 +141,6 @@ struct grpc_fd {
 | 
	
		
			
				|  |  |       Ref/Unref by two to avoid altering the orphaned bit */
 | 
	
		
			
				|  |  |    gpr_atm refst;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu mu;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    /* Indicates that the fd is shutdown and that any pending read/write closures
 | 
	
		
			
				|  |  |       should fail */
 | 
	
		
			
				|  |  |    bool shutdown;
 | 
	
	
		
			
				|  | @@ -120,9 +153,6 @@ struct grpc_fd {
 | 
	
		
			
				|  |  |    grpc_closure *read_closure;
 | 
	
		
			
				|  |  |    grpc_closure *write_closure;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* The polling island to which this fd belongs to (protected by mu) */
 | 
	
		
			
				|  |  | -  struct polling_island *polling_island;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    struct grpc_fd *freelist_next;
 | 
	
		
			
				|  |  |    grpc_closure *on_done_closure;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -225,41 +255,21 @@ struct grpc_pollset_worker {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct grpc_pollset {
 | 
	
		
			
				|  |  | -  gpr_mu mu;
 | 
	
		
			
				|  |  | +  poll_obj po;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    grpc_pollset_worker root_worker;
 | 
	
		
			
				|  |  |    bool kicked_without_pollers;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    bool shutting_down;          /* Is the pollset shutting down ? */
 | 
	
		
			
				|  |  |    bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
 | 
	
		
			
				|  |  |    grpc_closure *shutdown_done; /* Called after after shutdown is complete */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* The polling island to which this pollset belongs to */
 | 
	
		
			
				|  |  | -  struct polling_island *polling_island;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
		
			
				|  |  |   * Pollset-set Declarations
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -/* TODO: sreek - Change the pollset_set implementation such that a pollset_set
 | 
	
		
			
				|  |  | - * directly points to a polling_island (and adding an fd/pollset/pollset_set to
 | 
	
		
			
				|  |  | - * the current pollset_set would result in polling island merges. This would
 | 
	
		
			
				|  |  | - * remove the need to maintain fd_count here. This will also significantly
 | 
	
		
			
				|  |  | - * simplify the grpc_fd structure since we would no longer need to explicitly
 | 
	
		
			
				|  |  | - * maintain the orphaned state */
 | 
	
		
			
				|  |  |  struct grpc_pollset_set {
 | 
	
		
			
				|  |  | -  gpr_mu mu;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  size_t pollset_count;
 | 
	
		
			
				|  |  | -  size_t pollset_capacity;
 | 
	
		
			
				|  |  | -  grpc_pollset **pollsets;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  size_t pollset_set_count;
 | 
	
		
			
				|  |  | -  size_t pollset_set_capacity;
 | 
	
		
			
				|  |  | -  struct grpc_pollset_set **pollset_sets;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  size_t fd_count;
 | 
	
		
			
				|  |  | -  size_t fd_capacity;
 | 
	
		
			
				|  |  | -  grpc_fd **fds;
 | 
	
		
			
				|  |  | +  poll_obj po;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
	
		
			
				|  | @@ -915,7 +925,7 @@ static void fd_global_shutdown(void) {
 | 
	
		
			
				|  |  |    while (fd_freelist != NULL) {
 | 
	
		
			
				|  |  |      grpc_fd *fd = fd_freelist;
 | 
	
		
			
				|  |  |      fd_freelist = fd_freelist->freelist_next;
 | 
	
		
			
				|  |  | -    gpr_mu_destroy(&fd->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_destroy(&fd->po.mu);
 | 
	
		
			
				|  |  |      gpr_free(fd);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_destroy(&fd_freelist_mu);
 | 
	
	
		
			
				|  | @@ -933,13 +943,17 @@ static grpc_fd *fd_create(int fd, const char *name) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (new_fd == NULL) {
 | 
	
		
			
				|  |  |      new_fd = gpr_malloc(sizeof(grpc_fd));
 | 
	
		
			
				|  |  | -    gpr_mu_init(&new_fd->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_init(&new_fd->po.mu);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Note: It is not really needed to get the new_fd->mu lock here. If this is a
 | 
	
		
			
				|  |  | -     newly created fd (or an fd we got from the freelist), no one else would be
 | 
	
		
			
				|  |  | -     holding a lock to it anyway. */
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&new_fd->mu);
 | 
	
		
			
				|  |  | +  /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
 | 
	
		
			
				|  |  | +   * is a newly created fd (or an fd we got from the freelist), no one else
 | 
	
		
			
				|  |  | +   * would be holding a lock to it anyway. */
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&new_fd->po.mu);
 | 
	
		
			
				|  |  | +  new_fd->po.pi = NULL;
 | 
	
		
			
				|  |  | +#ifdef PO_DEBUG
 | 
	
		
			
				|  |  | +  new_fd->po.obj_type = POLL_OBJ_FD;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
 | 
	
		
			
				|  |  |    new_fd->fd = fd;
 | 
	
	
		
			
				|  | @@ -947,12 +961,11 @@ static grpc_fd *fd_create(int fd, const char *name) {
 | 
	
		
			
				|  |  |    new_fd->orphaned = false;
 | 
	
		
			
				|  |  |    new_fd->read_closure = CLOSURE_NOT_READY;
 | 
	
		
			
				|  |  |    new_fd->write_closure = CLOSURE_NOT_READY;
 | 
	
		
			
				|  |  | -  new_fd->polling_island = NULL;
 | 
	
		
			
				|  |  |    new_fd->freelist_next = NULL;
 | 
	
		
			
				|  |  |    new_fd->on_done_closure = NULL;
 | 
	
		
			
				|  |  |    new_fd->read_notifier_pollset = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&new_fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&new_fd->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    char *fd_name;
 | 
	
		
			
				|  |  |    gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
 | 
	
	
		
			
				|  | @@ -964,17 +977,13 @@ static grpc_fd *fd_create(int fd, const char *name) {
 | 
	
		
			
				|  |  |    return new_fd;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static bool fd_is_orphaned(grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static int fd_wrapped_fd(grpc_fd *fd) {
 | 
	
		
			
				|  |  |    int ret_fd = -1;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    if (!fd->orphaned) {
 | 
	
		
			
				|  |  |      ret_fd = fd->fd;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return ret_fd;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -986,7 +995,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 | 
	
		
			
				|  |  |    grpc_error *error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  |    polling_island *unref_pi = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    fd->on_done_closure = on_done;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* If release_fd is not NULL, we should be relinquishing control of the file
 | 
	
	
		
			
				|  | @@ -1006,25 +1015,25 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Remove the fd from the polling island:
 | 
	
		
			
				|  |  |       - Get a lock on the latest polling island (i.e the last island in the
 | 
	
		
			
				|  |  | -       linked list pointed by fd->polling_island). This is the island that
 | 
	
		
			
				|  |  | +       linked list pointed by fd->po.pi). This is the island that
 | 
	
		
			
				|  |  |         would actually contain the fd
 | 
	
		
			
				|  |  |       - Remove the fd from the latest polling island
 | 
	
		
			
				|  |  |       - Unlock the latest polling island
 | 
	
		
			
				|  |  | -     - Set fd->polling_island to NULL (but remove the ref on the polling island
 | 
	
		
			
				|  |  | +     - Set fd->po.pi to NULL (but remove the ref on the polling island
 | 
	
		
			
				|  |  |         before doing this.) */
 | 
	
		
			
				|  |  | -  if (fd->polling_island != NULL) {
 | 
	
		
			
				|  |  | -    polling_island *pi_latest = polling_island_lock(fd->polling_island);
 | 
	
		
			
				|  |  | +  if (fd->po.pi != NULL) {
 | 
	
		
			
				|  |  | +    polling_island *pi_latest = polling_island_lock(fd->po.pi);
 | 
	
		
			
				|  |  |      polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error);
 | 
	
		
			
				|  |  |      gpr_mu_unlock(&pi_latest->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    unref_pi = fd->polling_island;
 | 
	
		
			
				|  |  | -    fd->polling_island = NULL;
 | 
	
		
			
				|  |  | +    unref_pi = fd->po.pi;
 | 
	
		
			
				|  |  | +    fd->po.pi = NULL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error),
 | 
	
		
			
				|  |  |                        NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |    UNREF_BY(fd, 2, reason); /* Drop the reference */
 | 
	
		
			
				|  |  |    if (unref_pi != NULL) {
 | 
	
		
			
				|  |  |      /* Unref stale polling island here, outside the fd lock above.
 | 
	
	
		
			
				|  | @@ -1089,23 +1098,23 @@ static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                                    grpc_fd *fd) {
 | 
	
		
			
				|  |  |    grpc_pollset *notifier = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    notifier = fd->read_notifier_pollset;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return notifier;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static bool fd_is_shutdown(grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    const bool r = fd->shutdown;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |    return r;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Might be called multiple times */
 | 
	
		
			
				|  |  |  static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    /* Do the actual shutdown only once */
 | 
	
		
			
				|  |  |    if (!fd->shutdown) {
 | 
	
		
			
				|  |  |      fd->shutdown = true;
 | 
	
	
		
			
				|  | @@ -1116,28 +1125,28 @@ static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
 | 
	
		
			
				|  |  |      set_ready_locked(exec_ctx, fd, &fd->read_closure);
 | 
	
		
			
				|  |  |      set_ready_locked(exec_ctx, fd, &fd->write_closure);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 | 
	
		
			
				|  |  |                                grpc_closure *closure) {
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    notify_on_locked(exec_ctx, fd, &fd->read_closure, closure);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 | 
	
		
			
				|  |  |                                 grpc_closure *closure) {
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    notify_on_locked(exec_ctx, fd, &fd->write_closure, closure);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | -  grpc_workqueue *workqueue = GRPC_WORKQUEUE_REF(
 | 
	
		
			
				|  |  | -      (grpc_workqueue *)fd->polling_island, "fd_get_workqueue");
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  | +  grpc_workqueue *workqueue =
 | 
	
		
			
				|  |  | +      GRPC_WORKQUEUE_REF((grpc_workqueue *)fd->po.pi, "fd_get_workqueue");
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |    return workqueue;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1277,8 +1286,12 @@ static grpc_error *kick_poller(void) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
 | 
	
		
			
				|  |  | -  gpr_mu_init(&pollset->mu);
 | 
	
		
			
				|  |  | -  *mu = &pollset->mu;
 | 
	
		
			
				|  |  | +  gpr_mu_init(&pollset->po.mu);
 | 
	
		
			
				|  |  | +  *mu = &pollset->po.mu;
 | 
	
		
			
				|  |  | +  pollset->po.pi = NULL;
 | 
	
		
			
				|  |  | +#ifdef PO_DEBUG
 | 
	
		
			
				|  |  | +  pollset->po.obj_type = POLL_OBJ_POLLSET;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
 | 
	
		
			
				|  |  |    pollset->kicked_without_pollers = false;
 | 
	
	
		
			
				|  | @@ -1286,8 +1299,6 @@ static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
 | 
	
		
			
				|  |  |    pollset->shutting_down = false;
 | 
	
		
			
				|  |  |    pollset->finish_shutdown_called = false;
 | 
	
		
			
				|  |  |    pollset->shutdown_done = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  pollset->polling_island = NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Convert a timespec to milliseconds:
 | 
	
	
		
			
				|  | @@ -1317,26 +1328,26 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 | 
	
		
			
				|  |  |                                 grpc_pollset *notifier) {
 | 
	
		
			
				|  |  | -  /* Need the fd->mu since we might be racing with fd_notify_on_read */
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  /* Need the fd->po.mu since we might be racing with fd_notify_on_read */
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    set_ready_locked(exec_ctx, fd, &fd->read_closure);
 | 
	
		
			
				|  |  |    fd->read_notifier_pollset = notifier;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  /* Need the fd->mu since we might be racing with fd_notify_on_write */
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +  /* Need the fd->po.mu since we might be racing with fd_notify_on_write */
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  |    set_ready_locked(exec_ctx, fd, &fd->write_closure);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                             grpc_pollset *ps, char *reason) {
 | 
	
		
			
				|  |  | -  if (ps->polling_island != NULL) {
 | 
	
		
			
				|  |  | -    PI_UNREF(exec_ctx, ps->polling_island, reason);
 | 
	
		
			
				|  |  | +  if (ps->po.pi != NULL) {
 | 
	
		
			
				|  |  | +    PI_UNREF(exec_ctx, ps->po.pi, reason);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  ps->polling_island = NULL;
 | 
	
		
			
				|  |  | +  ps->po.pi = NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
 | 
	
	
		
			
				|  | @@ -1346,12 +1357,12 @@ static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    pollset->finish_shutdown_called = true;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Release the ref and set pollset->polling_island to NULL */
 | 
	
		
			
				|  |  | +  /* Release the ref and set pollset->po.pi to NULL */
 | 
	
		
			
				|  |  |    pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown");
 | 
	
		
			
				|  |  |    grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* pollset->mu lock must be held by the caller before calling this */
 | 
	
		
			
				|  |  | +/* pollset->po.mu lock must be held by the caller before calling this */
 | 
	
		
			
				|  |  |  static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |                               grpc_closure *closure) {
 | 
	
		
			
				|  |  |    GPR_TIMER_BEGIN("pollset_shutdown", 0);
 | 
	
	
		
			
				|  | @@ -1376,7 +1387,7 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |   * here */
 | 
	
		
			
				|  |  |  static void pollset_destroy(grpc_pollset *pollset) {
 | 
	
		
			
				|  |  |    GPR_ASSERT(!pollset_has_workers(pollset));
 | 
	
		
			
				|  |  | -  gpr_mu_destroy(&pollset->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_destroy(&pollset->po.mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_reset(grpc_pollset *pollset) {
 | 
	
	
		
			
				|  | @@ -1386,7 +1397,7 @@ static void pollset_reset(grpc_pollset *pollset) {
 | 
	
		
			
				|  |  |    pollset->finish_shutdown_called = false;
 | 
	
		
			
				|  |  |    pollset->kicked_without_pollers = false;
 | 
	
		
			
				|  |  |    pollset->shutdown_done = NULL;
 | 
	
		
			
				|  |  | -  GPR_ASSERT(pollset->polling_island == NULL);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(pollset->po.pi == NULL);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static bool maybe_do_workqueue_work(grpc_exec_ctx *exec_ctx,
 | 
	
	
		
			
				|  | @@ -1426,7 +1437,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    GPR_TIMER_BEGIN("pollset_work_and_unlock", 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* We need to get the epoll_fd to wait on. The epoll_fd is in inside the
 | 
	
		
			
				|  |  | -     latest polling island pointed by pollset->polling_island.
 | 
	
		
			
				|  |  | +     latest polling island pointed by pollset->po.pi
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |       Since epoll_fd is immutable, we can read it without obtaining the polling
 | 
	
		
			
				|  |  |       island lock. There is however a possibility that the polling island (from
 | 
	
	
		
			
				|  | @@ -1435,36 +1446,36 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |       right-away from epoll_wait() and pick up the latest polling_island the next
 | 
	
		
			
				|  |  |       this function (i.e pollset_work_and_unlock()) is called */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (pollset->polling_island == NULL) {
 | 
	
		
			
				|  |  | -    pollset->polling_island = polling_island_create(exec_ctx, NULL, error);
 | 
	
		
			
				|  |  | -    if (pollset->polling_island == NULL) {
 | 
	
		
			
				|  |  | +  if (pollset->po.pi == NULL) {
 | 
	
		
			
				|  |  | +    pollset->po.pi = polling_island_create(exec_ctx, NULL, error);
 | 
	
		
			
				|  |  | +    if (pollset->po.pi == NULL) {
 | 
	
		
			
				|  |  |        GPR_TIMER_END("pollset_work_and_unlock", 0);
 | 
	
		
			
				|  |  |        return; /* Fatal error. We cannot continue */
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    PI_ADD_REF(pollset->polling_island, "ps");
 | 
	
		
			
				|  |  | +    PI_ADD_REF(pollset->po.pi, "ps");
 | 
	
		
			
				|  |  |      GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p",
 | 
	
		
			
				|  |  | -                       (void *)pollset, (void *)pollset->polling_island);
 | 
	
		
			
				|  |  | +                       (void *)pollset, (void *)pollset->po.pi);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  pi = polling_island_maybe_get_latest(pollset->polling_island);
 | 
	
		
			
				|  |  | +  pi = polling_island_maybe_get_latest(pollset->po.pi);
 | 
	
		
			
				|  |  |    epoll_fd = pi->epoll_fd;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Update the pollset->polling_island since the island being pointed by
 | 
	
		
			
				|  |  | -     pollset->polling_island maybe older than the one pointed by pi) */
 | 
	
		
			
				|  |  | -  if (pollset->polling_island != pi) {
 | 
	
		
			
				|  |  | +  /* Update the pollset->po.pi since the island being pointed by
 | 
	
		
			
				|  |  | +     pollset->po.pi maybe older than the one pointed by pi) */
 | 
	
		
			
				|  |  | +  if (pollset->po.pi != pi) {
 | 
	
		
			
				|  |  |      /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
 | 
	
		
			
				|  |  |         polling island to be deleted */
 | 
	
		
			
				|  |  |      PI_ADD_REF(pi, "ps");
 | 
	
		
			
				|  |  | -    PI_UNREF(exec_ctx, pollset->polling_island, "ps");
 | 
	
		
			
				|  |  | -    pollset->polling_island = pi;
 | 
	
		
			
				|  |  | +    PI_UNREF(exec_ctx, pollset->po.pi, "ps");
 | 
	
		
			
				|  |  | +    pollset->po.pi = pi;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Add an extra ref so that the island does not get destroyed (which means
 | 
	
		
			
				|  |  |       the epoll_fd won't be closed) while we are are doing an epoll_wait() on the
 | 
	
		
			
				|  |  |       epoll_fd */
 | 
	
		
			
				|  |  |    PI_ADD_REF(pi, "ps_work");
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&pollset->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* If we get some workqueue work to do, it might end up completing an item on
 | 
	
		
			
				|  |  |       the completion queue, so there's no need to poll... so we skip that and
 | 
	
	
		
			
				|  | @@ -1537,17 +1548,17 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    GPR_ASSERT(pi != NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Before leaving, release the extra ref we added to the polling island. It
 | 
	
		
			
				|  |  | -     is important to use "pi" here (i.e our old copy of pollset->polling_island
 | 
	
		
			
				|  |  | +     is important to use "pi" here (i.e our old copy of pollset->po.pi
 | 
	
		
			
				|  |  |       that we got before releasing the polling island lock). This is because
 | 
	
		
			
				|  |  | -     pollset->polling_island pointer might get udpated in other parts of the
 | 
	
		
			
				|  |  | +     pollset->po.pi pointer might get udpated in other parts of the
 | 
	
		
			
				|  |  |       code when there is an island merge while we are doing epoll_wait() above */
 | 
	
		
			
				|  |  |    PI_UNREF(exec_ctx, pi, "ps_work");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GPR_TIMER_END("pollset_work_and_unlock", 0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* pollset->mu lock must be held by the caller before calling this.
 | 
	
		
			
				|  |  | -   The function pollset_work() may temporarily release the lock (pollset->mu)
 | 
	
		
			
				|  |  | +/* pollset->po.mu lock must be held by the caller before calling this.
 | 
	
		
			
				|  |  | +   The function pollset_work() may temporarily release the lock (pollset->po.mu)
 | 
	
		
			
				|  |  |     during the course of its execution but it will always re-acquire the lock and
 | 
	
		
			
				|  |  |     ensure that it is held by the time the function returns */
 | 
	
		
			
				|  |  |  static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
	
		
			
				|  | @@ -1617,7 +1628,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |                              &g_orig_sigmask, &error);
 | 
	
		
			
				|  |  |      grpc_exec_ctx_flush(exec_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    gpr_mu_lock(&pollset->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_lock(&pollset->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* Note: There is no need to reset worker.is_kicked to 0 since we are no
 | 
	
		
			
				|  |  |         longer going to use this worker */
 | 
	
	
		
			
				|  | @@ -1637,9 +1648,9 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |      GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0);
 | 
	
		
			
				|  |  |      finish_shutdown_locked(exec_ctx, pollset);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&pollset->po.mu);
 | 
	
		
			
				|  |  |      grpc_exec_ctx_flush(exec_ctx);
 | 
	
		
			
				|  |  | -    gpr_mu_lock(&pollset->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_lock(&pollset->po.mu);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    *worker_hdl = NULL;
 | 
	
	
		
			
				|  | @@ -1653,130 +1664,160 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |    return error;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  | -                           grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  GPR_TIMER_BEGIN("pollset_add_fd", 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  grpc_error *error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | +static void add_poll_object(grpc_exec_ctx *exec_ctx, poll_obj *bag,
 | 
	
		
			
				|  |  | +                            poll_obj_type bag_type, poll_obj *item,
 | 
	
		
			
				|  |  | +                            poll_obj_type item_type) {
 | 
	
		
			
				|  |  | +  GPR_TIMER_BEGIN("add_poll_object", 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&pollset->mu);
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | +#ifdef PO_DEBUG
 | 
	
		
			
				|  |  | +  GPR_ASSERT(item->obj_type == item_type);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(bag->obj_type == bag_type);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  grpc_error *error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  |    polling_island *pi_new = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&bag->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&item->mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  retry:
 | 
	
		
			
				|  |  | -  /* 1) If fd->polling_island and pollset->polling_island are both non-NULL and
 | 
	
		
			
				|  |  | -   *    equal, do nothing.
 | 
	
		
			
				|  |  | -   * 2) If fd->polling_island and pollset->polling_island are both NULL, create
 | 
	
		
			
				|  |  | -   *    a new polling island (with a refcount of 2) and make the polling_island
 | 
	
		
			
				|  |  | -   *    fields in both fd and pollset to point to the new island
 | 
	
		
			
				|  |  | -   * 3) If one of fd->polling_island or pollset->polling_island is NULL, update
 | 
	
		
			
				|  |  | -   *    the NULL polling_island field to point to the non-NULL polling_island
 | 
	
		
			
				|  |  | -   *    field (ensure that the refcount on the polling island is incremented by
 | 
	
		
			
				|  |  | -   *    1 to account for the newly added reference)
 | 
	
		
			
				|  |  | -   * 4) Finally, if fd->polling_island and pollset->polling_island are non-NULL
 | 
	
		
			
				|  |  | -   *    and different, merge both the polling islands and update the
 | 
	
		
			
				|  |  | -   *    polling_island fields in both fd and pollset to point to the merged
 | 
	
		
			
				|  |  | -   *    polling island.
 | 
	
		
			
				|  |  | +  /*
 | 
	
		
			
				|  |  | +   * 1) If item->pi and bag->pi are both non-NULL and equal, do nothing
 | 
	
		
			
				|  |  | +   * 2) If item->pi and bag->pi are both NULL, create a new polling island (with
 | 
	
		
			
				|  |  | +   *    a refcount of 2) and point item->pi and bag->pi to the new island
 | 
	
		
			
				|  |  | +   * 3) If exactly one of item->pi or bag->pi is NULL, update it to point to
 | 
	
		
			
				|  |  | +   *    the other's non-NULL pi
 | 
	
		
			
				|  |  | +   * 4) Finally if item->pi and bag-pi are non-NULL and not-equal, merge the
 | 
	
		
			
				|  |  | +   *    polling islands and update item->pi and bag->pi to point to the new
 | 
	
		
			
				|  |  | +   *    island
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (fd->orphaned) {
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | -    /* early out */
 | 
	
		
			
				|  |  | +  /* Early out if we are trying to add an 'fd' to a 'bag' but the fd is already
 | 
	
		
			
				|  |  | +   * orphaned */
 | 
	
		
			
				|  |  | +  if (item_type == POLL_OBJ_FD && (FD_FROM_PO(item))->orphaned) {
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&item->mu);
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&bag->mu);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (fd->polling_island == pollset->polling_island) {
 | 
	
		
			
				|  |  | -    pi_new = fd->polling_island;
 | 
	
		
			
				|  |  | +  if (item->pi == bag->pi) {
 | 
	
		
			
				|  |  | +    pi_new = item->pi;
 | 
	
		
			
				|  |  |      if (pi_new == NULL) {
 | 
	
		
			
				|  |  | -      /* Unlock before creating a new polling island: the polling island will
 | 
	
		
			
				|  |  | -         create a workqueue which creates a file descriptor, and holding an fd
 | 
	
		
			
				|  |  | -         lock here can eventually cause a loop to appear to TSAN (making it
 | 
	
		
			
				|  |  | -         unhappy). We don't think it's a real loop (there's an epoch point where
 | 
	
		
			
				|  |  | -         that loop possibility disappears), but the advantages of keeping TSAN
 | 
	
		
			
				|  |  | -         happy outweigh any performance advantage we might have by keeping the
 | 
	
		
			
				|  |  | -         lock held. */
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | -      pi_new = polling_island_create(exec_ctx, fd, &error);
 | 
	
		
			
				|  |  | -      gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | -      /* Need to reverify any assumptions made between the initial lock and
 | 
	
		
			
				|  |  | -         getting to this branch: if they've changed, we need to throw away our
 | 
	
		
			
				|  |  | -         work and figure things out again. */
 | 
	
		
			
				|  |  | -      if (fd->polling_island != NULL) {
 | 
	
		
			
				|  |  | -        GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | -            "pollset_add_fd: Raced creating new polling island. pi_new: %p "
 | 
	
		
			
				|  |  | -            "(fd: %d, pollset: %p)",
 | 
	
		
			
				|  |  | -            (void *)pi_new, fd->fd, (void *)pollset);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /* No need to lock 'pi_new' here since this is a new polling island and
 | 
	
		
			
				|  |  | -         * no one has a reference to it yet */
 | 
	
		
			
				|  |  | -        polling_island_remove_all_fds_locked(pi_new, true, &error);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /* Ref and unref so that the polling island gets deleted during unref */
 | 
	
		
			
				|  |  | -        PI_ADD_REF(pi_new, "dance_of_destruction");
 | 
	
		
			
				|  |  | -        PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
 | 
	
		
			
				|  |  | -        goto retry;
 | 
	
		
			
				|  |  | +      /* GPR_ASSERT(item->pi == bag->pi == NULL) */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      /* If we are adding an fd to a bag (i.e pollset or pollset_set), then
 | 
	
		
			
				|  |  | +       * we need to do some extra work to make TSAN happy */
 | 
	
		
			
				|  |  | +      if (item_type == POLL_OBJ_FD) {
 | 
	
		
			
				|  |  | +        /* Unlock before creating a new polling island: the polling island will
 | 
	
		
			
				|  |  | +           create a workqueue which creates a file descriptor, and holding an fd
 | 
	
		
			
				|  |  | +           lock here can eventually cause a loop to appear to TSAN (making it
 | 
	
		
			
				|  |  | +           unhappy). We don't think it's a real loop (there's an epoch point
 | 
	
		
			
				|  |  | +           where that loop possibility disappears), but the advantages of
 | 
	
		
			
				|  |  | +           keeping TSAN happy outweigh any performance advantage we might have
 | 
	
		
			
				|  |  | +           by keeping the lock held. */
 | 
	
		
			
				|  |  | +        gpr_mu_unlock(&item->mu);
 | 
	
		
			
				|  |  | +        pi_new = polling_island_create(exec_ctx, FD_FROM_PO(item), &error);
 | 
	
		
			
				|  |  | +        gpr_mu_lock(&item->mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /* Need to reverify any assumptions made between the initial lock and
 | 
	
		
			
				|  |  | +           getting to this branch: if they've changed, we need to throw away our
 | 
	
		
			
				|  |  | +           work and figure things out again. */
 | 
	
		
			
				|  |  | +        if (item->pi != NULL) {
 | 
	
		
			
				|  |  | +          GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | +              "add_poll_object: Raced creating new polling island. pi_new: %p "
 | 
	
		
			
				|  |  | +              "(fd: %d, %s: %p)",
 | 
	
		
			
				|  |  | +              (void *)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type),
 | 
	
		
			
				|  |  | +              (void *)bag);
 | 
	
		
			
				|  |  | +          /* No need to lock 'pi_new' here since this is a new polling island
 | 
	
		
			
				|  |  | +            * and no one has a reference to it yet */
 | 
	
		
			
				|  |  | +          polling_island_remove_all_fds_locked(pi_new, true, &error);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +          /* Ref and unref so that the polling island gets deleted during unref
 | 
	
		
			
				|  |  | +           */
 | 
	
		
			
				|  |  | +          PI_ADD_REF(pi_new, "dance_of_destruction");
 | 
	
		
			
				|  |  | +          PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
 | 
	
		
			
				|  |  | +          goto retry;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        } else {
 | 
	
		
			
				|  |  | -        GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | -            "pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
 | 
	
		
			
				|  |  | -            "pollset: %p)",
 | 
	
		
			
				|  |  | -            (void *)pi_new, fd->fd, (void *)pollset);
 | 
	
		
			
				|  |  | +        pi_new = polling_island_create(exec_ctx, NULL, &error);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | +          "add_poll_object: Created new polling island. pi_new: %p (%s: %p, "
 | 
	
		
			
				|  |  | +          "%s: %p)",
 | 
	
		
			
				|  |  | +          (void *)pi_new, poll_obj_string(item_type), (void *)item,
 | 
	
		
			
				|  |  | +          poll_obj_string(bag_type), (void *)bag);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | +          "add_poll_object: Same polling island. pi: %p (%s, %s)",
 | 
	
		
			
				|  |  | +          (void *)pi_new, poll_obj_string(item_type),
 | 
	
		
			
				|  |  | +          poll_obj_string(bag_type));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } else if (item->pi == NULL) {
 | 
	
		
			
				|  |  | +    /* GPR_ASSERT(bag->pi != NULL) */
 | 
	
		
			
				|  |  | +    /* Make pi_new point to latest pi*/
 | 
	
		
			
				|  |  | +    pi_new = polling_island_lock(bag->pi);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (item_type == POLL_OBJ_FD) {
 | 
	
		
			
				|  |  | +      grpc_fd *fd = FD_FROM_PO(item);
 | 
	
		
			
				|  |  | +      polling_island_add_fds_locked(pi_new, &fd, 1, true, &error);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -  } else if (fd->polling_island == NULL) {
 | 
	
		
			
				|  |  | -    pi_new = polling_island_lock(pollset->polling_island);
 | 
	
		
			
				|  |  | -    polling_island_add_fds_locked(pi_new, &fd, 1, true, &error);
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&pi_new->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&pi_new->mu);
 | 
	
		
			
				|  |  |      GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | -        "pollset_add_fd: fd->pi was NULL. pi_new: %p (fd: %d, pollset: %p, "
 | 
	
		
			
				|  |  | -        "pollset->pi: %p)",
 | 
	
		
			
				|  |  | -        (void *)pi_new, fd->fd, (void *)pollset,
 | 
	
		
			
				|  |  | -        (void *)pollset->polling_island);
 | 
	
		
			
				|  |  | -  } else if (pollset->polling_island == NULL) {
 | 
	
		
			
				|  |  | -    pi_new = polling_island_lock(fd->polling_island);
 | 
	
		
			
				|  |  | +        "add_poll_obj: item->pi was NULL. pi_new: %p (item(%s): %p, "
 | 
	
		
			
				|  |  | +        "bag(%s): %p)",
 | 
	
		
			
				|  |  | +        (void *)pi_new, poll_obj_string(item_type), (void *)item,
 | 
	
		
			
				|  |  | +        poll_obj_string(bag_type), (void *)bag);
 | 
	
		
			
				|  |  | +  } else if (bag->pi == NULL) {
 | 
	
		
			
				|  |  | +    /* GPR_ASSERT(item->pi != NULL) */
 | 
	
		
			
				|  |  | +    /* Make pi_new to point to latest pi */
 | 
	
		
			
				|  |  | +    pi_new = polling_island_lock(item->pi);
 | 
	
		
			
				|  |  |      gpr_mu_unlock(&pi_new->mu);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | -        "pollset_add_fd: pollset->pi was NULL. pi_new: %p (fd: %d, pollset: "
 | 
	
		
			
				|  |  | -        "%p, fd->pi: %p",
 | 
	
		
			
				|  |  | -        (void *)pi_new, fd->fd, (void *)pollset, (void *)fd->polling_island);
 | 
	
		
			
				|  |  | +        "add_poll_obj: bag->pi was NULL. pi_new: %p (item(%s): %p, "
 | 
	
		
			
				|  |  | +        "bag(%s): %p)",
 | 
	
		
			
				|  |  | +        (void *)pi_new, poll_obj_string(item_type), (void *)item,
 | 
	
		
			
				|  |  | +        poll_obj_string(bag_type), (void *)bag);
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    pi_new = polling_island_merge(fd->polling_island, pollset->polling_island,
 | 
	
		
			
				|  |  | -                                  &error);
 | 
	
		
			
				|  |  | +    pi_new = polling_island_merge(item->pi, bag->pi, &error);
 | 
	
		
			
				|  |  |      GRPC_POLLING_TRACE(
 | 
	
		
			
				|  |  | -        "pollset_add_fd: polling islands merged. pi_new: %p (fd: %d, pollset: "
 | 
	
		
			
				|  |  | -        "%p, fd->pi: %p, pollset->pi: %p)",
 | 
	
		
			
				|  |  | -        (void *)pi_new, fd->fd, (void *)pollset, (void *)fd->polling_island,
 | 
	
		
			
				|  |  | -        (void *)pollset->polling_island);
 | 
	
		
			
				|  |  | +        "add_poll_obj: polling islands merged. pi_new: %p (item(%s): %p, "
 | 
	
		
			
				|  |  | +        "bag(%s): %p)",
 | 
	
		
			
				|  |  | +        (void *)pi_new, poll_obj_string(item_type), (void *)item,
 | 
	
		
			
				|  |  | +        poll_obj_string(bag_type), (void *)bag);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* At this point, pi_new is the polling island that both fd->polling_island
 | 
	
		
			
				|  |  | -     and pollset->polling_island must be pointing to */
 | 
	
		
			
				|  |  | +  /* At this point, pi_new is the polling island that both item->pi and bag->pi
 | 
	
		
			
				|  |  | +     MUST be pointing to */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (fd->polling_island != pi_new) {
 | 
	
		
			
				|  |  | -    PI_ADD_REF(pi_new, "fd");
 | 
	
		
			
				|  |  | -    if (fd->polling_island != NULL) {
 | 
	
		
			
				|  |  | -      PI_UNREF(exec_ctx, fd->polling_island, "fd");
 | 
	
		
			
				|  |  | +  if (item->pi != pi_new) {
 | 
	
		
			
				|  |  | +    PI_ADD_REF(pi_new, poll_obj_string(item_type));
 | 
	
		
			
				|  |  | +    if (item->pi != NULL) {
 | 
	
		
			
				|  |  | +      PI_UNREF(exec_ctx, item->pi, poll_obj_string(item_type));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    fd->polling_island = pi_new;
 | 
	
		
			
				|  |  | +    item->pi = pi_new;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (pollset->polling_island != pi_new) {
 | 
	
		
			
				|  |  | -    PI_ADD_REF(pi_new, "ps");
 | 
	
		
			
				|  |  | -    if (pollset->polling_island != NULL) {
 | 
	
		
			
				|  |  | -      PI_UNREF(exec_ctx, pollset->polling_island, "ps");
 | 
	
		
			
				|  |  | +  if (bag->pi != pi_new) {
 | 
	
		
			
				|  |  | +    PI_ADD_REF(pi_new, poll_obj_string(bag_type));
 | 
	
		
			
				|  |  | +    if (bag->pi != NULL) {
 | 
	
		
			
				|  |  | +      PI_UNREF(exec_ctx, bag->pi, poll_obj_string(bag_type));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    pollset->polling_island = pi_new;
 | 
	
		
			
				|  |  | +    bag->pi = pi_new;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&item->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&bag->mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  GRPC_LOG_IF_ERROR("pollset_add_fd", error);
 | 
	
		
			
				|  |  | +  GRPC_LOG_IF_ERROR("add_poll_object", error);
 | 
	
		
			
				|  |  | +  GPR_TIMER_END("add_poll_object", 0);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  GPR_TIMER_END("pollset_add_fd", 0);
 | 
	
		
			
				|  |  | +static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  | +                           grpc_fd *fd) {
 | 
	
		
			
				|  |  | +  add_poll_object(exec_ctx, &pollset->po, POLL_OBJ_POLLSET, &fd->po,
 | 
	
		
			
				|  |  | +                  POLL_OBJ_FD);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*******************************************************************************
 | 
	
	
		
			
				|  | @@ -1784,142 +1825,60 @@ retry:
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_pollset_set *pollset_set_create(void) {
 | 
	
		
			
				|  |  | -  grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set));
 | 
	
		
			
				|  |  | -  memset(pollset_set, 0, sizeof(*pollset_set));
 | 
	
		
			
				|  |  | -  gpr_mu_init(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  return pollset_set;
 | 
	
		
			
				|  |  | +  grpc_pollset_set *pss = gpr_malloc(sizeof(*pss));
 | 
	
		
			
				|  |  | +  gpr_mu_init(&pss->po.mu);
 | 
	
		
			
				|  |  | +  pss->po.pi = NULL;
 | 
	
		
			
				|  |  | +#ifdef PO_DEBUG
 | 
	
		
			
				|  |  | +  pss->po.obj_type = POLL_OBJ_POLLSET_SET;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +  return pss;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void pollset_set_destroy(grpc_pollset_set *pollset_set) {
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  gpr_mu_destroy(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->fd_count; i++) {
 | 
	
		
			
				|  |  | -    GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
 | 
	
		
			
				|  |  | +static void pollset_set_destroy(grpc_pollset_set *pss) {
 | 
	
		
			
				|  |  | +  gpr_mu_destroy(&pss->po.mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (pss->po.pi != NULL) {
 | 
	
		
			
				|  |  | +    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 | 
	
		
			
				|  |  | +    PI_UNREF(&exec_ctx, pss->po.pi, "pss_destroy");
 | 
	
		
			
				|  |  | +    grpc_exec_ctx_finish(&exec_ctx);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_free(pollset_set->pollsets);
 | 
	
		
			
				|  |  | -  gpr_free(pollset_set->pollset_sets);
 | 
	
		
			
				|  |  | -  gpr_free(pollset_set->fds);
 | 
	
		
			
				|  |  | -  gpr_free(pollset_set);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_free(pss);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                               grpc_pollset_set *pollset_set, grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  if (pollset_set->fd_count == pollset_set->fd_capacity) {
 | 
	
		
			
				|  |  | -    pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity);
 | 
	
		
			
				|  |  | -    pollset_set->fds = gpr_realloc(
 | 
	
		
			
				|  |  | -        pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GRPC_FD_REF(fd, "pollset_set");
 | 
	
		
			
				|  |  | -  pollset_set->fds[pollset_set->fd_count++] = fd;
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->pollset_count; i++) {
 | 
	
		
			
				|  |  | -    pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->pollset_set_count; i++) {
 | 
	
		
			
				|  |  | -    pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset_set->mu);
 | 
	
		
			
				|  |  | +static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
 | 
	
		
			
				|  |  | +                               grpc_fd *fd) {
 | 
	
		
			
				|  |  | +  add_poll_object(exec_ctx, &pss->po, POLL_OBJ_POLLSET_SET, &fd->po,
 | 
	
		
			
				|  |  | +                  POLL_OBJ_FD);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                               grpc_pollset_set *pollset_set, grpc_fd *fd) {
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->fd_count; i++) {
 | 
	
		
			
				|  |  | -    if (pollset_set->fds[i] == fd) {
 | 
	
		
			
				|  |  | -      pollset_set->fd_count--;
 | 
	
		
			
				|  |  | -      GPR_SWAP(grpc_fd *, pollset_set->fds[i],
 | 
	
		
			
				|  |  | -               pollset_set->fds[pollset_set->fd_count]);
 | 
	
		
			
				|  |  | -      GRPC_FD_UNREF(fd, "pollset_set");
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->pollset_set_count; i++) {
 | 
	
		
			
				|  |  | -    pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset_set->mu);
 | 
	
		
			
				|  |  | +static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss,
 | 
	
		
			
				|  |  | +                               grpc_fd *fd) {
 | 
	
		
			
				|  |  | +  /* Nothing to do */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                    grpc_pollset_set *pollset_set,
 | 
	
		
			
				|  |  | -                                    grpc_pollset *pollset) {
 | 
	
		
			
				|  |  | -  size_t i, j;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
 | 
	
		
			
				|  |  | -    pollset_set->pollset_capacity =
 | 
	
		
			
				|  |  | -        GPR_MAX(8, 2 * pollset_set->pollset_capacity);
 | 
	
		
			
				|  |  | -    pollset_set->pollsets =
 | 
	
		
			
				|  |  | -        gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity *
 | 
	
		
			
				|  |  | -                                               sizeof(*pollset_set->pollsets));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
 | 
	
		
			
				|  |  | -  for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
 | 
	
		
			
				|  |  | -    if (fd_is_orphaned(pollset_set->fds[i])) {
 | 
	
		
			
				|  |  | -      GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
 | 
	
		
			
				|  |  | -      pollset_set->fds[j++] = pollset_set->fds[i];
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  pollset_set->fd_count = j;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset_set->mu);
 | 
	
		
			
				|  |  | +                                    grpc_pollset_set *pss, grpc_pollset *ps) {
 | 
	
		
			
				|  |  | +  add_poll_object(exec_ctx, &pss->po, POLL_OBJ_POLLSET_SET, &ps->po,
 | 
	
		
			
				|  |  | +                  POLL_OBJ_POLLSET);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | -                                    grpc_pollset_set *pollset_set,
 | 
	
		
			
				|  |  | -                                    grpc_pollset *pollset) {
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&pollset_set->mu);
 | 
	
		
			
				|  |  | -  for (i = 0; i < pollset_set->pollset_count; i++) {
 | 
	
		
			
				|  |  | -    if (pollset_set->pollsets[i] == pollset) {
 | 
	
		
			
				|  |  | -      pollset_set->pollset_count--;
 | 
	
		
			
				|  |  | -      GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i],
 | 
	
		
			
				|  |  | -               pollset_set->pollsets[pollset_set->pollset_count]);
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&pollset_set->mu);
 | 
	
		
			
				|  |  | +                                    grpc_pollset_set *pss, grpc_pollset *ps) {
 | 
	
		
			
				|  |  | +  /* Nothing to do */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                          grpc_pollset_set *bag,
 | 
	
		
			
				|  |  |                                          grpc_pollset_set *item) {
 | 
	
		
			
				|  |  | -  size_t i, j;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&bag->mu);
 | 
	
		
			
				|  |  | -  if (bag->pollset_set_count == bag->pollset_set_capacity) {
 | 
	
		
			
				|  |  | -    bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
 | 
	
		
			
				|  |  | -    bag->pollset_sets =
 | 
	
		
			
				|  |  | -        gpr_realloc(bag->pollset_sets,
 | 
	
		
			
				|  |  | -                    bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  bag->pollset_sets[bag->pollset_set_count++] = item;
 | 
	
		
			
				|  |  | -  for (i = 0, j = 0; i < bag->fd_count; i++) {
 | 
	
		
			
				|  |  | -    if (fd_is_orphaned(bag->fds[i])) {
 | 
	
		
			
				|  |  | -      GRPC_FD_UNREF(bag->fds[i], "pollset_set");
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
 | 
	
		
			
				|  |  | -      bag->fds[j++] = bag->fds[i];
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  bag->fd_count = j;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&bag->mu);
 | 
	
		
			
				|  |  | +  add_poll_object(exec_ctx, &bag->po, POLL_OBJ_POLLSET_SET, &item->po,
 | 
	
		
			
				|  |  | +                  POLL_OBJ_POLLSET_SET);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                          grpc_pollset_set *bag,
 | 
	
		
			
				|  |  |                                          grpc_pollset_set *item) {
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&bag->mu);
 | 
	
		
			
				|  |  | -  for (i = 0; i < bag->pollset_set_count; i++) {
 | 
	
		
			
				|  |  | -    if (bag->pollset_sets[i] == item) {
 | 
	
		
			
				|  |  | -      bag->pollset_set_count--;
 | 
	
		
			
				|  |  | -      GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
 | 
	
		
			
				|  |  | -               bag->pollset_sets[bag->pollset_set_count]);
 | 
	
		
			
				|  |  | -      break;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&bag->mu);
 | 
	
		
			
				|  |  | +  /* Nothing to do */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Test helper functions
 | 
	
	
		
			
				|  | @@ -1927,9 +1886,9 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  void *grpc_fd_get_polling_island(grpc_fd *fd) {
 | 
	
		
			
				|  |  |    polling_island *pi;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&fd->mu);
 | 
	
		
			
				|  |  | -  pi = fd->polling_island;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&fd->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&fd->po.mu);
 | 
	
		
			
				|  |  | +  pi = fd->po.pi;
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&fd->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return pi;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -1937,9 +1896,9 @@ void *grpc_fd_get_polling_island(grpc_fd *fd) {
 | 
	
		
			
				|  |  |  void *grpc_pollset_get_polling_island(grpc_pollset *ps) {
 | 
	
		
			
				|  |  |    polling_island *pi;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&ps->mu);
 | 
	
		
			
				|  |  | -  pi = ps->polling_island;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&ps->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&ps->po.mu);
 | 
	
		
			
				|  |  | +  pi = ps->po.pi;
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&ps->po.mu);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return pi;
 | 
	
		
			
				|  |  |  }
 |