Ejemplo n.º 1
0
static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 grpc_fd *fd, int and_unlock_pollset) {
    grpc_unary_promote_args *up_args;
    GPR_ASSERT(fd);
    if (fd == pollset->data.ptr) goto exit;

    if (!grpc_pollset_has_workers(pollset)) {
        /* Fast path -- no in flight cbs */
        /* TODO(klempner): Comment this out and fix any test failures or establish
         * they are due to timing issues */
        grpc_fd *fds[2];
        fds[0] = pollset->data.ptr;
        fds[1] = fd;

        if (fds[0] == NULL) {
            pollset->data.ptr = fd;
            GRPC_FD_REF(fd, "basicpoll");
        } else if (!grpc_fd_is_orphaned(fds[0])) {
            grpc_platform_become_multipoller(exec_ctx, pollset, fds,
                                             GPR_ARRAY_SIZE(fds));
            GRPC_FD_UNREF(fds[0], "basicpoll");
        } else {
            /* old fd is orphaned and we haven't cleaned it up until now, so remain a
             * unary poller */
            GRPC_FD_UNREF(fds[0], "basicpoll");
            pollset->data.ptr = fd;
            GRPC_FD_REF(fd, "basicpoll");
        }
        goto exit;
    }

    /* Now we need to promote. This needs to happen when we're not polling. Since
     * this may be called from poll, the wait needs to happen asynchronously. */
    GRPC_FD_REF(fd, "basicpoll_add");
    pollset->in_flight_cbs++;
    up_args = gpr_malloc(sizeof(*up_args));
    up_args->fd = fd;
    up_args->original_vtable = pollset->vtable;
    up_args->pollset = pollset;
    up_args->promotion_closure.cb = basic_do_promote;
    up_args->promotion_closure.cb_arg = up_args;

    grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1);
    grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);

exit:
    if (and_unlock_pollset) {
        gpr_mu_unlock(&pollset->mu);
    }
}
Ejemplo n.º 2
0
static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
    pollset->vtable = &basic_pollset;
    pollset->data.ptr = fd_or_null;
    if (fd_or_null != NULL) {
        GRPC_FD_REF(fd_or_null, "basicpoll");
    }
}
Ejemplo n.º 3
0
static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args, int success) {
  grpc_unary_promote_args *up_args = args;
  const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
  grpc_pollset *pollset = up_args->pollset;
  grpc_fd *fd = up_args->fd;

  /*
   * This is quite tricky. There are a number of cases to keep in mind here:
   * 1. fd may have been orphaned
   * 2. The pollset may no longer be a unary poller (and we can't let case #1
   * leak to other pollset types!)
   * 3. pollset's fd (which may have changed) may have been orphaned
   * 4. The pollset may be shutting down.
   */

  gpr_mu_lock(&pollset->mu);
  /* First we need to ensure that nobody is polling concurrently */
  GPR_ASSERT(!grpc_pollset_has_workers(pollset));

  gpr_free(up_args);
  /* At this point the pollset may no longer be a unary poller. In that case
   * we should just call the right add function and be done. */
  /* TODO(klempner): If we're not careful this could cause infinite recursion.
   * That's not a problem for now because empty_pollset has a trivial poller
   * and we don't have any mechanism to unbecome multipoller. */
  pollset->in_flight_cbs--;
  if (pollset->shutting_down) {
    /* We don't care about this pollset anymore. */
    if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) {
      finish_shutdown(exec_ctx, pollset);
    }
  } else if (grpc_fd_is_orphaned(fd)) {
    /* Don't try to add it to anything, we'll drop our ref on it below */
  } else if (pollset->vtable != original_vtable) {
    pollset->vtable->add_fd(exec_ctx, pollset, fd, 0);
  } else if (fd != pollset->data.ptr) {
    grpc_fd *fds[2];
    fds[0] = pollset->data.ptr;
    fds[1] = fd;

    if (fds[0] && !grpc_fd_is_orphaned(fds[0])) {
      grpc_platform_become_multipoller(exec_ctx, pollset, fds,
                                       GPR_ARRAY_SIZE(fds));
      GRPC_FD_UNREF(fds[0], "basicpoll");
    } else {
      /* old fd is orphaned and we haven't cleaned it up until now, so remain a
       * unary poller */
      /* Note that it is possible that fds[1] is also orphaned at this point.
       * That's okay, we'll correct it at the next add or poll. */
      if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
      pollset->data.ptr = fd;
      GRPC_FD_REF(fd, "basicpoll");
    }
  }

  gpr_mu_unlock(&pollset->mu);

  /* Matching ref in basic_pollset_add_fd */
  GRPC_FD_UNREF(fd, "basicpoll_add");
}
Ejemplo n.º 4
0
gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
                              gpr_uint32 read_mask, gpr_uint32 write_mask,
                              grpc_fd_watcher *watcher) {
  gpr_uint32 mask = 0;
  /* keep track of pollers that have requested our events, in case they change
   */
  GRPC_FD_REF(fd, "poll");

  gpr_mu_lock(&fd->watcher_mu);
  /* if there is nobody polling for read, but we need to, then start doing so */
  if (!fd->read_watcher && gpr_atm_acq_load(&fd->readst) != NOT_READY) {
    fd->read_watcher = watcher;
    mask |= read_mask;
  }
  /* if there is nobody polling for write, but we need to, then start doing so
   */
  if (!fd->write_watcher && gpr_atm_acq_load(&fd->writest) != NOT_READY) {
    fd->write_watcher = watcher;
    mask |= write_mask;
  }
  /* if not polling, remember this watcher in case we need someone to later */
  if (mask == 0) {
    watcher->next = &fd->inactive_watcher_root;
    watcher->prev = watcher->next->prev;
    watcher->next->prev = watcher->prev->next = watcher;
  }
  watcher->pollset = pollset;
  watcher->fd = fd;
  gpr_mu_unlock(&fd->watcher_mu);

  return mask;
}
static void multipoll_with_poll_pollset_del_fd(grpc_pollset *pollset,
                                               grpc_fd *fd) {
  /* will get removed next poll cycle */
  pollset_hdr *h = pollset->data.ptr;
  if (h->del_count == h->del_capacity) {
    h->del_capacity = GPR_MAX(h->del_capacity + 8, h->del_count * 3 / 2);
    h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity);
  }
  h->dels[h->del_count++] = fd;
  GRPC_FD_REF(fd, "multipoller_del");
}
Ejemplo n.º 6
0
uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
                            grpc_pollset_worker *worker, uint32_t read_mask,
                            uint32_t write_mask, grpc_fd_watcher *watcher) {
  uint32_t mask = 0;
  grpc_closure *cur;
  int requested;
  /* keep track of pollers that have requested our events, in case they change
   */
  GRPC_FD_REF(fd, "poll");

  gpr_mu_lock(&fd->mu);

  /* if we are shutdown, then don't add to the watcher set */
  if (fd->shutdown) {
    watcher->fd = NULL;
    watcher->pollset = NULL;
    watcher->worker = NULL;
    gpr_mu_unlock(&fd->mu);
    GRPC_FD_UNREF(fd, "poll");
    return 0;
  }

  /* if there is nobody polling for read, but we need to, then start doing so */
  cur = fd->read_closure;
  requested = cur != CLOSURE_READY;
  if (read_mask && fd->read_watcher == NULL && requested) {
    fd->read_watcher = watcher;
    mask |= read_mask;
  }
  /* if there is nobody polling for write, but we need to, then start doing so
   */
  cur = fd->write_closure;
  requested = cur != CLOSURE_READY;
  if (write_mask && fd->write_watcher == NULL && requested) {
    fd->write_watcher = watcher;
    mask |= write_mask;
  }
  /* if not polling, remember this watcher in case we need someone to later */
  if (mask == 0 && worker != NULL) {
    watcher->next = &fd->inactive_watcher_root;
    watcher->prev = watcher->next->prev;
    watcher->next->prev = watcher->prev->next = watcher;
  }
  watcher->pollset = pollset;
  watcher->worker = worker;
  watcher->fd = fd;
  gpr_mu_unlock(&fd->mu);

  return mask;
}
static void multipoll_with_poll_pollset_add_fd(grpc_pollset *pollset,
                                               grpc_fd *fd) {
  size_t i;
  pollset_hdr *h = pollset->data.ptr;
  /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */
  for (i = 0; i < h->fd_count; i++) {
    if (h->fds[i] == fd) return;
  }
  if (h->fd_count == h->fd_capacity) {
    h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2);
    h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity);
  }
  h->fds[h->fd_count++] = fd;
  GRPC_FD_REF(fd, "multipoller");
}
Ejemplo n.º 8
0
static void multipoll_with_epoll_pollset_add_fd(grpc_pollset *pollset,
                                                grpc_fd *fd,
                                                int and_unlock_pollset) {
  if (and_unlock_pollset) {
    gpr_mu_unlock(&pollset->mu);
    finally_add_fd(pollset, fd);
  } else {
    delayed_add *da = gpr_malloc(sizeof(*da));
    da->pollset = pollset;
    da->fd = fd;
    GRPC_FD_REF(fd, "delayed_add");
    grpc_iomgr_closure_init(&da->closure, perform_delayed_add, da);
    pollset->in_flight_cbs++;
    grpc_iomgr_add_callback(&da->closure);
  }
}
void grpc_poll_become_multipoller(grpc_pollset *pollset, grpc_fd **fds,
                                  size_t nfds) {
  size_t i;
  pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
  pollset->vtable = &multipoll_with_poll_pollset;
  pollset->data.ptr = h;
  h->fd_count = nfds;
  h->fd_capacity = nfds;
  h->fds = gpr_malloc(nfds * sizeof(grpc_fd *));
  h->del_count = 0;
  h->del_capacity = 0;
  h->dels = NULL;
  for (i = 0; i < nfds; i++) {
    h->fds[i] = fds[i];
    GRPC_FD_REF(fds[i], "multipoller");
  }
}
static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
                                               grpc_pollset *pollset,
                                               grpc_fd *fd,
                                               int and_unlock_pollset) {
  size_t i;
  pollset_hdr *h = pollset->data.ptr;
  /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */
  for (i = 0; i < h->fd_count; i++) {
    if (h->fds[i] == fd) goto exit;
  }
  if (h->fd_count == h->fd_capacity) {
    h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2);
    h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity);
  }
  h->fds[h->fd_count++] = fd;
  GRPC_FD_REF(fd, "multipoller");
exit:
  if (and_unlock_pollset) {
    gpr_mu_unlock(&pollset->mu);
  }
}
Ejemplo n.º 11
0
static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
        grpc_pollset *pollset,
        grpc_pollset_worker *worker,
        gpr_timespec deadline,
        gpr_timespec now) {
#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)

    struct pollfd pfd[3];
    grpc_fd *fd;
    grpc_fd_watcher fd_watcher;
    int timeout;
    int r;
    nfds_t nfds;

    fd = pollset->data.ptr;
    if (fd && grpc_fd_is_orphaned(fd)) {
        GRPC_FD_UNREF(fd, "basicpoll");
        fd = pollset->data.ptr = NULL;
    }
    timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
    pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
    pfd[0].events = POLLIN;
    pfd[0].revents = 0;
    pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
    pfd[1].events = POLLIN;
    pfd[1].revents = 0;
    nfds = 2;
    if (fd) {
        pfd[2].fd = fd->fd;
        pfd[2].revents = 0;
        GRPC_FD_REF(fd, "basicpoll_begin");
        gpr_mu_unlock(&pollset->mu);
        pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
                        POLLOUT, &fd_watcher);
        if (pfd[2].events != 0) {
            nfds++;
        }
    } else {
        gpr_mu_unlock(&pollset->mu);
    }

    /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
       even going into the blocking annotation if possible */
    /* poll fd count (argument 2) is shortened by one if we have no events
       to poll on - such that it only includes the kicker */
    GPR_TIMER_BEGIN("poll", 0);
    GRPC_SCHEDULING_START_BLOCKING_REGION;
    r = grpc_poll_function(pfd, nfds, timeout);
    GRPC_SCHEDULING_END_BLOCKING_REGION;
    GPR_TIMER_END("poll", 0);

    if (r < 0) {
        if (errno != EINTR) {
            gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
        }
        if (fd) {
            grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
        }
    } else if (r == 0) {
        if (fd) {
            grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
        }
    } else {
        if (pfd[0].revents & POLLIN_CHECK) {
            grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
        }
        if (pfd[1].revents & POLLIN_CHECK) {
            grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
        }
        if (nfds > 2) {
            grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
                             pfd[2].revents & POLLOUT_CHECK);
        } else if (fd) {
            grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
        }
    }

    if (fd) {
        GRPC_FD_UNREF(fd, "basicpoll_begin");
    }
}