From 249de2b5c0113dde23d0667cbab7208875b4b0c1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 Oct 2017 11:49:19 -0700 Subject: Initial refactor --- src/core/lib/iomgr/ev_epollex_linux.c | 824 ++++++++++------------------------ 1 file changed, 247 insertions(+), 577 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 8eb4de44d9..5317c6bff6 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -50,99 +50,61 @@ #include "src/core/lib/support/spinlock.h" /******************************************************************************* - * Polling object +* pollable Declarations */ -typedef enum { - PO_POLLING_GROUP, - PO_POLLSET_SET, - PO_POLLSET, - PO_FD, /* ordering is important: we always want to lock pollsets before fds: - this guarantees that using an fd as a pollable is safe */ - PO_EMPTY_POLLABLE, - PO_COUNT -} polling_obj_type; +typedef enum { PO_MULTI, PO_FD, PO_EMPTY } pollable_type; -typedef struct polling_obj polling_obj; -typedef struct polling_group polling_group; +typedef struct pollable pollable; -struct polling_obj { - gpr_mu mu; - polling_obj_type type; - polling_group *group; - struct polling_obj *next; - struct polling_obj *prev; -}; - -struct polling_group { - polling_obj po; +struct pollable { + pollable_type type; // immutable gpr_refcount refs; -}; -static void po_init(polling_obj *po, polling_obj_type type); -static void po_destroy(polling_obj *po); -static void po_join(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b); -static int po_cmp(polling_obj *a, polling_obj *b); + int epfd; + grpc_wakeup_fd wakeup; -static void pg_create(grpc_exec_ctx *exec_ctx, polling_obj **initial_po, - size_t initial_po_count); -static polling_group *pg_ref(polling_group *pg); -static void pg_unref(polling_group *pg); -static void pg_merge(grpc_exec_ctx *exec_ctx, polling_group *a, - polling_group *b); -static void pg_join(grpc_exec_ctx *exec_ctx, polling_group *pg, - polling_obj *po); + // only for type fd... one ref to the owner fd + grpc_fd *owner_fd; -/******************************************************************************* - * pollable Declarations - */ + grpc_pollset_set *pollset_set; + pollable *next; + pollable *prev; -typedef struct pollable { - polling_obj po; - int epfd; - grpc_wakeup_fd wakeup; + gpr_mu mu; grpc_pollset_worker *root_worker; -} pollable; +}; -static const char *polling_obj_type_string(polling_obj_type t) { +static const char *pollable_type_string(pollable_type t) { switch (t) { - case PO_POLLING_GROUP: - return "polling_group"; - case PO_POLLSET_SET: - return "pollset_set"; - case PO_POLLSET: + case PO_MULTI: return "pollset"; case PO_FD: return "fd"; - case PO_EMPTY_POLLABLE: - return "empty_pollable"; - case PO_COUNT: - return ""; + case PO_EMPTY: + return "empty"; } return ""; } static char *pollable_desc(pollable *p) { char *out; - gpr_asprintf(&out, "type=%s group=%p epfd=%d wakeup=%d", - polling_obj_type_string(p->po.type), p->po.group, p->epfd, - p->wakeup.read_fd); + gpr_asprintf(&out, "type=%s epfd=%d wakeup=%d", pollable_type_string(p->type), + p->epfd, p->wakeup.read_fd); return out; } -static pollable g_empty_pollable; +static pollable *g_empty_pollable; -static void pollable_init(pollable *p, polling_obj_type type); -static void pollable_destroy(pollable *p); -/* ensure that p->epfd, p->wakeup are initialized; p->po.mu must be held */ -static grpc_error *pollable_materialize(pollable *p); +static grpc_error *pollable_create(pollable_type type, pollable **p); +static pollable *pollable_ref(pollable *p); +static void pollable_unref(pollable *p); /******************************************************************************* * Fd Declarations */ struct grpc_fd { - pollable pollable_obj; int fd; /* refst format: bit 0 : 1=Active / 0=Orphaned @@ -150,11 +112,8 @@ struct grpc_fd { Ref/Unref by two to avoid altering the orphaned bit */ gpr_atm refst; - /* The fd is either closed or we relinquished control of it. In either - cases, this indicates that the 'fd' on this structure is no longer - valid */ - gpr_mu orphaned_mu; - bool orphaned; + gpr_mu pollable_mu; + pollable *pollable_obj; gpr_atm read_closure; gpr_atm write_closure; @@ -176,36 +135,26 @@ static void fd_global_shutdown(void); * Pollset Declarations */ -typedef struct pollset_worker_link { - grpc_pollset_worker *next; - grpc_pollset_worker *prev; -} pollset_worker_link; - -typedef enum { - PWL_POLLSET, - PWL_POLLABLE, - POLLSET_WORKER_LINK_COUNT -} pollset_worker_links; - struct grpc_pollset_worker { bool kicked; bool initialized_cv; - pollset_worker_link links[POLLSET_WORKER_LINK_COUNT]; gpr_cv cv; grpc_pollset *pollset; pollable *pollable_obj; + + grpc_pollset_worker *next; + grpc_pollset_worker *prev; }; #define MAX_EPOLL_EVENTS 100 #define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5 struct grpc_pollset { - pollable pollable_obj; - pollable *current_pollable_obj; - int kick_alls_pending; + gpr_mu mu; + pollable *active_pollable; bool kicked_without_poller; grpc_closure *shutdown_closure; - grpc_pollset_worker *root_worker; + int worker_count; int event_cursor; int event_count; @@ -216,7 +165,12 @@ struct grpc_pollset { * Pollset-set Declarations */ struct grpc_pollset_set { - polling_obj po; + gpr_refcount refs; + gpr_mu mu; + grpc_pollset_set *parent; + // only valid if parent==NULL + pollable *child_pollsets; + grpc_fd *child_fds; }; /******************************************************************************* @@ -282,8 +236,10 @@ static void fd_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_fd *fd = (grpc_fd *)arg; /* Add the fd to the freelist */ grpc_iomgr_unregister_object(&fd->iomgr_object); - pollable_destroy(&fd->pollable_obj); - gpr_mu_destroy(&fd->orphaned_mu); + if (fd->pollable_obj) { + pollable_unref(fd->pollable_obj); + } + gpr_mu_destroy(&fd->pollable_mu); gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; fd_freelist = fd; @@ -343,12 +299,10 @@ static grpc_fd *fd_create(int fd, const char *name) { new_fd = (grpc_fd *)gpr_malloc(sizeof(grpc_fd)); } - pollable_init(&new_fd->pollable_obj, PO_FD); - + gpr_mu_init(&new_fd->pollable_mu); + new_fd->pollable_obj = NULL; gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); new_fd->fd = fd; - gpr_mu_init(&new_fd->orphaned_mu); - new_fd->orphaned = false; grpc_lfev_init(&new_fd->read_closure); grpc_lfev_init(&new_fd->write_closure); gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL); @@ -369,24 +323,15 @@ static grpc_fd *fd_create(int fd, const char *name) { } static int fd_wrapped_fd(grpc_fd *fd) { - int ret_fd = -1; - gpr_mu_lock(&fd->orphaned_mu); - if (!fd->orphaned) { - ret_fd = fd->fd; - } - gpr_mu_unlock(&fd->orphaned_mu); - - return ret_fd; + int ret_fd = fd->fd; + return (gpr_atm_acq_load(&fd->refst) & 1) ? ret_fd : -1; } static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, int *release_fd, bool already_closed, const char *reason) { bool is_fd_closed = already_closed; - grpc_error *error = GRPC_ERROR_NONE; - gpr_mu_lock(&fd->pollable_obj.po.mu); - gpr_mu_lock(&fd->orphaned_mu); fd->on_done_closure = on_done; /* If release_fd is not NULL, we should be relinquishing control of the file @@ -398,8 +343,6 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, is_fd_closed = true; } - fd->orphaned = true; - if (!is_fd_closed) { gpr_log(GPR_DEBUG, "TODO: handle fd removal?"); } @@ -408,13 +351,9 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, to be alive (and not added to freelist) until the end of this function */ REF_BY(fd, 1, reason); - GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error)); + GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE); - gpr_mu_unlock(&fd->orphaned_mu); - gpr_mu_unlock(&fd->pollable_obj.po.mu); UNREF_BY(exec_ctx, fd, 2, reason); /* Drop the reference */ - GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); - GRPC_ERROR_UNREF(error); } static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx, @@ -451,63 +390,62 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, * Pollable Definitions */ -static void pollable_init(pollable *p, polling_obj_type type) { - po_init(&p->po, type); - p->root_worker = NULL; - p->epfd = -1; +static grpc_error *pollable_create(pollable_type type, pollable **p) { + *p = NULL; + + int epfd = epoll_create1(EPOLL_CLOEXEC); + if (epfd == -1) { + return GRPC_OS_ERROR(errno, "epoll_create1"); + } + grpc_wakeup_fd wakeup_fd; + grpc_error *err = grpc_wakeup_fd_init(&wakeup_fd); + if (err != GRPC_ERROR_NONE) { + close(epfd); + return err; + } + struct epoll_event ev; + ev.events = (uint32_t)(EPOLLIN | EPOLLET); + ev.data.ptr = NULL; + if (epoll_ctl(epfd, EPOLL_CTL_ADD, wakeup_fd.read_fd, &ev) != 0) { + err = GRPC_OS_ERROR(errno, "epoll_ctl"); + close(epfd); + grpc_wakeup_fd_destroy(&wakeup_fd); + return err; + } + + *p = gpr_malloc(sizeof(**p)); + (*p)->type = type; + gpr_ref_init(&(*p)->refs, 1); + (*p)->epfd = epfd; + (*p)->wakeup = wakeup_fd; + (*p)->owner_fd = NULL; + (*p)->pollset_set = NULL; + (*p)->next = (*p)->prev = *p; + (*p)->root_worker = NULL; + return GRPC_ERROR_NONE; } -static void pollable_destroy(pollable *p) { - po_destroy(&p->po); - if (p->epfd != -1) { - close(p->epfd); - grpc_wakeup_fd_destroy(&p->wakeup); - } +static pollable *pollable_ref(pollable *p) { + gpr_ref(&p->refs); + return p; } -/* ensure that p->epfd, p->wakeup are initialized; p->po.mu must be held */ -static grpc_error *pollable_materialize(pollable *p) { - if (p->epfd == -1) { - int new_epfd = epoll_create1(EPOLL_CLOEXEC); - if (new_epfd < 0) { - return GRPC_OS_ERROR(errno, "epoll_create1"); - } - grpc_error *err = grpc_wakeup_fd_init(&p->wakeup); - if (err != GRPC_ERROR_NONE) { - close(new_epfd); - return err; - } - struct epoll_event ev; - ev.events = (uint32_t)(EPOLLIN | EPOLLET); - ev.data.ptr = (void *)(1 | (intptr_t)&p->wakeup); - if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, p->wakeup.read_fd, &ev) != 0) { - err = GRPC_OS_ERROR(errno, "epoll_ctl"); - close(new_epfd); - grpc_wakeup_fd_destroy(&p->wakeup); - return err; - } - - p->epfd = new_epfd; +static void pollable_unref(pollable *p) { + if (p != NULL && gpr_unref(&p->refs)) { + close(p->epfd); + grpc_wakeup_fd_destroy(&p->wakeup); } - return GRPC_ERROR_NONE; } -/* pollable must be materialized */ static grpc_error *pollable_add_fd(pollable *p, grpc_fd *fd) { grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollable_add_fd"; const int epfd = p->epfd; - GPR_ASSERT(epfd != -1); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "add fd %p (%d) to pollable %p", fd, fd->fd, p); } - gpr_mu_lock(&fd->orphaned_mu); - if (fd->orphaned) { - gpr_mu_unlock(&fd->orphaned_mu); - return GRPC_ERROR_NONE; - } struct epoll_event ev_fd; ev_fd.events = (uint32_t)(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE); ev_fd.data.ptr = fd; @@ -519,7 +457,6 @@ static grpc_error *pollable_add_fd(pollable *p, grpc_fd *fd) { append_error(&error, GRPC_OS_ERROR(errno, "epoll_ctl"), err_desc); } } - gpr_mu_unlock(&fd->orphaned_mu); return error; } @@ -535,25 +472,24 @@ GPR_TLS_DECL(g_current_thread_worker); static grpc_error *pollset_global_init(void) { gpr_tls_init(&g_current_thread_pollset); gpr_tls_init(&g_current_thread_worker); - pollable_init(&g_empty_pollable, PO_EMPTY_POLLABLE); - return GRPC_ERROR_NONE; + return pollable_create(PO_EMPTY, &g_empty_pollable); } static void pollset_global_shutdown(void) { - pollable_destroy(&g_empty_pollable); + pollable_unref(g_empty_pollable); gpr_tls_destroy(&g_current_thread_pollset); gpr_tls_destroy(&g_current_thread_worker); } static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && - pollset->kick_alls_pending == 0) { + if (pollset->shutdown_closure != NULL && pollset->worker_count == 0) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); pollset->shutdown_closure = NULL; } } +#if 0 static void do_kick_all(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error_unused) { grpc_error *error = GRPC_ERROR_NONE; @@ -596,14 +532,13 @@ static void do_kick_all(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_unlock(&pollset->pollable_obj.po.mu); GRPC_LOG_IF_ERROR("kick_all", error); } +#endif static void pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - pollset->kick_alls_pending++; - GRPC_CLOSURE_SCHED(exec_ctx, GRPC_CLOSURE_CREATE(do_kick_all, pollset, - grpc_schedule_on_exec_ctx), - GRPC_ERROR_NONE); + abort(); } +#if 0 static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, grpc_pollset_worker *specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -665,10 +600,13 @@ static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, return GRPC_ERROR_NONE; } } +#endif /* p->po.mu must be held before calling this function */ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + abort(); +#if 0 pollable *p = pollset->current_pollable_obj; GRPC_STATS_INC_POLLSET_KICK(exec_ctx); if (p != &pollset->pollable_obj) { @@ -679,15 +617,13 @@ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_unlock(&p->po.mu); } return error; +#endif } static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { - pollable_init(&pollset->pollable_obj, PO_POLLSET); - pollset->current_pollable_obj = &g_empty_pollable; - pollset->kicked_without_poller = false; - pollset->shutdown_closure = NULL; - pollset->root_worker = NULL; - *mu = &pollset->pollable_obj.po.mu; + gpr_mu_init(&pollset->mu); + pollset->active_pollable = pollable_ref(g_empty_pollable); + *mu = &pollset->mu; } /* Convert a timespec to milliseconds: @@ -735,12 +671,28 @@ static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } -static grpc_error *fd_become_pollable_locked(grpc_fd *fd) { +static grpc_error *fd_become_pollable(grpc_fd *fd, pollable **p) { + gpr_mu_lock(&fd->pollable_mu); grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "fd_become_pollable"; - if (append_error(&error, pollable_materialize(&fd->pollable_obj), err_desc)) { - append_error(&error, pollable_add_fd(&fd->pollable_obj, fd), err_desc); + if (fd->pollable_obj == NULL) { + if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj), + err_desc)) { + if (!append_error(&error, pollable_add_fd(fd->pollable_obj, fd), + err_desc)) { + pollable_unref(fd->pollable_obj); + fd->pollable_obj = NULL; + } + } + } + if (error == GRPC_ERROR_NONE) { + GPR_ASSERT(fd->pollable_obj != NULL); + *p = pollable_ref(fd->pollable_obj); + } else { + GPR_ASSERT(fd->pollable_obj == NULL); + *p = NULL; } + gpr_mu_unlock(&fd->pollable_mu); return error; } @@ -753,10 +705,6 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset_maybe_finish_shutdown(exec_ctx, pollset); } -static bool pollset_is_pollable_fd(grpc_pollset *pollset, pollable *p) { - return p != &g_empty_pollable && p != &pollset->pollable_obj; -} - static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, bool drain) { static const char *err_desc = "pollset_process_events"; @@ -800,11 +748,8 @@ static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, /* pollset_shutdown is guaranteed to be called before pollset_destroy. */ static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - pollable_destroy(&pollset->pollable_obj); - if (pollset_is_pollable_fd(pollset, pollset->current_pollable_obj)) { - UNREF_BY(exec_ctx, (grpc_fd *)pollset->current_pollable_obj, 2, - "pollset_pollable"); - } + pollable_unref(pollset->active_pollable); + pollset->active_pollable = NULL; GRPC_LOG_IF_ERROR("pollset_process_events", pollset_process_events(exec_ctx, pollset, true)); } @@ -845,41 +790,37 @@ static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } /* Return true if first in list */ -static bool worker_insert(grpc_pollset_worker **root, pollset_worker_links link, - grpc_pollset_worker *worker) { - if (*root == NULL) { - *root = worker; - worker->links[link].next = worker->links[link].prev = worker; +static bool worker_insert(pollable *pollable_obj, grpc_pollset_worker *worker) { + if (pollable_obj->root_worker == NULL) { + pollable_obj->root_worker = worker; + worker->next = worker->prev = worker; return true; } else { - worker->links[link].next = *root; - worker->links[link].prev = worker->links[link].next->links[link].prev; - worker->links[link].next->links[link].prev = worker; - worker->links[link].prev->links[link].next = worker; + worker->next = pollable_obj->root_worker; + worker->prev = worker->next->prev; + worker->next->prev = worker; + worker->prev->next = worker; return false; } } -/* Return true if last in list */ -typedef enum { EMPTIED, NEW_ROOT, REMOVED } worker_remove_result; - -static worker_remove_result worker_remove(grpc_pollset_worker **root, - pollset_worker_links link, +/* returns the new root IFF the root changed */ +static grpc_pollset_worker *worker_remove(pollable *pollable_obj, grpc_pollset_worker *worker) { - if (worker == *root) { - if (worker == worker->links[link].next) { - *root = NULL; - return EMPTIED; + if (worker == pollable_obj->root_worker) { + if (worker == worker->next) { + pollable_obj->root_worker = NULL; + return NULL; } else { - *root = worker->links[link].next; - worker->links[link].prev->links[link].next = worker->links[link].next; - worker->links[link].next->links[link].prev = worker->links[link].prev; - return NEW_ROOT; + pollable_obj->root_worker = worker->next; + worker->prev->next = worker->next; + worker->next->prev = worker->prev; + return pollable_obj->root_worker; } } else { - worker->links[link].prev->links[link].next = worker->links[link].next; - worker->links[link].next->links[link].prev = worker->links[link].prev; - return REMOVED; + worker->prev->next = worker->next; + worker->next->prev = worker->prev; + return NULL; } } @@ -892,20 +833,12 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->initialized_cv = false; worker->kicked = false; worker->pollset = pollset; - worker->pollable_obj = pollset->current_pollable_obj; - - if (pollset_is_pollable_fd(pollset, worker->pollable_obj)) { - REF_BY((grpc_fd *)worker->pollable_obj, 2, "one_poll"); - } - - worker_insert(&pollset->root_worker, PWL_POLLSET, worker); - if (!worker_insert(&worker->pollable_obj->root_worker, PWL_POLLABLE, - worker)) { + worker->pollable_obj = pollable_ref(pollset->active_pollable); + gpr_mu_lock(&worker->pollable_obj->mu); + pollset->worker_count++; + if (!worker_insert(worker->pollable_obj, worker)) { worker->initialized_cv = true; gpr_cv_init(&worker->cv); - if (worker->pollable_obj != &pollset->pollable_obj) { - gpr_mu_unlock(&pollset->pollable_obj.po.mu); - } if (GRPC_TRACER_ON(grpc_polling_trace) && worker->pollable_obj->root_worker != worker) { gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset, @@ -913,7 +846,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, poll_deadline_to_millis_timeout(deadline, *now)); } while (do_poll && worker->pollable_obj->root_worker != worker) { - if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->po.mu, deadline)) { + if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->mu, deadline)) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p timeout_wait %p w=%p", pollset, worker->pollable_obj, worker); @@ -931,32 +864,29 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->pollable_obj, worker); } } - if (worker->pollable_obj != &pollset->pollable_obj) { - gpr_mu_unlock(&worker->pollable_obj->po.mu); - gpr_mu_lock(&pollset->pollable_obj.po.mu); - gpr_mu_lock(&worker->pollable_obj->po.mu); - } *now = gpr_now(now->clock_type); } + gpr_mu_unlock(&worker->pollable_obj->mu); return do_poll && pollset->shutdown_closure == NULL && - pollset->current_pollable_obj == worker->pollable_obj; + pollset->active_pollable == worker->pollable_obj; } static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl) { - if (NEW_ROOT == - worker_remove(&worker->pollable_obj->root_worker, PWL_POLLABLE, worker)) { - gpr_cv_signal(&worker->pollable_obj->root_worker->cv); + gpr_mu_lock(&worker->pollable_obj->mu); + grpc_pollset_worker *new_root = worker_remove(worker->pollable_obj, worker); + if (new_root != NULL) { + GPR_ASSERT(new_root->initialized_cv); + gpr_cv_signal(&new_root->cv); } if (worker->initialized_cv) { gpr_cv_destroy(&worker->cv); } - if (pollset_is_pollable_fd(pollset, worker->pollable_obj)) { - UNREF_BY(exec_ctx, (grpc_fd *)worker->pollable_obj, 2, "one_poll"); - } - if (EMPTIED == worker_remove(&pollset->root_worker, PWL_POLLSET, worker)) { + gpr_mu_unlock(&worker->pollable_obj->mu); + pollset->worker_count--; + if (pollset->worker_count == 0) { pollset_maybe_finish_shutdown(exec_ctx, pollset); } } @@ -969,31 +899,23 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { grpc_pollset_worker worker; - if (0 && GRPC_TRACER_ON(grpc_polling_trace)) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64 - ".%09d deadline=%" PRId64 ".%09d kwp=%d root_worker=%p", + ".%09d deadline=%" PRId64 ".%09d kwp=%d", pollset, worker_hdl, &worker, now.tv_sec, now.tv_nsec, - deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, - pollset->root_worker); + deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller); } - grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_work"; if (pollset->kicked_without_poller) { pollset->kicked_without_poller = false; return GRPC_ERROR_NONE; } - if (pollset->current_pollable_obj != &pollset->pollable_obj) { - gpr_mu_lock(&pollset->current_pollable_obj->po.mu); - } + grpc_error *error = GRPC_ERROR_NONE; if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); GPR_ASSERT(!pollset->shutdown_closure); - append_error(&error, pollable_materialize(worker.pollable_obj), err_desc); - if (worker.pollable_obj != &pollset->pollable_obj) { - gpr_mu_unlock(&worker.pollable_obj->po.mu); - } - gpr_mu_unlock(&pollset->pollable_obj.po.mu); + gpr_mu_unlock(&pollset->mu); if (pollset->event_cursor == pollset->event_count) { append_error(&error, pollset_epoll(exec_ctx, pollset, worker.pollable_obj, now, deadline), @@ -1001,89 +923,73 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } append_error(&error, pollset_process_events(exec_ctx, pollset, false), err_desc); - gpr_mu_lock(&pollset->pollable_obj.po.mu); - if (worker.pollable_obj != &pollset->pollable_obj) { - gpr_mu_lock(&worker.pollable_obj->po.mu); - } + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); gpr_tls_set(&g_current_thread_pollset, 0); gpr_tls_set(&g_current_thread_worker, 0); - pollset_maybe_finish_shutdown(exec_ctx, pollset); } end_worker(exec_ctx, pollset, &worker, worker_hdl); - if (worker.pollable_obj != &pollset->pollable_obj) { - gpr_mu_unlock(&worker.pollable_obj->po.mu); - } - if (grpc_exec_ctx_has_work(exec_ctx)) { - gpr_mu_unlock(&pollset->pollable_obj.po.mu); - grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&pollset->pollable_obj.po.mu); - } return error; } -static void unref_fd_no_longer_poller(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_fd *fd = (grpc_fd *)arg; - UNREF_BY(exec_ctx, fd, 2, "pollset_pollable"); -} - /* expects pollsets locked, flag whether fd is locked or not */ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, grpc_fd *fd, - bool fd_locked) { + grpc_pollset *pollset, grpc_fd *fd) { static const char *err_desc = "pollset_add_fd"; grpc_error *error = GRPC_ERROR_NONE; - if (pollset->current_pollable_obj == &g_empty_pollable) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, - "PS:%p add fd %p; transition pollable from empty to fd", pollset, - fd); - } - /* empty pollable --> single fd pollable */ - pollset_kick_all(exec_ctx, pollset); - pollset->current_pollable_obj = &fd->pollable_obj; - if (!fd_locked) gpr_mu_lock(&fd->pollable_obj.po.mu); - append_error(&error, fd_become_pollable_locked(fd), err_desc); - if (!fd_locked) gpr_mu_unlock(&fd->pollable_obj.po.mu); - REF_BY(fd, 2, "pollset_pollable"); - } else if (pollset->current_pollable_obj == &pollset->pollable_obj) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p add fd %p; already multipolling", pollset, fd); - } - append_error(&error, pollable_add_fd(pollset->current_pollable_obj, fd), - err_desc); - } else if (pollset->current_pollable_obj != &fd->pollable_obj) { - grpc_fd *had_fd = (grpc_fd *)pollset->current_pollable_obj; - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, - "PS:%p add fd %p; transition pollable from fd %p to multipoller", - pollset, fd, had_fd); - } - /* Introduce a spurious completion. - If we do not, then it may be that the fd-specific epoll set consumed - a completion without being polled, leading to a missed edge going up. */ - grpc_lfev_set_ready(exec_ctx, &had_fd->read_closure, "read"); - grpc_lfev_set_ready(exec_ctx, &had_fd->write_closure, "write"); - pollset_kick_all(exec_ctx, pollset); - pollset->current_pollable_obj = &pollset->pollable_obj; - if (append_error(&error, pollable_materialize(&pollset->pollable_obj), - err_desc)) { - pollable_add_fd(&pollset->pollable_obj, had_fd); - pollable_add_fd(&pollset->pollable_obj, fd); - } - GRPC_CLOSURE_SCHED(exec_ctx, - GRPC_CLOSURE_CREATE(unref_fd_no_longer_poller, had_fd, - grpc_schedule_on_exec_ctx), - GRPC_ERROR_NONE); + pollable *po_at_start = pollable_ref(pollset->active_pollable); + switch (pollset->active_pollable->type) { + case PO_EMPTY: + /* empty pollable --> single fd pollable */ + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p add fd %p; transition pollable from empty to fd", + pollset, fd); + } + pollset_kick_all(exec_ctx, pollset); + pollable_unref(pollset->active_pollable); + append_error(&error, fd_become_pollable(fd, &pollset->active_pollable), + err_desc); + break; + case PO_FD: + /* fd --> multipoller */ + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log( + GPR_DEBUG, + "PS:%p add fd %p; transition pollable from fd %p to multipoller", + pollset, fd, pollset->active_pollable->owner_fd); + } + pollset_kick_all(exec_ctx, pollset); + pollable_unref(pollset->active_pollable); + if (append_error(&error, + pollable_create(PO_MULTI, &pollset->active_pollable), + err_desc)) { + append_error(&error, pollable_add_fd(pollset->active_pollable, + po_at_start->owner_fd), + err_desc); + append_error(&error, pollable_add_fd(pollset->active_pollable, fd), + err_desc); + } + break; + case PO_MULTI: + append_error(&error, pollable_add_fd(pollset->active_pollable, fd), + err_desc); + break; + } + if (error != GRPC_ERROR_NONE) { + pollable_unref(pollset->active_pollable); + pollset->active_pollable = po_at_start; + } else { + pollable_unref(po_at_start); } return error; } static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { - gpr_mu_lock(&pollset->pollable_obj.po.mu); - grpc_error *error = pollset_add_fd_locked(exec_ctx, pollset, fd, false); - gpr_mu_unlock(&pollset->pollable_obj.po.mu); + gpr_mu_lock(&pollset->mu); + grpc_error *error = pollset_add_fd_locked(exec_ctx, pollset, fd); + gpr_mu_unlock(&pollset->mu); GRPC_LOG_IF_ERROR("pollset_add_fd", error); } @@ -1091,301 +997,65 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, * Pollset-set Definitions */ +static grpc_pollset_set *pss_lock_adam(grpc_pollset_set *pss) { + gpr_mu_lock(&pss->mu); + while (pss->parent != NULL) { + gpr_mu_lock(&pss->parent->mu); + gpr_mu_unlock(&pss->mu); + pss = pss->parent; + } + return pss; +} + static grpc_pollset_set *pollset_set_create(void) { - grpc_pollset_set *pss = (grpc_pollset_set *)gpr_zalloc(sizeof(*pss)); - po_init(&pss->po, PO_POLLSET_SET); + grpc_pollset_set *pss = (grpc_pollset_set *)gpr_malloc(sizeof(*pss)); + gpr_mu_init(&pss->mu); + gpr_ref_init(&pss->refs, 1); + pss->parent = NULL; + pss->child_pollsets = NULL; + pss->child_fds = NULL; return pss; } static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss) { - po_destroy(&pss->po); - gpr_free(pss); -} + grpc_pollset_set *pss) {} static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { - po_join(exec_ctx, &pss->po, &fd->pollable_obj.po); + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_set_add_fd"; + pss = pss_lock_adam(pss); + pollable *p = pss->child_pollsets; + if (p != NULL) { + do { + append_error(&error, pollable_add_fd(p, fd), err_desc); + p = p->next; + } while (p != pss->child_pollsets); + + } else { + } + gpr_mu_unlock(&pss->mu); + + GRPC_LOG_IF_ERROR("pollset_set_add_fd", error); } static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) {} static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss, grpc_pollset *ps) { - po_join(exec_ctx, &pss->po, &ps->pollable_obj.po); -} + grpc_pollset_set *pss, grpc_pollset *ps) {} static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) {} static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *bag, - grpc_pollset_set *item) { - po_join(exec_ctx, &bag->po, &item->po); -} + grpc_pollset_set *item) {} static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *bag, grpc_pollset_set *item) {} -static void po_init(polling_obj *po, polling_obj_type type) { - gpr_mu_init(&po->mu); - po->type = type; - po->group = NULL; - po->next = po; - po->prev = po; -} - -static polling_group *pg_lock_latest(polling_group *pg) { - /* assumes pg unlocked; consumes ref, returns ref */ - gpr_mu_lock(&pg->po.mu); - while (pg->po.group != NULL) { - polling_group *new_pg = pg_ref(pg->po.group); - gpr_mu_unlock(&pg->po.mu); - pg_unref(pg); - pg = new_pg; - gpr_mu_lock(&pg->po.mu); - } - return pg; -} - -static void po_destroy(polling_obj *po) { - if (po->group != NULL) { - polling_group *pg = pg_lock_latest(po->group); - po->prev->next = po->next; - po->next->prev = po->prev; - gpr_mu_unlock(&pg->po.mu); - pg_unref(pg); - } - gpr_mu_destroy(&po->mu); -} - -static polling_group *pg_ref(polling_group *pg) { - gpr_ref(&pg->refs); - return pg; -} - -static void pg_unref(polling_group *pg) { - if (gpr_unref(&pg->refs)) { - po_destroy(&pg->po); - gpr_free(pg); - } -} - -static int po_cmp(polling_obj *a, polling_obj *b) { - if (a == b) return 0; - if (a->type < b->type) return -1; - if (a->type > b->type) return 1; - if (a < b) return -1; - assert(a > b); - return 1; -} - -static void po_join(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b) { - switch (po_cmp(a, b)) { - case 0: - return; - case 1: - GPR_SWAP(polling_obj *, a, b); - /* fall through */ - case -1: - gpr_mu_lock(&a->mu); - gpr_mu_lock(&b->mu); - - if (a->group == NULL) { - if (b->group == NULL) { - polling_obj *initial_po[] = {a, b}; - pg_create(exec_ctx, initial_po, GPR_ARRAY_SIZE(initial_po)); - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); - } else { - polling_group *b_group = pg_ref(b->group); - gpr_mu_unlock(&b->mu); - gpr_mu_unlock(&a->mu); - pg_join(exec_ctx, b_group, a); - } - } else if (b->group == NULL) { - polling_group *a_group = pg_ref(a->group); - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); - pg_join(exec_ctx, a_group, b); - } else if (a->group == b->group) { - /* nothing to do */ - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); - } else { - polling_group *a_group = pg_ref(a->group); - polling_group *b_group = pg_ref(b->group); - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); - pg_merge(exec_ctx, a_group, b_group); - } - } -} - -static void pg_notify(grpc_exec_ctx *exec_ctx, polling_obj *a, polling_obj *b) { - if (a->type == PO_FD && b->type == PO_POLLSET) { - pollset_add_fd_locked(exec_ctx, (grpc_pollset *)b, (grpc_fd *)a, true); - } else if (a->type == PO_POLLSET && b->type == PO_FD) { - pollset_add_fd_locked(exec_ctx, (grpc_pollset *)a, (grpc_fd *)b, true); - } -} - -static void pg_broadcast(grpc_exec_ctx *exec_ctx, polling_group *from, - polling_group *to) { - for (polling_obj *a = from->po.next; a != &from->po; a = a->next) { - for (polling_obj *b = to->po.next; b != &to->po; b = b->next) { - if (po_cmp(a, b) < 0) { - gpr_mu_lock(&a->mu); - gpr_mu_lock(&b->mu); - } else { - GPR_ASSERT(po_cmp(a, b) != 0); - gpr_mu_lock(&b->mu); - gpr_mu_lock(&a->mu); - } - pg_notify(exec_ctx, a, b); - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); - } - } -} - -static void pg_create(grpc_exec_ctx *exec_ctx, polling_obj **initial_po, - size_t initial_po_count) { - /* assumes all polling objects in initial_po are locked */ - polling_group *pg = (polling_group *)gpr_malloc(sizeof(*pg)); - po_init(&pg->po, PO_POLLING_GROUP); - gpr_ref_init(&pg->refs, (int)initial_po_count); - for (size_t i = 0; i < initial_po_count; i++) { - GPR_ASSERT(initial_po[i]->group == NULL); - initial_po[i]->group = pg; - } - for (size_t i = 1; i < initial_po_count; i++) { - initial_po[i]->prev = initial_po[i - 1]; - } - for (size_t i = 0; i < initial_po_count - 1; i++) { - initial_po[i]->next = initial_po[i + 1]; - } - initial_po[0]->prev = &pg->po; - initial_po[initial_po_count - 1]->next = &pg->po; - pg->po.next = initial_po[0]; - pg->po.prev = initial_po[initial_po_count - 1]; - for (size_t i = 1; i < initial_po_count; i++) { - for (size_t j = 0; j < i; j++) { - pg_notify(exec_ctx, initial_po[i], initial_po[j]); - } - } -} - -static void pg_join(grpc_exec_ctx *exec_ctx, polling_group *pg, - polling_obj *po) { - /* assumes neither pg nor po are locked; consumes one ref to pg */ - pg = pg_lock_latest(pg); - /* pg locked */ - for (polling_obj *existing = pg->po.next /* skip pg - it's just a stub */; - existing != &pg->po; existing = existing->next) { - if (po_cmp(po, existing) < 0) { - gpr_mu_lock(&po->mu); - gpr_mu_lock(&existing->mu); - } else { - GPR_ASSERT(po_cmp(po, existing) != 0); - gpr_mu_lock(&existing->mu); - gpr_mu_lock(&po->mu); - } - /* pg, po, existing locked */ - if (po->group != NULL) { - gpr_mu_unlock(&pg->po.mu); - polling_group *po_group = pg_ref(po->group); - gpr_mu_unlock(&po->mu); - gpr_mu_unlock(&existing->mu); - pg_merge(exec_ctx, pg, po_group); - /* early exit: polling obj picked up a group during joining: we needed - to do a full merge */ - return; - } - pg_notify(exec_ctx, po, existing); - gpr_mu_unlock(&po->mu); - gpr_mu_unlock(&existing->mu); - } - gpr_mu_lock(&po->mu); - if (po->group != NULL) { - gpr_mu_unlock(&pg->po.mu); - polling_group *po_group = pg_ref(po->group); - gpr_mu_unlock(&po->mu); - pg_merge(exec_ctx, pg, po_group); - /* early exit: polling obj picked up a group during joining: we needed - to do a full merge */ - return; - } - po->group = pg; - po->next = &pg->po; - po->prev = pg->po.prev; - po->prev->next = po->next->prev = po; - gpr_mu_unlock(&pg->po.mu); - gpr_mu_unlock(&po->mu); -} - -static void pg_merge(grpc_exec_ctx *exec_ctx, polling_group *a, - polling_group *b) { - for (;;) { - if (a == b) { - pg_unref(a); - pg_unref(b); - return; - } - if (a > b) GPR_SWAP(polling_group *, a, b); - gpr_mu_lock(&a->po.mu); - gpr_mu_lock(&b->po.mu); - if (a->po.group != NULL) { - polling_group *m2 = pg_ref(a->po.group); - gpr_mu_unlock(&a->po.mu); - gpr_mu_unlock(&b->po.mu); - pg_unref(a); - a = m2; - } else if (b->po.group != NULL) { - polling_group *m2 = pg_ref(b->po.group); - gpr_mu_unlock(&a->po.mu); - gpr_mu_unlock(&b->po.mu); - pg_unref(b); - b = m2; - } else { - break; - } - } - polling_group **unref = NULL; - size_t unref_count = 0; - size_t unref_cap = 0; - b->po.group = a; - pg_broadcast(exec_ctx, a, b); - pg_broadcast(exec_ctx, b, a); - while (b->po.next != &b->po) { - polling_obj *po = b->po.next; - gpr_mu_lock(&po->mu); - if (unref_count == unref_cap) { - unref_cap = GPR_MAX(8, 3 * unref_cap / 2); - unref = (polling_group **)gpr_realloc(unref, unref_cap * sizeof(*unref)); - } - unref[unref_count++] = po->group; - po->group = pg_ref(a); - // unlink from b - po->prev->next = po->next; - po->next->prev = po->prev; - // link to a - po->next = &a->po; - po->prev = a->po.prev; - po->next->prev = po->prev->next = po; - gpr_mu_unlock(&po->mu); - } - gpr_mu_unlock(&a->po.mu); - gpr_mu_unlock(&b->po.mu); - for (size_t i = 0; i < unref_count; i++) { - pg_unref(unref[i]); - } - gpr_free(unref); - pg_unref(b); -} - /******************************************************************************* * Event engine binding */ -- cgit v1.2.3 From 23adbd5a815026fc4543a3ccdb57a8871939f017 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 Oct 2017 15:29:18 -0700 Subject: Finish off epollex refactoring (no testing yet) --- src/core/lib/iomgr/ev_epollex_linux.c | 494 ++++++++++++++++++++++------------ 1 file changed, 319 insertions(+), 175 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 5317c6bff6..e456e108c5 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -135,6 +135,13 @@ static void fd_global_shutdown(void); * Pollset Declarations */ +typedef struct { + grpc_pollset_worker *next; + grpc_pollset_worker *prev; +} pwlink; + +typedef enum { PWLINK_POLLABLE = 0, PWLINK_POLLSET, PWLINK_COUNT } pwlinks; + struct grpc_pollset_worker { bool kicked; bool initialized_cv; @@ -142,8 +149,7 @@ struct grpc_pollset_worker { grpc_pollset *pollset; pollable *pollable_obj; - grpc_pollset_worker *next; - grpc_pollset_worker *prev; + pwlink links[PWLINK_COUNT]; }; #define MAX_EPOLL_EVENTS 100 @@ -154,7 +160,7 @@ struct grpc_pollset { pollable *active_pollable; bool kicked_without_poller; grpc_closure *shutdown_closure; - int worker_count; + grpc_pollset_worker *root_worker; int event_cursor; int event_count; @@ -164,13 +170,19 @@ struct grpc_pollset { /******************************************************************************* * Pollset-set Declarations */ + struct grpc_pollset_set { gpr_refcount refs; gpr_mu mu; grpc_pollset_set *parent; - // only valid if parent==NULL - pollable *child_pollsets; - grpc_fd *child_fds; + + size_t pollset_count; + size_t pollset_capacity; + pollable **pollsets; + + size_t fd_count; + size_t fd_capacity; + grpc_fd **fds; }; /******************************************************************************* @@ -483,64 +495,52 @@ static void pollset_global_shutdown(void) { static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - if (pollset->shutdown_closure != NULL && pollset->worker_count == 0) { + if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); pollset->shutdown_closure = NULL; } } -#if 0 -static void do_kick_all(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error_unused) { - grpc_error *error = GRPC_ERROR_NONE; - grpc_pollset *pollset = (grpc_pollset *)arg; - gpr_mu_lock(&pollset->pollable_obj.po.mu); - if (pollset->root_worker != NULL) { - grpc_pollset_worker *worker = pollset->root_worker; - do { - GRPC_STATS_INC_POLLSET_KICK(exec_ctx); - if (worker->pollable_obj != &pollset->pollable_obj) { - gpr_mu_lock(&worker->pollable_obj->po.mu); - } - if (worker->initialized_cv && worker != pollset->root_worker) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kickall_via_cv %p (pollable %p vs %p)", - pollset, worker, &pollset->pollable_obj, - worker->pollable_obj); - } - worker->kicked = true; - gpr_cv_signal(&worker->cv); - } else { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kickall_via_wakeup %p (pollable %p vs %p)", - pollset, worker, &pollset->pollable_obj, - worker->pollable_obj); - } - append_error(&error, - grpc_wakeup_fd_wakeup(&worker->pollable_obj->wakeup), - "pollset_shutdown"); - } - if (worker->pollable_obj != &pollset->pollable_obj) { - gpr_mu_unlock(&worker->pollable_obj->po.mu); - } - - worker = worker->links[PWL_POLLSET].next; - } while (worker != pollset->root_worker); +/* both pollset->active_pollable->mu, pollset->mu must be held before calling + * this function */ +static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + grpc_pollset_worker *specific_worker) { + pollable *p = pollset->active_pollable; + if (specific_worker->kicked) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); + } + return GRPC_ERROR_NONE; + } else if (gpr_tls_get(&g_current_thread_worker) == + (intptr_t)specific_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); + } + specific_worker->kicked = true; + return GRPC_ERROR_NONE; + } else if (specific_worker == p->root_worker) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); + } + specific_worker->kicked = true; + return grpc_wakeup_fd_wakeup(&p->wakeup); + } else { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); + } + specific_worker->kicked = true; + gpr_cv_signal(&specific_worker->cv); + return GRPC_ERROR_NONE; } - pollset->kick_alls_pending--; - pollset_maybe_finish_shutdown(exec_ctx, pollset); - gpr_mu_unlock(&pollset->pollable_obj.po.mu); - GRPC_LOG_IF_ERROR("kick_all", error); -} -#endif - -static void pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - abort(); } -#if 0 -static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, +/* both pollset->active_pollable->mu, pollset->mu must be held before calling + * this function */ +static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { + pollable *p = pollset->active_pollable; if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kick %p tls_pollset=%p tls_worker=%p " @@ -558,12 +558,7 @@ static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; } else { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_any_via_wakeup_fd", p); - } - grpc_error *err = pollable_materialize(p); - if (err != GRPC_ERROR_NONE) return err; - return grpc_wakeup_fd_wakeup(&p->wakeup); + return pollset_kick_one(exec_ctx, pollset, pollset->root_worker); } } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -571,53 +566,32 @@ static grpc_error *pollset_kick_inner(grpc_pollset *pollset, pollable *p, } return GRPC_ERROR_NONE; } - } else if (specific_worker->kicked) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); - } - return GRPC_ERROR_NONE; - } else if (gpr_tls_get(&g_current_thread_worker) == - (intptr_t)specific_worker) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); - } - specific_worker->kicked = true; - return GRPC_ERROR_NONE; - } else if (specific_worker == p->root_worker) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); - } - grpc_error *err = pollable_materialize(p); - if (err != GRPC_ERROR_NONE) return err; - specific_worker->kicked = true; - return grpc_wakeup_fd_wakeup(&p->wakeup); } else { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); - } - specific_worker->kicked = true; - gpr_cv_signal(&specific_worker->cv); - return GRPC_ERROR_NONE; + return pollset_kick_one(exec_ctx, pollset, specific_worker); } } -#endif -/* p->po.mu must be held before calling this function */ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { - abort(); -#if 0 - pollable *p = pollset->current_pollable_obj; - GRPC_STATS_INC_POLLSET_KICK(exec_ctx); - if (p != &pollset->pollable_obj) { - gpr_mu_lock(&p->po.mu); - } - grpc_error *error = pollset_kick_inner(pollset, p, specific_worker); - if (p != &pollset->pollable_obj) { - gpr_mu_unlock(&p->po.mu); + pollable *p = pollset->active_pollable; + gpr_mu_lock(&p->mu); + grpc_error *error = pollset_kick_inner(exec_ctx, pollset, specific_worker); + gpr_mu_unlock(&p->mu); + return error; +} + +static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset) { + pollable *p = pollset->active_pollable; + grpc_error *error = GRPC_ERROR_NONE; + const char *err_desc = "pollset_kick_all"; + gpr_mu_lock(&p->mu); + for (grpc_pollset_worker *w = pollset->root_worker; w != NULL; + w = w->links[PWLINK_POLLSET].next) { + append_error(&error, pollset_kick_one(exec_ctx, pollset, w), err_desc); } + gpr_mu_unlock(&p->mu); return error; -#endif } static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { @@ -701,7 +675,7 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_closure *closure) { GPR_ASSERT(pollset->shutdown_closure == NULL); pollset->shutdown_closure = closure; - pollset_kick_all(exec_ctx, pollset); + GRPC_LOG_IF_ERROR("pollset_shutdown", pollset_kick_all(exec_ctx, pollset)); pollset_maybe_finish_shutdown(exec_ctx, pollset); } @@ -790,37 +764,41 @@ static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } /* Return true if first in list */ -static bool worker_insert(pollable *pollable_obj, grpc_pollset_worker *worker) { - if (pollable_obj->root_worker == NULL) { - pollable_obj->root_worker = worker; - worker->next = worker->prev = worker; +static bool worker_insert(grpc_pollset_worker **root_worker, + grpc_pollset_worker *worker, pwlinks link) { + if (*root_worker == NULL) { + *root_worker = worker; + worker->links[link].next = worker->links[link].prev = worker; return true; } else { - worker->next = pollable_obj->root_worker; - worker->prev = worker->next->prev; - worker->next->prev = worker; - worker->prev->next = worker; + worker->links[link].next = *root_worker; + worker->links[link].prev = worker->links[link].next->links[link].prev; + worker->links[link].next->links[link].prev = worker; + worker->links[link].prev->links[link].next = worker; return false; } } /* returns the new root IFF the root changed */ -static grpc_pollset_worker *worker_remove(pollable *pollable_obj, - grpc_pollset_worker *worker) { - if (worker == pollable_obj->root_worker) { - if (worker == worker->next) { - pollable_obj->root_worker = NULL; - return NULL; +typedef enum { WRR_NEW_ROOT, WRR_EMPTIED, WRR_REMOVED } worker_remove_result; + +static worker_remove_result worker_remove(grpc_pollset_worker **root_worker, + grpc_pollset_worker *worker, + pwlinks link) { + if (worker == *root_worker) { + if (worker == worker->links[link].next) { + *root_worker = NULL; + return WRR_EMPTIED; } else { - pollable_obj->root_worker = worker->next; - worker->prev->next = worker->next; - worker->next->prev = worker->prev; - return pollable_obj->root_worker; + *root_worker = worker->links[link].next; + worker->links[link].prev->links[link].next = worker->links[link].next; + worker->links[link].next->links[link].prev = worker->links[link].prev; + return WRR_NEW_ROOT; } } else { - worker->prev->next = worker->next; - worker->next->prev = worker->prev; - return NULL; + worker->links[link].prev->links[link].next = worker->links[link].next; + worker->links[link].next->links[link].prev = worker->links[link].prev; + return WRR_REMOVED; } } @@ -834,9 +812,10 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->kicked = false; worker->pollset = pollset; worker->pollable_obj = pollable_ref(pollset->active_pollable); + worker_insert(&pollset->root_worker, worker, PWLINK_POLLSET); gpr_mu_lock(&worker->pollable_obj->mu); - pollset->worker_count++; - if (!worker_insert(worker->pollable_obj, worker)) { + if (!worker_insert(&worker->pollable_obj->root_worker, worker, + PWLINK_POLLABLE)) { worker->initialized_cv = true; gpr_cv_init(&worker->cv); if (GRPC_TRACER_ON(grpc_polling_trace) && @@ -876,8 +855,9 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl) { gpr_mu_lock(&worker->pollable_obj->mu); - grpc_pollset_worker *new_root = worker_remove(worker->pollable_obj, worker); - if (new_root != NULL) { + if (worker_remove(&worker->pollable_obj->root_worker, worker, + PWLINK_POLLABLE) == WRR_NEW_ROOT) { + grpc_pollset_worker *new_root = worker->pollable_obj->root_worker; GPR_ASSERT(new_root->initialized_cv); gpr_cv_signal(&new_root->cv); } @@ -885,8 +865,7 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_cv_destroy(&worker->cv); } gpr_mu_unlock(&worker->pollable_obj->mu); - pollset->worker_count--; - if (pollset->worker_count == 0) { + if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET)) { pollset_maybe_finish_shutdown(exec_ctx, pollset); } } @@ -932,48 +911,64 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, return error; } +static grpc_error *pollset_transition_pollable_from_empty_to_fd_locked( + grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { + static const char *err_desc = "pollset_transition_pollable_from_empty_to_fd"; + grpc_error *error = GRPC_ERROR_NONE; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PS:%p add fd %p; transition pollable from empty to fd", + pollset, fd); + } + append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); + pollable_unref(pollset->active_pollable); + append_error(&error, fd_become_pollable(fd, &pollset->active_pollable), + err_desc); + return error; +} + +static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( + grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *and_add_fd) { + static const char *err_desc = "pollset_transition_pollable_from_fd_to_multi"; + grpc_error *error = GRPC_ERROR_NONE; + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p add fd %p; transition pollable from fd %p to multipoller", + pollset, and_add_fd, pollset->active_pollable->owner_fd); + } + append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); + pollable_unref(pollset->active_pollable); + grpc_fd *initial_fd = pollset->active_pollable->owner_fd; + if (append_error(&error, pollable_create(PO_MULTI, &pollset->active_pollable), + err_desc)) { + append_error(&error, pollable_add_fd(pollset->active_pollable, initial_fd), + err_desc); + if (and_add_fd != NULL) { + append_error(&error, + pollable_add_fd(pollset->active_pollable, and_add_fd), + err_desc); + } + } + return error; +} + /* expects pollsets locked, flag whether fd is locked or not */ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { - static const char *err_desc = "pollset_add_fd"; grpc_error *error = GRPC_ERROR_NONE; pollable *po_at_start = pollable_ref(pollset->active_pollable); switch (pollset->active_pollable->type) { case PO_EMPTY: /* empty pollable --> single fd pollable */ - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, - "PS:%p add fd %p; transition pollable from empty to fd", - pollset, fd); - } - pollset_kick_all(exec_ctx, pollset); - pollable_unref(pollset->active_pollable); - append_error(&error, fd_become_pollable(fd, &pollset->active_pollable), - err_desc); + error = pollset_transition_pollable_from_empty_to_fd_locked(exec_ctx, + pollset, fd); break; case PO_FD: /* fd --> multipoller */ - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log( - GPR_DEBUG, - "PS:%p add fd %p; transition pollable from fd %p to multipoller", - pollset, fd, pollset->active_pollable->owner_fd); - } - pollset_kick_all(exec_ctx, pollset); - pollable_unref(pollset->active_pollable); - if (append_error(&error, - pollable_create(PO_MULTI, &pollset->active_pollable), - err_desc)) { - append_error(&error, pollable_add_fd(pollset->active_pollable, - po_at_start->owner_fd), - err_desc); - append_error(&error, pollable_add_fd(pollset->active_pollable, fd), - err_desc); - } + error = pollset_transition_pollable_from_fd_to_multi_locked(exec_ctx, + pollset, fd); break; case PO_MULTI: - append_error(&error, pollable_add_fd(pollset->active_pollable, fd), - err_desc); + error = pollable_add_fd(pollset->active_pollable, fd); break; } if (error != GRPC_ERROR_NONE) { @@ -985,6 +980,34 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, return error; } +static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + pollable **pollable_obj) { + grpc_error *error = GRPC_ERROR_NONE; + gpr_mu_lock(&pollset->mu); + pollable *po_at_start = pollable_ref(pollset->active_pollable); + switch (pollset->active_pollable->type) { + case PO_EMPTY: + error = pollable_create(PO_MULTI, &pollset->active_pollable); + break; + case PO_FD: + error = pollset_transition_pollable_from_fd_to_multi_locked( + exec_ctx, pollset, NULL); + break; + case PO_MULTI: + break; + } + if (error != GRPC_ERROR_NONE) { + pollable_unref(pollset->active_pollable); + pollset->active_pollable = po_at_start; + } else { + *pollable_obj = pollable_ref(pollset->active_pollable); + pollable_unref(po_at_start); + } + gpr_mu_unlock(&pollset->mu); + return error; +} + static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { gpr_mu_lock(&pollset->mu); @@ -1008,12 +1031,9 @@ static grpc_pollset_set *pss_lock_adam(grpc_pollset_set *pss) { } static grpc_pollset_set *pollset_set_create(void) { - grpc_pollset_set *pss = (grpc_pollset_set *)gpr_malloc(sizeof(*pss)); + grpc_pollset_set *pss = (grpc_pollset_set *)gpr_zalloc(sizeof(*pss)); gpr_mu_init(&pss->mu); gpr_ref_init(&pss->refs, 1); - pss->parent = NULL; - pss->child_pollsets = NULL; - pss->child_fds = NULL; return pss; } @@ -1025,32 +1045,156 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_fd"; pss = pss_lock_adam(pss); - pollable *p = pss->child_pollsets; - if (p != NULL) { - do { - append_error(&error, pollable_add_fd(p, fd), err_desc); - p = p->next; - } while (p != pss->child_pollsets); - - } else { + for (size_t i = 0; i < pss->pollset_count; i++) { + append_error(&error, pollable_add_fd(pss->pollsets[i], fd), err_desc); } + if (pss->fd_count == pss->fd_capacity) { + pss->fd_capacity = GPR_MAX(pss->fd_capacity * 2, 8); + pss->fds = gpr_realloc(pss->fds, pss->fd_capacity * sizeof(*pss->fds)); + } + REF_BY(fd, 2, "pollset_set"); + pss->fds[pss->fd_count++] = fd; gpr_mu_unlock(&pss->mu); - GRPC_LOG_IF_ERROR("pollset_set_add_fd", error); + GRPC_LOG_IF_ERROR(err_desc, error); } static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, - grpc_fd *fd) {} + grpc_fd *fd) { + pss = pss_lock_adam(pss); + size_t i; + for (i = 0; i < pss->fd_count; i++) { + if (pss->fds[i] == fd) { + UNREF_BY(exec_ctx, fd, 2, "pollset_set"); + break; + } + } + GPR_ASSERT(i != pss->fd_count); + for (; i < pss->fd_count - 1; i++) { + pss->fds[i] = pss->fds[i + 1]; + } + pss->fd_count--; + gpr_mu_unlock(&pss->mu); +} static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss, grpc_pollset *ps) {} + grpc_pollset_set *pss, grpc_pollset *ps) { + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_set_add_pollset"; + pollable *pollable_obj; + if (!GRPC_LOG_IF_ERROR( + err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { + return; + } + pss = pss_lock_adam(pss); + for (size_t i = 0; i < pss->fd_count; i++) { + append_error(&error, pollable_add_fd(pollable_obj, pss->fds[i]), err_desc); + } + if (pss->pollset_count == pss->pollset_capacity) { + pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); + pss->pollsets = gpr_realloc(pss->pollsets, + pss->pollset_capacity * sizeof(*pss->pollsets)); + } + pss->pollsets[pss->pollset_count++] = pollable_obj; + gpr_mu_unlock(&pss->mu); + + GRPC_LOG_IF_ERROR(err_desc, error); +} static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss, grpc_pollset *ps) {} + grpc_pollset_set *pss, grpc_pollset *ps) { + pss = pss_lock_adam(pss); + size_t i; + for (i = 0; i < pss->pollset_count; i++) { + if (pss->pollsets[i] == ps->active_pollable) { + pollable_unref(pss->pollsets[i]); + break; + } + } + GPR_ASSERT(i != pss->pollset_count); + for (; i < pss->pollset_count - 1; i++) { + pss->pollsets[i] = pss->pollsets[i + 1]; + } + pss->pollset_count--; + gpr_mu_unlock(&pss->mu); +} + +static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, + size_t fd_count, pollable **pollables, + size_t pollable_count, + const char *err_desc) { + grpc_error *error = GRPC_ERROR_NONE; + for (size_t i = 0; i < fd_count; i++) { + for (size_t j = 0; j < pollable_count; j++) { + append_error(&error, pollable_add_fd(pollables[j], fds[i]), err_desc); + } + } + return error; +} static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *bag, - grpc_pollset_set *item) {} + grpc_pollset_set *a, + grpc_pollset_set *b) { + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_set_add_fd"; + for (;;) { + if (a == b) { + // pollset ancestors are the same: nothing to do + return; + } + if (a > b) { + GPR_SWAP(grpc_pollset_set *, a, b); + } + gpr_mu_lock(&a->mu); + gpr_mu_lock(&b->mu); + if (a->parent != NULL) { + a = a->parent; + } else if (b->parent != NULL) { + b = b->parent; + } else { + break; // exit loop, both pollsets locked + } + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); + } + // try to do the least copying possible + // TODO(ctiller): there's probably a better heuristic here + const size_t a_size = a->fd_count + a->pollset_count; + const size_t b_size = b->fd_count + b->pollset_count; + if (b_size > a_size) { + GPR_SWAP(grpc_pollset_set *, a, b); + } + gpr_ref(&a->refs); + b->parent = a; + append_error(&error, + add_fds_to_pollables(exec_ctx, a->fds, a->fd_count, b->pollsets, + b->pollset_count, "merge_a2b"), + err_desc); + append_error(&error, + add_fds_to_pollables(exec_ctx, b->fds, b->fd_count, a->pollsets, + a->pollset_count, "merge_b2a"), + err_desc); + if (a->fd_capacity < a->fd_count + b->fd_count) { + a->fd_capacity = GPR_MAX(2 * a->fd_capacity, a->fd_count + b->fd_count); + a->fds = gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)); + } + if (a->pollset_capacity < a->pollset_count + b->pollset_count) { + a->pollset_capacity = + GPR_MAX(2 * a->pollset_capacity, a->pollset_count + b->pollset_count); + a->pollsets = + gpr_realloc(a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); + } + memcpy(a->fds + a->fd_count, b->fds, b->fd_count * sizeof(*b->fds)); + memcpy(a->pollsets + a->pollset_count, b->pollsets, + b->pollset_count * sizeof(*b->pollsets)); + a->fd_count += b->fd_count; + a->pollset_count += b->pollset_count; + gpr_free(b->fds); + gpr_free(b->pollsets); + b->fd_count = b->fd_capacity = b->pollset_count = b->pollset_capacity = 0; + gpr_mu_unlock(&a->mu); + gpr_mu_unlock(&b->mu); +} static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *bag, -- cgit v1.2.3 From dca3c47dfdee591ccd5b358710ff700faeb38c99 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 Oct 2017 15:33:27 -0700 Subject: epex should be enabled by default --- src/core/lib/iomgr/ev_posix.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c index 4d3ae2228e..80269881cb 100644 --- a/src/core/lib/iomgr/ev_posix.c +++ b/src/core/lib/iomgr/ev_posix.c @@ -62,11 +62,9 @@ typedef struct { } event_engine_factory; static const event_engine_factory g_factories[] = { - {"epoll1", grpc_init_epoll1_linux}, - {"epollsig", grpc_init_epollsig_linux}, - {"poll", grpc_init_poll_posix}, + {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux}, + {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix}, - {"epollex", grpc_init_epollex_linux}, }; static void add(const char *beg, const char *end, char ***ss, size_t *ns) { -- cgit v1.2.3 From 65da0efda3bcf8c7e7962a9a30602df1c9c92bb6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 Oct 2017 15:35:59 -0700 Subject: Init mutex --- src/core/lib/iomgr/ev_epollex_linux.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index e456e108c5..7d3482d779 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -428,6 +428,7 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { *p = gpr_malloc(sizeof(**p)); (*p)->type = type; gpr_ref_init(&(*p)->refs, 1); + gpr_mu_init(&(*p)->mu); (*p)->epfd = epfd; (*p)->wakeup = wakeup_fd; (*p)->owner_fd = NULL; -- cgit v1.2.3 From 39908712befdb5b6d81c7b2c281ee849d8322350 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 Oct 2017 22:58:24 +0000 Subject: Fixes --- src/core/lib/iomgr/ev_epollex_linux.c | 1 + test/core/iomgr/pollset_set_test.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 7d3482d779..5b26901baa 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -653,6 +653,7 @@ static grpc_error *fd_become_pollable(grpc_fd *fd, pollable **p) { if (fd->pollable_obj == NULL) { if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj), err_desc)) { +fd->pollable_obj->owner_fd = fd; if (!append_error(&error, pollable_add_fd(fd->pollable_obj, fd), err_desc)) { pollable_unref(fd->pollable_obj); diff --git a/test/core/iomgr/pollset_set_test.c b/test/core/iomgr/pollset_set_test.c index 70efca8b16..aa1ad37927 100644 --- a/test/core/iomgr/pollset_set_test.c +++ b/test/core/iomgr/pollset_set_test.c @@ -431,13 +431,13 @@ void pollset_set_test_empty_pollset() { } int main(int argc, char **argv) { - const char *poll_strategy = grpc_get_poll_strategy_name(); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_test_init(argc, argv); grpc_init(); + const char *poll_strategy = grpc_get_poll_strategy_name(); if (poll_strategy != NULL && - (strcmp(poll_strategy, "epoll") == 0 || + (strcmp(poll_strategy, "epollsig") == 0 || strcmp(poll_strategy, "epoll-threadpool") == 0)) { pollset_set_test_basic(); pollset_set_test_dup_fds(); -- cgit v1.2.3 From c5ce0571e0ed718729ff38229630bf40277ff3a7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 3 Oct 2017 23:09:41 +0000 Subject: Locking fixes --- src/core/lib/iomgr/ev_epollex_linux.c | 44 +++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 5b26901baa..ca30cb5c6c 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -882,9 +882,9 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker worker; if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64 - ".%09d deadline=%" PRId64 ".%09d kwp=%d", + ".%09d deadline=%" PRId64 ".%09d kwp=%d pollable=%p", pollset, worker_hdl, &worker, now.tv_sec, now.tv_nsec, - deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller); + deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, pollset->active_pollable); } static const char *err_desc = "pollset_work"; if (pollset->kicked_without_poller) { @@ -918,8 +918,8 @@ static grpc_error *pollset_transition_pollable_from_empty_to_fd_locked( static const char *err_desc = "pollset_transition_pollable_from_empty_to_fd"; grpc_error *error = GRPC_ERROR_NONE; if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p add fd %p; transition pollable from empty to fd", - pollset, fd); + gpr_log(GPR_DEBUG, "PS:%p add fd %p (%d); transition pollable from empty to fd", + pollset, fd, fd->fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); pollable_unref(pollset->active_pollable); @@ -934,8 +934,8 @@ static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( grpc_error *error = GRPC_ERROR_NONE; if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, - "PS:%p add fd %p; transition pollable from fd %p to multipoller", - pollset, and_add_fd, pollset->active_pollable->owner_fd); + "PS:%p add fd %p (%d); transition pollable from fd %p to multipoller", + pollset, and_add_fd, and_add_fd?and_add_fd->fd:-1, pollset->active_pollable->owner_fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); pollable_unref(pollset->active_pollable); @@ -1025,9 +1025,9 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static grpc_pollset_set *pss_lock_adam(grpc_pollset_set *pss) { gpr_mu_lock(&pss->mu); while (pss->parent != NULL) { - gpr_mu_lock(&pss->parent->mu); gpr_mu_unlock(&pss->mu); pss = pss->parent; + gpr_mu_lock(&pss->mu); } return pss; } @@ -1044,6 +1044,9 @@ static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_fd"; pss = pss_lock_adam(pss); @@ -1063,6 +1066,9 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: del fd %p", pss, fd); + } pss = pss_lock_adam(pss); size_t i; for (i = 0; i < pss->fd_count; i++) { @@ -1081,9 +1087,12 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_pollset"; - pollable *pollable_obj; + pollable *pollable_obj = NULL; if (!GRPC_LOG_IF_ERROR( err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { return; @@ -1105,6 +1114,9 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: del pollset %p", pss, ps); + } pss = pss_lock_adam(pss); size_t i; for (i = 0; i < pss->pollset_count; i++) { @@ -1137,6 +1149,9 @@ static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *a, grpc_pollset_set *b) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS: merge (%p, %p)", a, b); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_fd"; for (;;) { @@ -1147,8 +1162,10 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, if (a > b) { GPR_SWAP(grpc_pollset_set *, a, b); } - gpr_mu_lock(&a->mu); - gpr_mu_lock(&b->mu); + gpr_mu *a_mu = &a->mu; + gpr_mu *b_mu = &b->mu; + gpr_mu_lock(a_mu); + gpr_mu_lock(b_mu); if (a->parent != NULL) { a = a->parent; } else if (b->parent != NULL) { @@ -1156,8 +1173,8 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } else { break; // exit loop, both pollsets locked } - gpr_mu_unlock(&a->mu); - gpr_mu_unlock(&b->mu); + gpr_mu_unlock(a_mu); + gpr_mu_unlock(b_mu); } // try to do the least copying possible // TODO(ctiller): there's probably a better heuristic here @@ -1166,6 +1183,9 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, if (b_size > a_size) { GPR_SWAP(grpc_pollset_set *, a, b); } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS: parent %p to %p", b, a); + } gpr_ref(&a->refs); b->parent = a; append_error(&error, -- cgit v1.2.3 From 389ea90c316adbe0de8f037dc5d76ecc8cd0351e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 17:42:49 +0000 Subject: Refcounting fix + tracing --- src/core/lib/iomgr/ev_epollex_linux.c | 97 ++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index ca30cb5c6c..ad41373da0 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -49,8 +49,13 @@ #include "src/core/lib/support/block_annotate.h" #include "src/core/lib/support/spinlock.h" +#ifndef NDEBUG +grpc_tracer_flag grpc_trace_pollable_refcount = + GRPC_TRACER_INITIALIZER(false, "pollable_refcount"); +#endif + /******************************************************************************* -* pollable Declarations + * pollable Declarations */ typedef enum { PO_MULTI, PO_FD, PO_EMPTY } pollable_type; @@ -97,8 +102,17 @@ static char *pollable_desc(pollable *p) { static pollable *g_empty_pollable; static grpc_error *pollable_create(pollable_type type, pollable **p); +#ifdef NDEBUG static pollable *pollable_ref(pollable *p); static void pollable_unref(pollable *p); +#define POLLABLE_REF(p, r) pollable_ref(p) +#define POLLABLE_UNREF(p, r) pollable_unref(p) +#else +static pollable *pollable_ref(pollable *p, int line, const char *reason); +static void pollable_unref(pollable *p, int line, const char *reason); +#define POLLABLE_REF(p, r) pollable_ref((p), __LINE__, (r)) +#define POLLABLE_UNREF(p, r) pollable_unref((p), __LINE__, (r)) +#endif /******************************************************************************* * Fd Declarations @@ -248,9 +262,7 @@ static void fd_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_fd *fd = (grpc_fd *)arg; /* Add the fd to the freelist */ grpc_iomgr_unregister_object(&fd->iomgr_object); - if (fd->pollable_obj) { - pollable_unref(fd->pollable_obj); - } + POLLABLE_UNREF(fd->pollable_obj, "fd_pollable"); gpr_mu_destroy(&fd->pollable_mu); gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; @@ -438,15 +450,33 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { return GRPC_ERROR_NONE; } +#ifdef NDEBUG static pollable *pollable_ref(pollable *p) { +#else +static pollable *pollable_ref(pollable *p, int line, const char *reason) { + if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) { + int r = (int)gpr_atm_no_barrier_load(&p->refs.count); + gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p ref %d->%d %s", p, r, r+1, reason); + } +#endif gpr_ref(&p->refs); return p; } +#ifdef NDEBUG static void pollable_unref(pollable *p) { +#else +static void pollable_unref(pollable *p, int line, const char *reason) { + if (p == NULL) return; + if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) { + int r = (int)gpr_atm_no_barrier_load(&p->refs.count); + gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p unref %d->%d %s", p, r, r-1, reason); + } +#endif if (p != NULL && gpr_unref(&p->refs)) { close(p->epfd); grpc_wakeup_fd_destroy(&p->wakeup); + gpr_free(p); } } @@ -489,7 +519,7 @@ static grpc_error *pollset_global_init(void) { } static void pollset_global_shutdown(void) { - pollable_unref(g_empty_pollable); + POLLABLE_UNREF(g_empty_pollable, "g_empty_pollable"); gpr_tls_destroy(&g_current_thread_pollset); gpr_tls_destroy(&g_current_thread_worker); } @@ -597,7 +627,7 @@ static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { gpr_mu_init(&pollset->mu); - pollset->active_pollable = pollable_ref(g_empty_pollable); + pollset->active_pollable = POLLABLE_REF(g_empty_pollable, "pollset"); *mu = &pollset->mu; } @@ -656,14 +686,14 @@ static grpc_error *fd_become_pollable(grpc_fd *fd, pollable **p) { fd->pollable_obj->owner_fd = fd; if (!append_error(&error, pollable_add_fd(fd->pollable_obj, fd), err_desc)) { - pollable_unref(fd->pollable_obj); + POLLABLE_UNREF(fd->pollable_obj, "fd_pollable"); fd->pollable_obj = NULL; } } } if (error == GRPC_ERROR_NONE) { GPR_ASSERT(fd->pollable_obj != NULL); - *p = pollable_ref(fd->pollable_obj); + *p = POLLABLE_REF(fd->pollable_obj, "pollset"); } else { GPR_ASSERT(fd->pollable_obj == NULL); *p = NULL; @@ -724,7 +754,7 @@ static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, /* pollset_shutdown is guaranteed to be called before pollset_destroy. */ static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - pollable_unref(pollset->active_pollable); + POLLABLE_UNREF(pollset->active_pollable, "pollset"); pollset->active_pollable = NULL; GRPC_LOG_IF_ERROR("pollset_process_events", pollset_process_events(exec_ctx, pollset, true)); @@ -813,7 +843,7 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->initialized_cv = false; worker->kicked = false; worker->pollset = pollset; - worker->pollable_obj = pollable_ref(pollset->active_pollable); + worker->pollable_obj = POLLABLE_REF(pollset->active_pollable, "pollset_worker"); worker_insert(&pollset->root_worker, worker, PWLINK_POLLSET); gpr_mu_lock(&worker->pollable_obj->mu); if (!worker_insert(&worker->pollable_obj->root_worker, worker, @@ -870,6 +900,7 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET)) { pollset_maybe_finish_shutdown(exec_ctx, pollset); } + POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); } /* pollset->po.mu lock must be held by the caller before calling this. @@ -922,7 +953,7 @@ static grpc_error *pollset_transition_pollable_from_empty_to_fd_locked( pollset, fd, fd->fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); - pollable_unref(pollset->active_pollable); + POLLABLE_UNREF(pollset->active_pollable, "pollset"); append_error(&error, fd_become_pollable(fd, &pollset->active_pollable), err_desc); return error; @@ -938,8 +969,9 @@ static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( pollset, and_add_fd, and_add_fd?and_add_fd->fd:-1, pollset->active_pollable->owner_fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); - pollable_unref(pollset->active_pollable); grpc_fd *initial_fd = pollset->active_pollable->owner_fd; + POLLABLE_UNREF(pollset->active_pollable, "pollset"); + pollset->active_pollable = NULL; if (append_error(&error, pollable_create(PO_MULTI, &pollset->active_pollable), err_desc)) { append_error(&error, pollable_add_fd(pollset->active_pollable, initial_fd), @@ -957,7 +989,7 @@ static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { grpc_error *error = GRPC_ERROR_NONE; - pollable *po_at_start = pollable_ref(pollset->active_pollable); + pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_add_fd"); switch (pollset->active_pollable->type) { case PO_EMPTY: /* empty pollable --> single fd pollable */ @@ -974,10 +1006,10 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, break; } if (error != GRPC_ERROR_NONE) { - pollable_unref(pollset->active_pollable); + POLLABLE_UNREF(pollset->active_pollable, "pollset"); pollset->active_pollable = po_at_start; } else { - pollable_unref(po_at_start); + POLLABLE_UNREF(po_at_start, "pollset_add_fd"); } return error; } @@ -987,9 +1019,10 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, pollable **pollable_obj) { grpc_error *error = GRPC_ERROR_NONE; gpr_mu_lock(&pollset->mu); - pollable *po_at_start = pollable_ref(pollset->active_pollable); + pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable"); switch (pollset->active_pollable->type) { case PO_EMPTY: + POLLABLE_UNREF(pollset->active_pollable, "pollset"); error = pollable_create(PO_MULTI, &pollset->active_pollable); break; case PO_FD: @@ -1000,11 +1033,12 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, break; } if (error != GRPC_ERROR_NONE) { - pollable_unref(pollset->active_pollable); + POLLABLE_UNREF(pollset->active_pollable, "pollset"); pollset->active_pollable = po_at_start; + *pollable_obj = NULL; } else { - *pollable_obj = pollable_ref(pollset->active_pollable); - pollable_unref(po_at_start); + *pollable_obj = POLLABLE_REF(pollset->active_pollable, "pollset_set"); + POLLABLE_UNREF(po_at_start, "pollset_as_multipollable"); } gpr_mu_unlock(&pollset->mu); return error; @@ -1039,8 +1073,22 @@ static grpc_pollset_set *pollset_set_create(void) { return pss; } -static void pollset_set_destroy(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss) {} +static void pollset_set_unref(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss) { + if (pss == NULL) return; + if (!gpr_unref(&pss->refs)) return; + pollset_set_unref(exec_ctx, pss->parent); + gpr_mu_destroy(&pss->mu); + for (size_t i=0; ipollset_count; i++) { + POLLABLE_UNREF(pss->pollsets[i], "pollset_set"); + } + for (size_t i=0;ifd_count; i++) { + UNREF_BY(exec_ctx, pss->fds[i], 2, "pollset_set"); + } + gpr_free(pss->pollsets); + gpr_free(pss->fds); + gpr_free(pss); +} static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { @@ -1095,6 +1143,7 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, pollable *pollable_obj = NULL; if (!GRPC_LOG_IF_ERROR( err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { +GPR_ASSERT(pollable_obj==NULL); return; } pss = pss_lock_adam(pss); @@ -1121,7 +1170,7 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, size_t i; for (i = 0; i < pss->pollset_count; i++) { if (pss->pollsets[i] == ps->active_pollable) { - pollable_unref(pss->pollsets[i]); + POLLABLE_UNREF(pss->pollsets[i], "pollset_set"); break; } } @@ -1251,7 +1300,7 @@ static const grpc_event_engine_vtable vtable = { pollset_add_fd, pollset_set_create, - pollset_set_destroy, + pollset_set_unref, // destroy ==> unref 1 public ref pollset_set_add_pollset, pollset_set_del_pollset, pollset_set_add_pollset_set, @@ -1272,6 +1321,8 @@ const grpc_event_engine_vtable *grpc_init_epollex_linux( return NULL; } + grpc_register_tracer(&grpc_trace_pollable_refcount); + fd_global_init(); if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { -- cgit v1.2.3 From 90a9d7d04a556647ffb1584454a54e97bc3c7ca2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 21:24:03 +0000 Subject: Fixes --- src/core/lib/iomgr/ev_epollex_linux.c | 56 ++++++++++++++++++++++++----------- src/core/lib/iomgr/tcp_posix.c | 2 +- 2 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index ad41373da0..396731758e 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -49,6 +49,9 @@ #include "src/core/lib/support/block_annotate.h" #include "src/core/lib/support/spinlock.h" +// debug aid: create workers on the heap (allows asan to spot use-after-destruction) +#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1 + #ifndef NDEBUG grpc_tracer_flag grpc_trace_pollable_refcount = GRPC_TRACER_INITIALIZER(false, "pollable_refcount"); @@ -421,28 +424,30 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { if (epfd == -1) { return GRPC_OS_ERROR(errno, "epoll_create1"); } - grpc_wakeup_fd wakeup_fd; - grpc_error *err = grpc_wakeup_fd_init(&wakeup_fd); + *p = gpr_malloc(sizeof(**p)); + grpc_error *err = grpc_wakeup_fd_init(&(*p)->wakeup); if (err != GRPC_ERROR_NONE) { close(epfd); + gpr_free(*p); + *p = NULL; return err; } struct epoll_event ev; ev.events = (uint32_t)(EPOLLIN | EPOLLET); - ev.data.ptr = NULL; - if (epoll_ctl(epfd, EPOLL_CTL_ADD, wakeup_fd.read_fd, &ev) != 0) { + ev.data.ptr = (void*)(1 | (intptr_t)&(*p)->wakeup); + if (epoll_ctl(epfd, EPOLL_CTL_ADD, (*p)->wakeup.read_fd, &ev) != 0) { err = GRPC_OS_ERROR(errno, "epoll_ctl"); close(epfd); - grpc_wakeup_fd_destroy(&wakeup_fd); + grpc_wakeup_fd_destroy(&(*p)->wakeup); +gpr_free(*p); +*p = NULL; return err; } - *p = gpr_malloc(sizeof(**p)); (*p)->type = type; gpr_ref_init(&(*p)->refs, 1); gpr_mu_init(&(*p)->mu); (*p)->epfd = epfd; - (*p)->wakeup = wakeup_fd; (*p)->owner_fd = NULL; (*p)->pollset_set = NULL; (*p)->next = (*p)->prev = *p; @@ -538,6 +543,7 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { pollable *p = pollset->active_pollable; +GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); @@ -617,10 +623,13 @@ static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_error *error = GRPC_ERROR_NONE; const char *err_desc = "pollset_kick_all"; gpr_mu_lock(&p->mu); - for (grpc_pollset_worker *w = pollset->root_worker; w != NULL; - w = w->links[PWLINK_POLLSET].next) { +grpc_pollset_worker *w = pollset->root_worker; +if (w!=NULL) { +do { append_error(&error, pollset_kick_one(exec_ctx, pollset, w), err_desc); - } + w = w->links[PWLINK_POLLSET].next; +} while (w != pollset->root_worker); +} gpr_mu_unlock(&p->mu); return error; } @@ -910,26 +919,31 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { +#ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP + grpc_pollset_worker *worker = gpr_malloc(sizeof(*worker)); +#define WORKER_PTR (worker) +#else grpc_pollset_worker worker; +#define WORKER_PTR (&worker) +#endif if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64 ".%09d deadline=%" PRId64 ".%09d kwp=%d pollable=%p", - pollset, worker_hdl, &worker, now.tv_sec, now.tv_nsec, + pollset, worker_hdl, WORKER_PTR, now.tv_sec, now.tv_nsec, deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, pollset->active_pollable); } static const char *err_desc = "pollset_work"; + grpc_error *error = GRPC_ERROR_NONE; if (pollset->kicked_without_poller) { pollset->kicked_without_poller = false; - return GRPC_ERROR_NONE; - } - grpc_error *error = GRPC_ERROR_NONE; - if (begin_worker(pollset, &worker, worker_hdl, &now, deadline)) { + } else { + if (begin_worker(pollset, WORKER_PTR, worker_hdl, &now, deadline)) { gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); - gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker); + gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); GPR_ASSERT(!pollset->shutdown_closure); gpr_mu_unlock(&pollset->mu); if (pollset->event_cursor == pollset->event_count) { - append_error(&error, pollset_epoll(exec_ctx, pollset, worker.pollable_obj, + append_error(&error, pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, now, deadline), err_desc); } @@ -940,7 +954,11 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_tls_set(&g_current_thread_pollset, 0); gpr_tls_set(&g_current_thread_worker, 0); } - end_worker(exec_ctx, pollset, &worker, worker_hdl); + end_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl); + } +#ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP + gpr_free(worker); +#endif return error; } @@ -1262,6 +1280,8 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, a->pollset_count += b->pollset_count; gpr_free(b->fds); gpr_free(b->pollsets); + b->fds = NULL; + b->pollsets = NULL; b->fd_count = b->fd_capacity = b->pollset_count = b->pollset_capacity = 0; gpr_mu_unlock(&a->mu); gpr_mu_unlock(&b->mu); diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c index 7e271294fd..4489896ffb 100644 --- a/src/core/lib/iomgr/tcp_posix.c +++ b/src/core/lib/iomgr/tcp_posix.c @@ -188,7 +188,7 @@ static void cover_self(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { } if (old_count == 0) { GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED(exec_ctx); - p = (backup_poller *)gpr_malloc(sizeof(*p) + grpc_pollset_size()); + p = (backup_poller *)gpr_zalloc(sizeof(*p) + grpc_pollset_size()); if (GRPC_TRACER_ON(grpc_tcp_trace)) { gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p create", p); } -- cgit v1.2.3 From 3d073c261eafe3ba1d9f7fb098ee1ddd1037334a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 22:10:58 +0000 Subject: Fix kicking --- src/core/lib/iomgr/ev_epollex_linux.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 396731758e..45aee891cb 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -542,7 +542,7 @@ static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { - pollable *p = pollset->active_pollable; + pollable *p = specific_worker->pollable_obj; GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -563,6 +563,7 @@ GPR_ASSERT(specific_worker != NULL); specific_worker->kicked = true; return grpc_wakeup_fd_wakeup(&p->wakeup); } else { + GPR_ASSERT(specific_worker->initialized_cv); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); } @@ -577,20 +578,17 @@ GPR_ASSERT(specific_worker != NULL); static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { - pollable *p = pollset->active_pollable; if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, - "PS:%p kick %p tls_pollset=%p tls_worker=%p " - "root_worker=(pollset:%p pollable:%p)", - p, specific_worker, (void *)gpr_tls_get(&g_current_thread_pollset), - (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker, - p->root_worker); + "PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p", + pollset, specific_worker, (void *)gpr_tls_get(&g_current_thread_pollset), + (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker); } if (specific_worker == NULL) { if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { if (pollset->root_worker == NULL) { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_any_without_poller", p); + gpr_log(GPR_DEBUG, "PS:%p kicked_any_without_poller", pollset); } pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; @@ -599,7 +597,7 @@ static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, } } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p kicked_any_but_awake", p); + gpr_log(GPR_DEBUG, "PS:%p kicked_any_but_awake", pollset); } return GRPC_ERROR_NONE; } @@ -905,9 +903,11 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (worker->initialized_cv) { gpr_cv_destroy(&worker->cv); } - gpr_mu_unlock(&worker->pollable_obj->mu); if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET)) { + gpr_mu_unlock(&worker->pollable_obj->mu); pollset_maybe_finish_shutdown(exec_ctx, pollset); + } else { + gpr_mu_unlock(&worker->pollable_obj->mu); } POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); } -- cgit v1.2.3 From 29a9c3af38e28153c37541163f73ad6223eb4ff6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 15:15:04 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.c | 146 ++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 45aee891cb..a5ef1d89f9 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -49,7 +49,8 @@ #include "src/core/lib/support/block_annotate.h" #include "src/core/lib/support/spinlock.h" -// debug aid: create workers on the heap (allows asan to spot use-after-destruction) +// debug aid: create workers on the heap (allows asan to spot +// use-after-destruction) #define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1 #ifndef NDEBUG @@ -434,13 +435,13 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { } struct epoll_event ev; ev.events = (uint32_t)(EPOLLIN | EPOLLET); - ev.data.ptr = (void*)(1 | (intptr_t)&(*p)->wakeup); + ev.data.ptr = (void *)(1 | (intptr_t) & (*p)->wakeup); if (epoll_ctl(epfd, EPOLL_CTL_ADD, (*p)->wakeup.read_fd, &ev) != 0) { err = GRPC_OS_ERROR(errno, "epoll_ctl"); close(epfd); grpc_wakeup_fd_destroy(&(*p)->wakeup); -gpr_free(*p); -*p = NULL; + gpr_free(*p); + *p = NULL; return err; } @@ -461,7 +462,8 @@ static pollable *pollable_ref(pollable *p) { static pollable *pollable_ref(pollable *p, int line, const char *reason) { if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) { int r = (int)gpr_atm_no_barrier_load(&p->refs.count); - gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p ref %d->%d %s", p, r, r+1, reason); + gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, + "POLLABLE:%p ref %d->%d %s", p, r, r + 1, reason); } #endif gpr_ref(&p->refs); @@ -475,7 +477,8 @@ static void pollable_unref(pollable *p, int line, const char *reason) { if (p == NULL) return; if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) { int r = (int)gpr_atm_no_barrier_load(&p->refs.count); - gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p unref %d->%d %s", p, r, r-1, reason); + gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, + "POLLABLE:%p unref %d->%d %s", p, r, r - 1, reason); } #endif if (p != NULL && gpr_unref(&p->refs)) { @@ -543,7 +546,7 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { pollable *p = specific_worker->pollable_obj; -GPR_ASSERT(specific_worker != NULL); + GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); @@ -581,8 +584,10 @@ static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p", - pollset, specific_worker, (void *)gpr_tls_get(&g_current_thread_pollset), - (void *)gpr_tls_get(&g_current_thread_worker), pollset->root_worker); + pollset, specific_worker, + (void *)gpr_tls_get(&g_current_thread_pollset), + (void *)gpr_tls_get(&g_current_thread_worker), + pollset->root_worker); } if (specific_worker == NULL) { if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { @@ -621,13 +626,13 @@ static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_error *error = GRPC_ERROR_NONE; const char *err_desc = "pollset_kick_all"; gpr_mu_lock(&p->mu); -grpc_pollset_worker *w = pollset->root_worker; -if (w!=NULL) { -do { - append_error(&error, pollset_kick_one(exec_ctx, pollset, w), err_desc); - w = w->links[PWLINK_POLLSET].next; -} while (w != pollset->root_worker); -} + grpc_pollset_worker *w = pollset->root_worker; + if (w != NULL) { + do { + append_error(&error, pollset_kick_one(exec_ctx, pollset, w), err_desc); + w = w->links[PWLINK_POLLSET].next; + } while (w != pollset->root_worker); + } gpr_mu_unlock(&p->mu); return error; } @@ -690,7 +695,7 @@ static grpc_error *fd_become_pollable(grpc_fd *fd, pollable **p) { if (fd->pollable_obj == NULL) { if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj), err_desc)) { -fd->pollable_obj->owner_fd = fd; + fd->pollable_obj->owner_fd = fd; if (!append_error(&error, pollable_add_fd(fd->pollable_obj, fd), err_desc)) { POLLABLE_UNREF(fd->pollable_obj, "fd_pollable"); @@ -850,7 +855,8 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, worker->initialized_cv = false; worker->kicked = false; worker->pollset = pollset; - worker->pollable_obj = POLLABLE_REF(pollset->active_pollable, "pollset_worker"); + worker->pollable_obj = + POLLABLE_REF(pollset->active_pollable, "pollset_worker"); worker_insert(&pollset->root_worker, worker, PWLINK_POLLSET); gpr_mu_lock(&worker->pollable_obj->mu); if (!worker_insert(&worker->pollable_obj->root_worker, worker, @@ -904,10 +910,10 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_cv_destroy(&worker->cv); } if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET)) { - gpr_mu_unlock(&worker->pollable_obj->mu); + gpr_mu_unlock(&worker->pollable_obj->mu); pollset_maybe_finish_shutdown(exec_ctx, pollset); } else { - gpr_mu_unlock(&worker->pollable_obj->mu); + gpr_mu_unlock(&worker->pollable_obj->mu); } POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); } @@ -930,31 +936,33 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRId64 ".%09d deadline=%" PRId64 ".%09d kwp=%d pollable=%p", pollset, worker_hdl, WORKER_PTR, now.tv_sec, now.tv_nsec, - deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, pollset->active_pollable); + deadline.tv_sec, deadline.tv_nsec, pollset->kicked_without_poller, + pollset->active_pollable); } static const char *err_desc = "pollset_work"; grpc_error *error = GRPC_ERROR_NONE; if (pollset->kicked_without_poller) { pollset->kicked_without_poller = false; } else { - if (begin_worker(pollset, WORKER_PTR, worker_hdl, &now, deadline)) { - gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); - gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); - GPR_ASSERT(!pollset->shutdown_closure); - gpr_mu_unlock(&pollset->mu); - if (pollset->event_cursor == pollset->event_count) { - append_error(&error, pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, - now, deadline), + if (begin_worker(pollset, WORKER_PTR, worker_hdl, &now, deadline)) { + gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); + gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); + GPR_ASSERT(!pollset->shutdown_closure); + gpr_mu_unlock(&pollset->mu); + if (pollset->event_cursor == pollset->event_count) { + append_error(&error, + pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, + now, deadline), + err_desc); + } + append_error(&error, pollset_process_events(exec_ctx, pollset, false), err_desc); + grpc_exec_ctx_flush(exec_ctx); + gpr_mu_lock(&pollset->mu); + gpr_tls_set(&g_current_thread_pollset, 0); + gpr_tls_set(&g_current_thread_worker, 0); } - append_error(&error, pollset_process_events(exec_ctx, pollset, false), - err_desc); - grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&pollset->mu); - gpr_tls_set(&g_current_thread_pollset, 0); - gpr_tls_set(&g_current_thread_worker, 0); - } - end_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl); + end_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl); } #ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP gpr_free(worker); @@ -967,7 +975,8 @@ static grpc_error *pollset_transition_pollable_from_empty_to_fd_locked( static const char *err_desc = "pollset_transition_pollable_from_empty_to_fd"; grpc_error *error = GRPC_ERROR_NONE; if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p add fd %p (%d); transition pollable from empty to fd", + gpr_log(GPR_DEBUG, + "PS:%p add fd %p (%d); transition pollable from empty to fd", pollset, fd, fd->fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); @@ -982,9 +991,11 @@ static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( static const char *err_desc = "pollset_transition_pollable_from_fd_to_multi"; grpc_error *error = GRPC_ERROR_NONE; if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, - "PS:%p add fd %p (%d); transition pollable from fd %p to multipoller", - pollset, and_add_fd, and_add_fd?and_add_fd->fd:-1, pollset->active_pollable->owner_fd); + gpr_log( + GPR_DEBUG, + "PS:%p add fd %p (%d); transition pollable from fd %p to multipoller", + pollset, and_add_fd, and_add_fd ? and_add_fd->fd : -1, + pollset->active_pollable->owner_fd); } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); grpc_fd *initial_fd = pollset->active_pollable->owner_fd; @@ -1007,7 +1018,8 @@ static grpc_error *pollset_transition_pollable_from_fd_to_multi_locked( static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { grpc_error *error = GRPC_ERROR_NONE; - pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_add_fd"); + pollable *po_at_start = + POLLABLE_REF(pollset->active_pollable, "pollset_add_fd"); switch (pollset->active_pollable->type) { case PO_EMPTY: /* empty pollable --> single fd pollable */ @@ -1037,7 +1049,8 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, pollable **pollable_obj) { grpc_error *error = GRPC_ERROR_NONE; gpr_mu_lock(&pollset->mu); - pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable"); + pollable *po_at_start = + POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable"); switch (pollset->active_pollable->type) { case PO_EMPTY: POLLABLE_UNREF(pollset->active_pollable, "pollset"); @@ -1091,16 +1104,15 @@ static grpc_pollset_set *pollset_set_create(void) { return pss; } -static void pollset_set_unref(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss) { +static void pollset_set_unref(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss) { if (pss == NULL) return; if (!gpr_unref(&pss->refs)) return; pollset_set_unref(exec_ctx, pss->parent); gpr_mu_destroy(&pss->mu); - for (size_t i=0; ipollset_count; i++) { + for (size_t i = 0; i < pss->pollset_count; i++) { POLLABLE_UNREF(pss->pollsets[i], "pollset_set"); } - for (size_t i=0;ifd_count; i++) { + for (size_t i = 0; i < pss->fd_count; i++) { UNREF_BY(exec_ctx, pss->fds[i], 2, "pollset_set"); } gpr_free(pss->pollsets); @@ -1110,9 +1122,9 @@ static void pollset_set_unref(grpc_exec_ctx *exec_ctx, static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_fd"; pss = pss_lock_adam(pss); @@ -1132,9 +1144,9 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_fd *fd) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS:%p: del fd %p", pss, fd); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: del fd %p", pss, fd); + } pss = pss_lock_adam(pss); size_t i; for (i = 0; i < pss->fd_count; i++) { @@ -1153,15 +1165,15 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_pollset"; pollable *pollable_obj = NULL; if (!GRPC_LOG_IF_ERROR( err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { -GPR_ASSERT(pollable_obj==NULL); + GPR_ASSERT(pollable_obj == NULL); return; } pss = pss_lock_adam(pss); @@ -1181,9 +1193,9 @@ GPR_ASSERT(pollable_obj==NULL); static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS:%p: del pollset %p", pss, ps); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: del pollset %p", pss, ps); + } pss = pss_lock_adam(pss); size_t i; for (i = 0; i < pss->pollset_count; i++) { @@ -1216,9 +1228,9 @@ static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *a, grpc_pollset_set *b) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS: merge (%p, %p)", a, b); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS: merge (%p, %p)", a, b); + } grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_fd"; for (;;) { @@ -1250,9 +1262,9 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, if (b_size > a_size) { GPR_SWAP(grpc_pollset_set *, a, b); } - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS: parent %p to %p", b, a); - } + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS: parent %p to %p", b, a); + } gpr_ref(&a->refs); b->parent = a; append_error(&error, @@ -1320,7 +1332,7 @@ static const grpc_event_engine_vtable vtable = { pollset_add_fd, pollset_set_create, - pollset_set_unref, // destroy ==> unref 1 public ref + pollset_set_unref, // destroy ==> unref 1 public ref pollset_set_add_pollset, pollset_set_del_pollset, pollset_set_add_pollset_set, -- cgit v1.2.3 From 4fd6a41e0bf3e64ff393ce310b9439c638613301 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 22:41:13 +0000 Subject: Fix orphan behavior --- src/core/lib/iomgr/ev_epollex_linux.c | 63 ++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index a5ef1d89f9..6724e7df1f 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -130,6 +130,8 @@ struct grpc_fd { Ref/Unref by two to avoid altering the orphaned bit */ gpr_atm refst; + gpr_mu orphan_mu; + gpr_mu pollable_mu; pollable *pollable_obj; @@ -268,6 +270,7 @@ static void fd_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_iomgr_unregister_object(&fd->iomgr_object); POLLABLE_UNREF(fd->pollable_obj, "fd_pollable"); gpr_mu_destroy(&fd->pollable_mu); + gpr_mu_destroy(&fd->orphan_mu); gpr_mu_lock(&fd_freelist_mu); fd->freelist_next = fd_freelist; fd_freelist = fd; @@ -328,6 +331,7 @@ static grpc_fd *fd_create(int fd, const char *name) { } gpr_mu_init(&new_fd->pollable_mu); + gpr_mu_init(&new_fd->orphan_mu); new_fd->pollable_obj = NULL; gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1); new_fd->fd = fd; @@ -360,6 +364,8 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, bool already_closed, const char *reason) { bool is_fd_closed = already_closed; + gpr_mu_lock(&fd->orphan_mu); + fd->on_done_closure = on_done; /* If release_fd is not NULL, we should be relinquishing control of the file @@ -381,6 +387,8 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, GRPC_CLOSURE_SCHED(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE); + gpr_mu_unlock(&fd->orphan_mu); + UNREF_BY(exec_ctx, fd, 2, reason); /* Drop the reference */ } @@ -1027,9 +1035,15 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, pollset, fd); break; case PO_FD: - /* fd --> multipoller */ - error = pollset_transition_pollable_from_fd_to_multi_locked(exec_ctx, - pollset, fd); + gpr_mu_lock(&po_at_start->owner_fd->orphan_mu); + if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & 1) == 0) { + error = pollset_transition_pollable_from_empty_to_fd_locked(exec_ctx, pollset, fd); + } else { + /* fd --> multipoller */ + error = pollset_transition_pollable_from_fd_to_multi_locked(exec_ctx, + pollset, fd); + } + gpr_mu_unlock(&po_at_start->owner_fd->orphan_mu); break; case PO_MULTI: error = pollable_add_fd(pollset->active_pollable, fd); @@ -1057,8 +1071,15 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, error = pollable_create(PO_MULTI, &pollset->active_pollable); break; case PO_FD: - error = pollset_transition_pollable_from_fd_to_multi_locked( - exec_ctx, pollset, NULL); + gpr_mu_lock(&po_at_start->owner_fd->orphan_mu); + if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & 1) == 0) { + POLLABLE_UNREF(pollset->active_pollable, "pollset"); + error = pollable_create(PO_MULTI, &pollset->active_pollable); + } else { + error = pollset_transition_pollable_from_fd_to_multi_locked( + exec_ctx, pollset, NULL); + } + gpr_mu_unlock(&po_at_start->owner_fd->orphan_mu); break; case PO_MULTI: break; @@ -1212,14 +1233,23 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, gpr_mu_unlock(&pss->mu); } +// add all fds to pollables, and output a new array of unorphaned out_fds static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, size_t fd_count, pollable **pollables, size_t pollable_count, - const char *err_desc) { + const char *err_desc, grpc_fd **out_fds, size_t *out_fd_count) { grpc_error *error = GRPC_ERROR_NONE; for (size_t i = 0; i < fd_count; i++) { - for (size_t j = 0; j < pollable_count; j++) { - append_error(&error, pollable_add_fd(pollables[j], fds[i]), err_desc); + gpr_mu_lock(&fds[i]->orphan_mu); + if ((gpr_atm_no_barrier_load(&fds[i]->refst) & 1) == 0) { + gpr_mu_unlock(&fds[i]->orphan_mu); + UNREF_BY(exec_ctx, fds[i], 2, "pollset_set"); + } else { + for (size_t j = 0; j < pollable_count; j++) { + append_error(&error, pollable_add_fd(pollables[j], fds[i]), err_desc); + } + gpr_mu_unlock(&fds[i]->orphan_mu); + out_fds[(*out_fd_count)++] = fds[i]; } } return error; @@ -1267,25 +1297,26 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } gpr_ref(&a->refs); b->parent = a; + if (a->fd_capacity < a->fd_count + b->fd_count) { + a->fd_capacity = GPR_MAX(2 * a->fd_capacity, a->fd_count + b->fd_count); + a->fds = gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)); + } + size_t initial_a_fd_count = a->fd_count; + a->fd_count = 0; append_error(&error, - add_fds_to_pollables(exec_ctx, a->fds, a->fd_count, b->pollsets, - b->pollset_count, "merge_a2b"), + add_fds_to_pollables(exec_ctx, a->fds, initial_a_fd_count, b->pollsets, + b->pollset_count, "merge_a2b", a->fds, &a->fd_count), err_desc); append_error(&error, add_fds_to_pollables(exec_ctx, b->fds, b->fd_count, a->pollsets, - a->pollset_count, "merge_b2a"), + a->pollset_count, "merge_b2a", a->fds, &a->fd_count), err_desc); - if (a->fd_capacity < a->fd_count + b->fd_count) { - a->fd_capacity = GPR_MAX(2 * a->fd_capacity, a->fd_count + b->fd_count); - a->fds = gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)); - } if (a->pollset_capacity < a->pollset_count + b->pollset_count) { a->pollset_capacity = GPR_MAX(2 * a->pollset_capacity, a->pollset_count + b->pollset_count); a->pollsets = gpr_realloc(a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); } - memcpy(a->fds + a->fd_count, b->fds, b->fd_count * sizeof(*b->fds)); memcpy(a->pollsets + a->pollset_count, b->pollsets, b->pollset_count * sizeof(*b->pollsets)); a->fd_count += b->fd_count; -- cgit v1.2.3 From d8d9f57ed4d70c5c023a1ba9be2d06c3d50330cb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 16:10:23 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 6724e7df1f..3f5ff06e13 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -1036,12 +1036,14 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, break; case PO_FD: gpr_mu_lock(&po_at_start->owner_fd->orphan_mu); - if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & 1) == 0) { - error = pollset_transition_pollable_from_empty_to_fd_locked(exec_ctx, pollset, fd); + if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & + 1) == 0) { + error = pollset_transition_pollable_from_empty_to_fd_locked( + exec_ctx, pollset, fd); } else { /* fd --> multipoller */ - error = pollset_transition_pollable_from_fd_to_multi_locked(exec_ctx, - pollset, fd); + error = pollset_transition_pollable_from_fd_to_multi_locked( + exec_ctx, pollset, fd); } gpr_mu_unlock(&po_at_start->owner_fd->orphan_mu); break; @@ -1072,7 +1074,8 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, break; case PO_FD: gpr_mu_lock(&po_at_start->owner_fd->orphan_mu); - if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & 1) == 0) { + if ((gpr_atm_no_barrier_load(&pollset->active_pollable->owner_fd->refst) & + 1) == 0) { POLLABLE_UNREF(pollset->active_pollable, "pollset"); error = pollable_create(PO_MULTI, &pollset->active_pollable); } else { @@ -1237,7 +1240,8 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, size_t fd_count, pollable **pollables, size_t pollable_count, - const char *err_desc, grpc_fd **out_fds, size_t *out_fd_count) { + const char *err_desc, grpc_fd **out_fds, + size_t *out_fd_count) { grpc_error *error = GRPC_ERROR_NONE; for (size_t i = 0; i < fd_count; i++) { gpr_mu_lock(&fds[i]->orphan_mu); @@ -1303,13 +1307,13 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } size_t initial_a_fd_count = a->fd_count; a->fd_count = 0; - append_error(&error, - add_fds_to_pollables(exec_ctx, a->fds, initial_a_fd_count, b->pollsets, - b->pollset_count, "merge_a2b", a->fds, &a->fd_count), + append_error(&error, add_fds_to_pollables( + exec_ctx, a->fds, initial_a_fd_count, b->pollsets, + b->pollset_count, "merge_a2b", a->fds, &a->fd_count), err_desc); - append_error(&error, - add_fds_to_pollables(exec_ctx, b->fds, b->fd_count, a->pollsets, - a->pollset_count, "merge_b2a", a->fds, &a->fd_count), + append_error(&error, add_fds_to_pollables(exec_ctx, b->fds, b->fd_count, + a->pollsets, a->pollset_count, + "merge_b2a", a->fds, &a->fd_count), err_desc); if (a->pollset_capacity < a->pollset_count + b->pollset_count) { a->pollset_capacity = -- cgit v1.2.3 From 14ee7c308d1ff5f7b502da3b631e034e54c4d64d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 4 Oct 2017 19:34:09 -0700 Subject: Actually register tracer --- src/core/lib/iomgr/ev_epollex_linux.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.c b/src/core/lib/iomgr/ev_epollex_linux.c index 3f5ff06e13..487f9a0fec 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.c +++ b/src/core/lib/iomgr/ev_epollex_linux.c @@ -1388,7 +1388,9 @@ const grpc_event_engine_vtable *grpc_init_epollex_linux( return NULL; } +#ifndef NDEBUG grpc_register_tracer(&grpc_trace_pollable_refcount); +#endif fd_global_init(); -- cgit v1.2.3 From b7a8cace34551eef286acd761c9b8e5de1747894 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 5 Oct 2017 09:50:18 -0700 Subject: Add abseil to core, use it for InlinedVector --- .clang_complete | 2 + .gitmodules | 3 ++ BUILD | 2 + CMakeLists.txt | 40 +++++++++++++++++ Makefile | 50 +++++++++++++++++++++- WORKSPACE | 5 +++ binding.gyp | 3 ++ build.yaml | 15 +++++++ grpc.gyp | 3 ++ src/core/lib/support/memory.h | 41 ++++++++++++++++++ src/core/lib/support/vector.h | 32 ++++++++++++++ test/core/support/BUILD | 26 +++++++++++ test/core/support/vector_test.cc | 42 ++++++++++++++++++ third_party/abseil-cpp | 1 + tools/run_tests/generated/sources_and_headers.json | 19 ++++++++ tools/run_tests/generated/tests.json | 22 ++++++++++ 16 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 src/core/lib/support/vector.h create mode 100644 test/core/support/vector_test.cc create mode 160000 third_party/abseil-cpp (limited to 'src') diff --git a/.clang_complete b/.clang_complete index 1818679705..9dff19a0e5 100644 --- a/.clang_complete +++ b/.clang_complete @@ -9,3 +9,5 @@ -Ithird_party/benchmark/include -Ithird_party/zlib -Ithird_party/protobuf/src +-Ithird_party/abseil-cpp +-I diff --git a/.gitmodules b/.gitmodules index 8af0052128..d7f23ffcbd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,3 +27,6 @@ [submodule "third_party/bloaty"] path = third_party/bloaty url = https://github.com/google/bloaty.git +[submodule "third_party/abseil-cpp"] + path = third_party/abseil-cpp + url = https://github.com/abseil/abseil-cpp diff --git a/BUILD b/BUILD index 1063b74f06..5c1c1d343e 100644 --- a/BUILD +++ b/BUILD @@ -518,6 +518,7 @@ grpc_cc_library( "src/core/lib/support/block_annotate.h", "src/core/lib/support/env.h", "src/core/lib/support/memory.h", + "src/core/lib/support/vector.h", "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/spinlock.h", @@ -531,6 +532,7 @@ grpc_cc_library( public_hdrs = GPR_PUBLIC_HDRS, deps = [ "gpr_codegen", + "@com_google_absl//absl/container:inlined_vector" ], ) diff --git a/CMakeLists.txt b/CMakeLists.txt index e92e19465b..be4c8c2c00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -758,6 +758,7 @@ endif() add_dependencies(buildtests_cxx stress_test) add_dependencies(buildtests_cxx thread_manager_test) add_dependencies(buildtests_cxx thread_stress_test) +add_dependencies(buildtests_cxx vector_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx writes_per_rpc_test) endif() @@ -12649,6 +12650,45 @@ target_link_libraries(thread_stress_test ${_gRPC_GFLAGS_LIBRARIES} ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(vector_test + test/core/support/vector_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(vector_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${BORINGSSL_ROOT_DIR}/include + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(vector_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc++ + grpc + gpr_test_util + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) diff --git a/Makefile b/Makefile index 37ebe95aa0..aba7f91432 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,7 @@ CXXFLAGS += -std=c++11 ifeq ($(SYSTEM),Darwin) CXXFLAGS += -stdlib=libc++ endif -CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 +CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Ithird_party/abseil-cpp LDFLAGS += -g CPPFLAGS += $(CPPFLAGS_$(CONFIG)) @@ -1179,6 +1179,7 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test stress_test: $(BINDIR)/$(CONFIG)/stress_test thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test +vector_test: $(BINDIR)/$(CONFIG)/vector_test writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test @@ -1617,6 +1618,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/vector_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/boringssl_aes_test \ $(BINDIR)/$(CONFIG)/boringssl_asn1_test \ @@ -1737,6 +1739,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/vector_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \ $(BINDIR)/$(CONFIG)/resolver_component_test \ @@ -2151,6 +2154,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 ) $(E) "[RUN] Testing thread_stress_test" $(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 ) + $(E) "[RUN] Testing vector_test" + $(Q) $(BINDIR)/$(CONFIG)/vector_test || ( echo test vector_test failed ; exit 1 ) $(E) "[RUN] Testing writes_per_rpc_test" $(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 ) $(E) "[RUN] Testing resolver_component_tests_runner_invoker_unsecure" @@ -17138,6 +17143,49 @@ endif endif +VECTOR_TEST_SRC = \ + test/core/support/vector_test.cc \ + +VECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(VECTOR_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/vector_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/vector_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/vector_test: $(PROTOBUF_DEP) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/vector_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/support/vector_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_vector_test: $(VECTOR_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(VECTOR_TEST_OBJS:.o=.dep) +endif +endif + + WRITES_PER_RPC_TEST_SRC = \ test/cpp/performance/writes_per_rpc_test.cc \ diff --git a/WORKSPACE b/WORKSPACE index bfb3a8c903..907cef1fca 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -92,3 +92,8 @@ new_local_repository( path = "third_party/cares", build_file = "third_party/cares/cares.BUILD", ) + +local_repository( + name = "com_google_absl", + path = "third_party/abseil-cpp", +) diff --git a/binding.gyp b/binding.gyp index 6dbd0e71c3..6e3437dbd7 100644 --- a/binding.gyp +++ b/binding.gyp @@ -63,6 +63,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'ldflags': [ '-g', @@ -184,6 +185,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -193,6 +195,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' diff --git a/build.yaml b/build.yaml index fb9cd4f938..aa6a062a54 100644 --- a/build.yaml +++ b/build.yaml @@ -4683,6 +4683,20 @@ targets: - gpr_test_util - gpr timeout_seconds: 1200 +- name: vector_test + gtest: true + build: test + language: c++ + src: + - test/core/support/vector_test.cc + deps: + - grpc_test_util + - grpc++ + - grpc + - gpr_test_util + - gpr + uses: + - grpc++_test - name: writes_per_rpc_test gtest: true cpu_cost: 0.5 @@ -4863,6 +4877,7 @@ defaults: -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX global: CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 + -Ithird_party/abseil-cpp LDFLAGS: -g zlib: CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration diff --git a/grpc.gyp b/grpc.gyp index 09f9045789..4176137dc3 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -57,6 +57,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'ldflags': [ '-g', @@ -134,6 +135,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -143,6 +145,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' diff --git a/src/core/lib/support/memory.h b/src/core/lib/support/memory.h index dc3d32e1c2..6b336681db 100644 --- a/src/core/lib/support/memory.h +++ b/src/core/lib/support/memory.h @@ -21,6 +21,7 @@ #include +#include #include #include @@ -54,6 +55,46 @@ inline UniquePtr MakeUnique(Args&&... args) { return UniquePtr(New(std::forward(args)...)); } +// an allocator that uses gpr_malloc/gpr_free +template +class Allocator { + public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::false_type propagate_on_container_move_assignment; + template + struct rebind { + typedef Allocator other; + }; + typedef std::true_type is_always_equal; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + pointer allocate(std::size_t n, + std::allocator::const_pointer hint = 0) { + return static_cast(gpr_malloc(n * sizeof(T))); + } + void deallocate(T* p, std::size_t n) { gpr_free(p); } + size_t max_size() const { + return std::numeric_limits::max() / sizeof(value_type); + } + void construct(pointer p, const_reference val) { new ((void*)p) T(val); } + template + void construct(U* p, Args&&... args) { + ::new ((void*)p) U(std::forward(args)...); + } + void destroy(pointer p) { p->~T(); } + template + void destroy(U* p) { + p->~U(); + } +}; + } // namespace grpc_core #endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */ diff --git a/src/core/lib/support/vector.h b/src/core/lib/support/vector.h new file mode 100644 index 0000000000..4a7db80676 --- /dev/null +++ b/src/core/lib/support/vector.h @@ -0,0 +1,32 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_VECTOR_H +#define GRPC_CORE_LIB_SUPPORT_VECTOR_H + +#include "absl/container/inlined_vector.h" +#include "src/core/lib/support/memory.h" + +namespace grpc_core { + +template +using InlinedVector = absl::InlinedVector>; + +} // namespace grpc_core + +#endif diff --git a/test/core/support/BUILD b/test/core/support/BUILD index 096576e13c..1eadc2c466 100644 --- a/test/core/support/BUILD +++ b/test/core/support/BUILD @@ -207,3 +207,29 @@ grpc_cc_test( "//test/core/util:gpr_test_util", ], ) + +grpc_cc_test( + name = "memory_test", + srcs = ["memory_test.cc"], + language = "C++", + deps = [ + "//:grpc", + "//test/core/util:gpr_test_util", + ], + external_deps = [ + "gtest", + ], +) + +grpc_cc_test( + name = "vector_test", + srcs = ["vector_test.cc"], + language = "C++", + deps = [ + "//:grpc", + "//test/core/util:gpr_test_util", + ], + external_deps = [ + "gtest", + ], +) diff --git a/test/core/support/vector_test.cc b/test/core/support/vector_test.cc new file mode 100644 index 0000000000..aad9f3be90 --- /dev/null +++ b/test/core/support/vector_test.cc @@ -0,0 +1,42 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/support/vector.h" +#include +#include "test/core/util/test_config.h" + +namespace grpc_core { +namespace testing { + +TEST(InlinedVectorTest, CreateAndIterate) { + InlinedVector v{1, 2, 3}; + int sum = 0; + for (auto i : v) { + sum += i; + } + EXPECT_EQ(6, sum); +} + +} // namespace testing +} // namespace grpc_core + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/third_party/abseil-cpp b/third_party/abseil-cpp new file mode 160000 index 0000000000..cc4bed2d74 --- /dev/null +++ b/third_party/abseil-cpp @@ -0,0 +1 @@ +Subproject commit cc4bed2d74f7c8717e31f9579214ab52a9c9c610 diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index c46eb726c8..772ad80b87 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -4216,6 +4216,25 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc++_test", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "vector_test", + "src": [ + "test/core/support/vector_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 1fefb52f07..c3eed8a706 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -4102,6 +4102,28 @@ ], "timeout_seconds": 1200 }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "vector_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ -- cgit v1.2.3 From 513daab34b6761986237f81793be7627e1fcf77a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 6 Oct 2017 09:18:34 -0700 Subject: C++ification --- src/core/lib/iomgr/ev_epollex_linux.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 1eddcef870..93f9d2feff 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -51,7 +51,7 @@ // debug aid: create workers on the heap (allows asan to spot // use-after-destruction) -#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1 +//#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1 #ifndef NDEBUG grpc_tracer_flag grpc_trace_pollable_refcount = @@ -433,7 +433,7 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { if (epfd == -1) { return GRPC_OS_ERROR(errno, "epoll_create1"); } - *p = gpr_malloc(sizeof(**p)); + *p = (pollable *)gpr_malloc(sizeof(**p)); grpc_error *err = grpc_wakeup_fd_init(&(*p)->wakeup); if (err != GRPC_ERROR_NONE) { close(epfd); @@ -934,7 +934,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker **worker_hdl, gpr_timespec now, gpr_timespec deadline) { #ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP - grpc_pollset_worker *worker = gpr_malloc(sizeof(*worker)); + grpc_pollset_worker *worker = + (grpc_pollset_worker *)gpr_malloc(sizeof(*worker)); #define WORKER_PTR (worker) #else grpc_pollset_worker worker; @@ -1157,7 +1158,8 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, } if (pss->fd_count == pss->fd_capacity) { pss->fd_capacity = GPR_MAX(pss->fd_capacity * 2, 8); - pss->fds = gpr_realloc(pss->fds, pss->fd_capacity * sizeof(*pss->fds)); + pss->fds = + (grpc_fd **)gpr_realloc(pss->fds, pss->fd_capacity * sizeof(*pss->fds)); } REF_BY(fd, 2, "pollset_set"); pss->fds[pss->fd_count++] = fd; @@ -1206,8 +1208,8 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, } if (pss->pollset_count == pss->pollset_capacity) { pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); - pss->pollsets = gpr_realloc(pss->pollsets, - pss->pollset_capacity * sizeof(*pss->pollsets)); + pss->pollsets = (pollable **)gpr_realloc( + pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets)); } pss->pollsets[pss->pollset_count++] = pollable_obj; gpr_mu_unlock(&pss->mu); @@ -1303,7 +1305,7 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, b->parent = a; if (a->fd_capacity < a->fd_count + b->fd_count) { a->fd_capacity = GPR_MAX(2 * a->fd_capacity, a->fd_count + b->fd_count); - a->fds = gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)); + a->fds = (grpc_fd **)gpr_realloc(a->fds, a->fd_capacity * sizeof(*a->fds)); } size_t initial_a_fd_count = a->fd_count; a->fd_count = 0; @@ -1318,8 +1320,8 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, if (a->pollset_capacity < a->pollset_count + b->pollset_count) { a->pollset_capacity = GPR_MAX(2 * a->pollset_capacity, a->pollset_count + b->pollset_count); - a->pollsets = - gpr_realloc(a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); + a->pollsets = (pollable **)gpr_realloc( + a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); } memcpy(a->pollsets + a->pollset_count, b->pollsets, b->pollset_count * sizeof(*b->pollsets)); -- cgit v1.2.3 From 00c207610bdcb7b34701115a4799c081294f8e3b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 8 Oct 2017 21:50:33 -0700 Subject: Have BDP estimator schedule timers --- .../transport/chttp2/transport/chttp2_transport.cc | 44 +++++++++++++++++++++- .../ext/transport/chttp2/transport/flow_control.cc | 2 - src/core/ext/transport/chttp2/transport/internal.h | 6 ++- src/core/lib/transport/bdp_estimator.cc | 5 +-- src/core/lib/transport/bdp_estimator.h | 18 +-------- 5 files changed, 51 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 0ef06ae6e0..97ac59fa86 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -152,10 +152,14 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); +static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error); static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error); +static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx, + void *tp, grpc_error *error); static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); @@ -305,6 +309,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_combiner_scheduler(t->combiner)); GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, grpc_combiner_scheduler(t->combiner)); + GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked, + next_bdp_ping_timer_expired_locked, t, + grpc_combiner_scheduler(t->combiner)); GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked, t, grpc_combiner_scheduler(t->combiner)); GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked, @@ -564,6 +571,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; } + schedule_bdp_ping_locked(exec_ctx, t); + grpc_chttp2_act_on_flowctl_action( exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t, @@ -619,6 +628,9 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, if (t->ping_state.is_delayed_ping_timer_set) { grpc_timer_cancel(exec_ctx, &t->ping_state.delayed_ping_timer); } + if (t->have_next_bdp_ping_timer) { + grpc_timer_cancel(exec_ctx, &t->next_bdp_ping_timer); + } switch (t->keepalive_state) { case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING: grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); @@ -2434,12 +2446,14 @@ void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS); } } +#if 0 if (action.need_ping) { GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); t->flow_control.bdp_estimator->SchedulePing(); send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked); } +#endif } static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, @@ -2560,6 +2574,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action_locked", 0); } +static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); + t->flow_control.bdp_estimator->SchedulePing(); + send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked, + &t->finish_bdp_ping_locked); +} + static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; @@ -2579,9 +2601,27 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, if (GRPC_TRACER_ON(grpc_http_trace)) { gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string); } - t->flow_control.bdp_estimator->CompletePing(exec_ctx); + if (error == GRPC_ERROR_CANCELLED) { + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); + return; + } + grpc_millis next_ping = t->flow_control.bdp_estimator->CompletePing(exec_ctx); + GPR_ASSERT(!t->have_next_bdp_ping_timer); + t->have_next_bdp_ping_timer = true; + grpc_timer_init(exec_ctx, &t->next_bdp_ping_timer, next_ping, + &t->next_bdp_ping_timer_expired_locked); +} - GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); +static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx, + void *tp, grpc_error *error) { + grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; + GPR_ASSERT(t->have_next_bdp_ping_timer); + t->have_next_bdp_ping_timer = false; + if (error == GRPC_ERROR_CANCELLED) { + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); + return; + } + schedule_bdp_ping_locked(exec_ctx, t); } void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args, diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 60c43d840a..d0e80c4bd5 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -459,8 +459,6 @@ grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( } } if (tfc->enable_bdp_probe) { - action.need_ping = tfc->bdp_estimator->NeedPing(exec_ctx); - // get bdp estimate and update initial_window accordingly. int64_t estimate = -1; if (tfc->bdp_estimator->EstimateBdp(&estimate)) { diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 05b677dd4b..b4eb033a47 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -422,6 +422,7 @@ struct grpc_chttp2_transport { grpc_chttp2_write_cb *write_cb_pool; /* bdp estimator */ + grpc_closure next_bdp_ping_timer_expired_locked; grpc_closure start_bdp_ping_locked; grpc_closure finish_bdp_ping_locked; @@ -442,6 +443,10 @@ struct grpc_chttp2_transport { /** destructive cleanup closure */ grpc_closure destructive_reclaimer_locked; + /* next bdp ping timer */ + bool have_next_bdp_ping_timer; + grpc_timer next_bdp_ping_timer; + /* keep-alive ping support */ /** Closure to initialize a keepalive ping */ grpc_closure init_keepalive_ping_locked; @@ -749,7 +754,6 @@ typedef struct { grpc_chttp2_flowctl_urgency send_setting_update; uint32_t initial_window_size; uint32_t max_frame_size; - bool need_ping; } grpc_chttp2_flowctl_action; // Reads the flow control data and returns and actionable struct that will tell diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc index 2a1c97c84e..f1597014b1 100644 --- a/src/core/lib/transport/bdp_estimator.cc +++ b/src/core/lib/transport/bdp_estimator.cc @@ -33,13 +33,12 @@ BdpEstimator::BdpEstimator(const char *name) accumulator_(0), estimate_(65536), ping_start_time_(gpr_time_0(GPR_CLOCK_MONOTONIC)), - next_ping_scheduled_(0), inter_ping_delay_(100.0), // start at 100ms stable_estimate_count_(0), bw_est_(0), name_(name) {} -void BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) { +grpc_millis BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) { gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec dt_ts = gpr_time_sub(now, ping_start_time_); double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec; @@ -79,7 +78,7 @@ void BdpEstimator::CompletePing(grpc_exec_ctx *exec_ctx) { } ping_state_ = PingState::UNSCHEDULED; accumulator_ = 0; - next_ping_scheduled_ = grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_; + return grpc_exec_ctx_now(exec_ctx) + inter_ping_delay_; } } // namespace grpc_core diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h index a4acf30ded..cda37f35a4 100644 --- a/src/core/lib/transport/bdp_estimator.h +++ b/src/core/lib/transport/bdp_estimator.h @@ -49,18 +49,6 @@ class BdpEstimator { void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; } - // Returns true if the user should schedule a ping - bool NeedPing(grpc_exec_ctx *exec_ctx) const { - switch (ping_state_) { - case PingState::UNSCHEDULED: - return grpc_exec_ctx_now(exec_ctx) >= next_ping_scheduled_; - case PingState::SCHEDULED: - case PingState::STARTED: - return false; - } - GPR_UNREACHABLE_CODE(return false); - } - // Schedule a ping: call in response to receiving a true from // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a // transport (but not necessarily started) @@ -88,8 +76,8 @@ class BdpEstimator { ping_start_time_ = gpr_now(GPR_CLOCK_MONOTONIC); } - // Completes a previously started ping - void CompletePing(grpc_exec_ctx *exec_ctx); + // Completes a previously started ping, returns when to schedule the next one + grpc_millis CompletePing(grpc_exec_ctx *exec_ctx) GRPC_MUST_USE_RESULT; private: enum class PingState { UNSCHEDULED, SCHEDULED, STARTED }; @@ -99,8 +87,6 @@ class BdpEstimator { int64_t estimate_; // when was the current ping started? gpr_timespec ping_start_time_; - // when should the next ping start? - grpc_millis next_ping_scheduled_; int inter_ping_delay_; int stable_estimate_count_; double bw_est_; -- cgit v1.2.3 From 5a408d8b1871d4ae2bc75d58c7288544d0925f39 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 8 Oct 2017 22:03:07 -0700 Subject: Remove #if 0 --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 97ac59fa86..f6f9242caf 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -2446,14 +2446,6 @@ void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS); } } -#if 0 - if (action.need_ping) { - GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); - t->flow_control.bdp_estimator->SchedulePing(); - send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked, - &t->finish_bdp_ping_locked); - } -#endif } static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, -- cgit v1.2.3 From 6f41ad760be147c93f9c4eab087a0f0aef8a7e32 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 08:31:19 -0700 Subject: Fix test --- src/core/lib/transport/bdp_estimator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h index cda37f35a4..f956b6d000 100644 --- a/src/core/lib/transport/bdp_estimator.h +++ b/src/core/lib/transport/bdp_estimator.h @@ -77,7 +77,7 @@ class BdpEstimator { } // Completes a previously started ping, returns when to schedule the next one - grpc_millis CompletePing(grpc_exec_ctx *exec_ctx) GRPC_MUST_USE_RESULT; + grpc_millis CompletePing(grpc_exec_ctx *exec_ctx); private: enum class PingState { UNSCHEDULED, SCHEDULED, STARTED }; -- cgit v1.2.3 From 247b23114d4782d9e6b2d3f4410f76fb85b31fb4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 09:16:19 -0700 Subject: C++ize PidController --- CMakeLists.txt | 140 +++++++++-------- Makefile | 168 ++++++++++++--------- build.yaml | 42 +++--- .../ext/transport/chttp2/transport/flow_control.cc | 23 ++- src/core/ext/transport/chttp2/transport/internal.h | 2 +- src/core/lib/transport/pid_controller.cc | 53 +++---- src/core/lib/transport/pid_controller.h | 112 +++++++++----- test/core/transport/BUILD | 5 +- test/core/transport/bdp_estimator_test.cc | 1 + test/core/transport/pid_controller_test.c | 78 ---------- test/core/transport/pid_controller_test.cc | 91 +++++++++++ tools/run_tests/generated/sources_and_headers.json | 70 ++++----- tools/run_tests/generated/tests.json | 88 +++++------ 13 files changed, 482 insertions(+), 391 deletions(-) delete mode 100644 test/core/transport/pid_controller_test.c create mode 100644 test/core/transport/pid_controller_test.cc (limited to 'src') diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b2774b796..78930832f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -542,8 +542,6 @@ add_dependencies(buildtests_c timeout_encoding_test) add_dependencies(buildtests_c timer_heap_test) add_dependencies(buildtests_c timer_list_test) add_dependencies(buildtests_c transport_connectivity_state_test) -add_dependencies(buildtests_c transport_metadata_test) -add_dependencies(buildtests_c transport_pid_controller_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_c transport_security_test) endif() @@ -758,6 +756,8 @@ endif() add_dependencies(buildtests_cxx stress_test) add_dependencies(buildtests_cxx thread_manager_test) add_dependencies(buildtests_cxx thread_stress_test) +add_dependencies(buildtests_cxx transport_metadata_test) +add_dependencies(buildtests_cxx transport_pid_controller_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx writes_per_rpc_test) endif() @@ -8946,64 +8946,6 @@ target_link_libraries(transport_connectivity_state_test gpr ) -endif (gRPC_BUILD_TESTS) -if (gRPC_BUILD_TESTS) - -add_executable(transport_metadata_test - test/core/transport/metadata_test.c -) - - -target_include_directories(transport_metadata_test - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include - PRIVATE ${BORINGSSL_ROOT_DIR}/include - PRIVATE ${PROTOBUF_ROOT_DIR}/src - PRIVATE ${BENCHMARK_ROOT_DIR}/include - PRIVATE ${ZLIB_ROOT_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib - PRIVATE ${CARES_INCLUDE_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include -) - -target_link_libraries(transport_metadata_test - ${_gRPC_ALLTARGETS_LIBRARIES} - grpc_test_util - grpc - gpr_test_util - gpr -) - -endif (gRPC_BUILD_TESTS) -if (gRPC_BUILD_TESTS) - -add_executable(transport_pid_controller_test - test/core/transport/pid_controller_test.c -) - - -target_include_directories(transport_pid_controller_test - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include - PRIVATE ${BORINGSSL_ROOT_DIR}/include - PRIVATE ${PROTOBUF_ROOT_DIR}/src - PRIVATE ${BENCHMARK_ROOT_DIR}/include - PRIVATE ${ZLIB_ROOT_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib - PRIVATE ${CARES_INCLUDE_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include -) - -target_link_libraries(transport_pid_controller_test - ${_gRPC_ALLTARGETS_LIBRARIES} - grpc_test_util - grpc - gpr_test_util - gpr -) - endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) @@ -12667,6 +12609,84 @@ target_link_libraries(thread_stress_test ${_gRPC_GFLAGS_LIBRARIES} ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(transport_metadata_test + test/core/transport/metadata_test.c + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(transport_metadata_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${BORINGSSL_ROOT_DIR}/include + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(transport_metadata_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr_test_util + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(transport_pid_controller_test + test/core/transport/pid_controller_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(transport_pid_controller_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${BORINGSSL_ROOT_DIR}/include + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(transport_pid_controller_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_util + grpc++ + grpc_test_util + grpc + gpr_test_util + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) diff --git a/Makefile b/Makefile index d4500bbbbd..6981ae1e7f 100644 --- a/Makefile +++ b/Makefile @@ -1090,8 +1090,6 @@ timeout_encoding_test: $(BINDIR)/$(CONFIG)/timeout_encoding_test timer_heap_test: $(BINDIR)/$(CONFIG)/timer_heap_test timer_list_test: $(BINDIR)/$(CONFIG)/timer_list_test transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_test -transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test -transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test @@ -1179,6 +1177,8 @@ streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test stress_test: $(BINDIR)/$(CONFIG)/stress_test thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test +transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test +transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test @@ -1471,8 +1471,6 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/timer_heap_test \ $(BINDIR)/$(CONFIG)/timer_list_test \ $(BINDIR)/$(CONFIG)/transport_connectivity_state_test \ - $(BINDIR)/$(CONFIG)/transport_metadata_test \ - $(BINDIR)/$(CONFIG)/transport_pid_controller_test \ $(BINDIR)/$(CONFIG)/transport_security_test \ $(BINDIR)/$(CONFIG)/udp_server_test \ $(BINDIR)/$(CONFIG)/uri_parser_test \ @@ -1617,6 +1615,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/transport_metadata_test \ + $(BINDIR)/$(CONFIG)/transport_pid_controller_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/boringssl_aes_test \ $(BINDIR)/$(CONFIG)/boringssl_asn1_test \ @@ -1738,6 +1738,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/stress_test \ $(BINDIR)/$(CONFIG)/thread_manager_test \ $(BINDIR)/$(CONFIG)/thread_stress_test \ + $(BINDIR)/$(CONFIG)/transport_metadata_test \ + $(BINDIR)/$(CONFIG)/transport_pid_controller_test \ $(BINDIR)/$(CONFIG)/writes_per_rpc_test \ $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \ $(BINDIR)/$(CONFIG)/resolver_component_test \ @@ -1988,10 +1990,6 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/timer_list_test || ( echo test timer_list_test failed ; exit 1 ) $(E) "[RUN] Testing transport_connectivity_state_test" $(Q) $(BINDIR)/$(CONFIG)/transport_connectivity_state_test || ( echo test transport_connectivity_state_test failed ; exit 1 ) - $(E) "[RUN] Testing transport_metadata_test" - $(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 ) - $(E) "[RUN] Testing transport_pid_controller_test" - $(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 ) $(E) "[RUN] Testing transport_security_test" $(Q) $(BINDIR)/$(CONFIG)/transport_security_test || ( echo test transport_security_test failed ; exit 1 ) $(E) "[RUN] Testing udp_server_test" @@ -2152,6 +2150,10 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/thread_manager_test || ( echo test thread_manager_test failed ; exit 1 ) $(E) "[RUN] Testing thread_stress_test" $(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 ) + $(E) "[RUN] Testing transport_metadata_test" + $(Q) $(BINDIR)/$(CONFIG)/transport_metadata_test || ( echo test transport_metadata_test failed ; exit 1 ) + $(E) "[RUN] Testing transport_pid_controller_test" + $(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 ) $(E) "[RUN] Testing writes_per_rpc_test" $(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 ) $(E) "[RUN] Testing resolver_component_tests_runner_invoker_unsecure" @@ -13384,70 +13386,6 @@ endif endif -TRANSPORT_METADATA_TEST_SRC = \ - test/core/transport/metadata_test.c \ - -TRANSPORT_METADATA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_METADATA_TEST_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/transport_metadata_test: openssl_dep_error - -else - - - -$(BINDIR)/$(CONFIG)/transport_metadata_test: $(TRANSPORT_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LD) $(LDFLAGS) $(TRANSPORT_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/transport_metadata_test - -endif - -$(OBJDIR)/$(CONFIG)/test/core/transport/metadata_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - -deps_transport_metadata_test: $(TRANSPORT_METADATA_TEST_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(TRANSPORT_METADATA_TEST_OBJS:.o=.dep) -endif -endif - - -TRANSPORT_PID_CONTROLLER_TEST_SRC = \ - test/core/transport/pid_controller_test.c \ - -TRANSPORT_PID_CONTROLLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_PID_CONTROLLER_TEST_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/transport_pid_controller_test: openssl_dep_error - -else - - - -$(BINDIR)/$(CONFIG)/transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LD) $(LDFLAGS) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/transport_pid_controller_test - -endif - -$(OBJDIR)/$(CONFIG)/test/core/transport/pid_controller_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - -deps_transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep) -endif -endif - - TRANSPORT_SECURITY_TEST_SRC = \ test/core/tsi/transport_security_test.c \ @@ -17155,6 +17093,92 @@ endif endif +TRANSPORT_METADATA_TEST_SRC = \ + test/core/transport/metadata_test.c \ + +TRANSPORT_METADATA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_METADATA_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/transport_metadata_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/transport_metadata_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/transport_metadata_test: $(PROTOBUF_DEP) $(TRANSPORT_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(TRANSPORT_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/transport_metadata_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/transport/metadata_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_transport_metadata_test: $(TRANSPORT_METADATA_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(TRANSPORT_METADATA_TEST_OBJS:.o=.dep) +endif +endif + + +TRANSPORT_PID_CONTROLLER_TEST_SRC = \ + test/core/transport/pid_controller_test.cc \ + +TRANSPORT_PID_CONTROLLER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TRANSPORT_PID_CONTROLLER_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/transport_pid_controller_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/transport_pid_controller_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/transport_pid_controller_test: $(PROTOBUF_DEP) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(TRANSPORT_PID_CONTROLLER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/transport_pid_controller_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/transport/pid_controller_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_transport_pid_controller_test: $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(TRANSPORT_PID_CONTROLLER_TEST_OBJS:.o=.dep) +endif +endif + + WRITES_PER_RPC_TEST_SRC = \ test/cpp/performance/writes_per_rpc_test.cc \ diff --git a/build.yaml b/build.yaml index 4eaaf6a035..a6550605d8 100644 --- a/build.yaml +++ b/build.yaml @@ -3322,26 +3322,6 @@ targets: - grpc - gpr_test_util - gpr -- name: transport_metadata_test - build: test - language: c - src: - - test/core/transport/metadata_test.c - deps: - - grpc_test_util - - grpc - - gpr_test_util - - gpr -- name: transport_pid_controller_test - build: test - language: c - src: - - test/core/transport/pid_controller_test.c - deps: - - grpc_test_util - - grpc - - gpr_test_util - - gpr - name: transport_security_test build: test language: c @@ -4689,6 +4669,28 @@ targets: - gpr_test_util - gpr timeout_seconds: 1200 +- name: transport_metadata_test + build: test + language: c++ + src: + - test/core/transport/metadata_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr +- name: transport_pid_controller_test + build: test + language: c++ + src: + - test/core/transport/pid_controller_test.cc + deps: + - grpc++_test_util + - grpc++ + - grpc_test_util + - grpc + - gpr_test_util + - gpr - name: writes_per_rpc_test gtest: true cpu_cost: 0.5 diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index d0e80c4bd5..716cd71490 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -399,22 +399,19 @@ static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx, if (!tfc->pid_controller_initialized) { tfc->last_pid_update = now; tfc->pid_controller_initialized = true; - grpc_pid_controller_args args; - memset(&args, 0, sizeof(args)); - args.gain_p = 4; - args.gain_i = 8; - args.gain_d = 0; - args.initial_control_value = target; - args.min_control_value = -1; - args.max_control_value = 25; - args.integral_range = 10; - grpc_pid_controller_init(&tfc->pid_controller, args); + tfc->pid_controller.Init(grpc_core::PidController::Args() + .set_gain_p(4) + .set_gain_i(8) + .set_gain_d(0) + .set_initial_control_value(target) + .set_min_control_value(-1) + .set_max_control_value(25) + .set_integral_range(10)); return pow(2, target); } - double bdp_error = target - grpc_pid_controller_last(&tfc->pid_controller); + double bdp_error = target - tfc->pid_controller->last_control_value(); double dt = (double)(now - tfc->last_pid_update) * 1e-3; - double log2_bdp_guess = - grpc_pid_controller_update(&tfc->pid_controller, bdp_error, dt); + double log2_bdp_guess = tfc->pid_controller->Update(bdp_error, dt); tfc->last_pid_update = now; return pow(2, log2_bdp_guess); } diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index b4eb033a47..f0a75dfb45 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -273,7 +273,7 @@ typedef struct { /* pid controller */ bool pid_controller_initialized; - grpc_pid_controller pid_controller; + grpc_core::ManualConstructor pid_controller; grpc_millis last_pid_update; // pointer back to transport for tracing diff --git a/src/core/lib/transport/pid_controller.cc b/src/core/lib/transport/pid_controller.cc index 4b304f17b2..9f7750d693 100644 --- a/src/core/lib/transport/pid_controller.cc +++ b/src/core/lib/transport/pid_controller.cc @@ -19,45 +19,30 @@ #include "src/core/lib/transport/pid_controller.h" #include -void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - grpc_pid_controller_args args) { - pid_controller->args = args; - pid_controller->last_control_value = args.initial_control_value; - grpc_pid_controller_reset(pid_controller); -} +namespace grpc_core { -void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) { - pid_controller->last_error = 0.0; - pid_controller->last_dc_dt = 0.0; - pid_controller->error_integral = 0.0; -} +PidController::PidController(const Args &args) + : last_control_value_(args.initial_control_value()), args_(args) {} -double grpc_pid_controller_update(grpc_pid_controller *pid_controller, - double error, double dt) { - if (dt == 0) return pid_controller->last_control_value; +double PidController::Update(double error, double dt) { + if (dt <= 0) return last_control_value_; /* integrate error using the trapezoid rule */ - pid_controller->error_integral += - dt * (pid_controller->last_error + error) * 0.5; - pid_controller->error_integral = GPR_CLAMP( - pid_controller->error_integral, -pid_controller->args.integral_range, - pid_controller->args.integral_range); - double diff_error = (error - pid_controller->last_error) / dt; + error_integral_ += dt * (last_error_ + error) * 0.5; + error_integral_ = GPR_CLAMP(error_integral_, -args_.integral_range(), + args_.integral_range()); + double diff_error = (error - last_error_) / dt; /* calculate derivative of control value vs time */ - double dc_dt = pid_controller->args.gain_p * error + - pid_controller->args.gain_i * pid_controller->error_integral + - pid_controller->args.gain_d * diff_error; + double dc_dt = args_.gain_p() * error + args_.gain_i() * error_integral_ + + args_.gain_d() * diff_error; /* and perform trapezoidal integration */ - double new_control_value = pid_controller->last_control_value + - dt * (pid_controller->last_dc_dt + dc_dt) * 0.5; - new_control_value = - GPR_CLAMP(new_control_value, pid_controller->args.min_control_value, - pid_controller->args.max_control_value); - pid_controller->last_error = error; - pid_controller->last_dc_dt = dc_dt; - pid_controller->last_control_value = new_control_value; + double new_control_value = + last_control_value_ + dt * (last_dc_dt_ + dc_dt) * 0.5; + new_control_value = GPR_CLAMP(new_control_value, args_.min_control_value(), + args_.max_control_value()); + last_error_ = error; + last_dc_dt_ = dc_dt; + last_control_value_ = new_control_value; return new_control_value; } -double grpc_pid_controller_last(grpc_pid_controller *pid_controller) { - return pid_controller->last_control_value; -} +} // namespace grpc_core diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h index 17feabfd39..87e59a1a90 100644 --- a/src/core/lib/transport/pid_controller.h +++ b/src/core/lib/transport/pid_controller.h @@ -19,9 +19,7 @@ #ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H #define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H -#ifdef __cplusplus -extern "C" { -#endif +#include /* \file Simple PID controller. Implements a proportional-integral-derivative controller. @@ -30,41 +28,87 @@ extern "C" { Gains can be set to adjust sensitivity to current error (p), the integral of error (i), and the derivative of error (d). */ -typedef struct { - double gain_p; - double gain_i; - double gain_d; - double initial_control_value; - double min_control_value; - double max_control_value; - double integral_range; -} grpc_pid_controller_args; +namespace grpc_core { -typedef struct { - double last_error; - double error_integral; - double last_control_value; - double last_dc_dt; - grpc_pid_controller_args args; -} grpc_pid_controller; +class PidController { + public: + class Args { + public: + double gain_p() const { return gain_p_; } + double gain_i() const { return gain_i_; } + double gain_d() const { return gain_d_; } + double initial_control_value() const { return initial_control_value_; } + double min_control_value() const { return min_control_value_; } + double max_control_value() const { return max_control_value_; } + double integral_range() const { return integral_range_; } -/** Initialize the controller */ -void grpc_pid_controller_init(grpc_pid_controller *pid_controller, - grpc_pid_controller_args args); + Args& set_gain_p(double gain_p) { + gain_p_ = gain_p; + return *this; + } + Args& set_gain_i(double gain_i) { + gain_i_ = gain_i; + return *this; + } + Args& set_gain_d(double gain_d) { + gain_d_ = gain_d; + return *this; + } + Args& set_initial_control_value(double initial_control_value) { + initial_control_value_ = initial_control_value; + return *this; + } + Args& set_min_control_value(double min_control_value) { + min_control_value_ = min_control_value; + return *this; + } + Args& set_max_control_value(double max_control_value) { + max_control_value_ = max_control_value; + return *this; + } + Args& set_integral_range(double integral_range) { + integral_range_ = integral_range; + return *this; + } -/** Reset the controller: useful when things have changed significantly */ -void grpc_pid_controller_reset(grpc_pid_controller *pid_controller); + private: + double gain_p_ = 0.0; + double gain_i_ = 0.0; + double gain_d_ = 0.0; + double initial_control_value_ = 0.0; + double min_control_value_ = std::numeric_limits::min(); + double max_control_value_ = std::numeric_limits::max(); + double integral_range_ = std::numeric_limits::max(); + }; -/** Update the controller: given a current error estimate, and the time since - the last update, returns a new control value */ -double grpc_pid_controller_update(grpc_pid_controller *pid_controller, - double error, double dt); + explicit PidController(const Args& args); -/** Returns the last control value calculated */ -double grpc_pid_controller_last(grpc_pid_controller *pid_controller); + /// Reset the controller internal state: useful when the environment has + /// changed significantly + void Reset() { + last_error_ = 0.0; + last_dc_dt_ = 0.0; + error_integral_ = 0.0; + } -#ifdef __cplusplus -} -#endif + /// Update the controller: given a current error estimate, and the time since + /// the last update, returns a new control value + double Update(double error, double dt); -#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */ \ No newline at end of file + /// Returns the last control value calculated + double last_control_value() const { return last_control_value_; } + + /// Returns the current error integral (mostly for testing) + double error_integral() const { return error_integral_; } + + private: + double last_error_ = 0.0; + double error_integral_ = 0.0; + double last_control_value_; + double last_dc_dt_ = 0.0; + const Args args_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */ diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD index ea5e577bd8..141381b6bd 100644 --- a/test/core/transport/BUILD +++ b/test/core/transport/BUILD @@ -71,7 +71,7 @@ grpc_cc_test( grpc_cc_test( name = "pid_controller_test", - srcs = ["pid_controller_test.c"], + srcs = ["pid_controller_test.cc"], language = "C", deps = [ "//:gpr", @@ -79,6 +79,9 @@ grpc_cc_test( "//test/core/util:gpr_test_util", "//test/core/util:grpc_test_util", ], + external_deps = [ + "gtest", + ], ) grpc_cc_test( diff --git a/test/core/transport/bdp_estimator_test.cc b/test/core/transport/bdp_estimator_test.cc index 56907b4e6a..a4a86f5b51 100644 --- a/test/core/transport/bdp_estimator_test.cc +++ b/test/core/transport/bdp_estimator_test.cc @@ -141,6 +141,7 @@ TEST_P(BdpEstimatorRandomTest, GetEstimateRandomValues) { INSTANTIATE_TEST_CASE_P(TooManyNames, BdpEstimatorRandomTest, ::testing::Values(3, 4, 6, 9, 13, 19, 28, 42, 63, 94, 141, 211, 316, 474, 711)); + } // namespace testing } // namespace grpc_core diff --git a/test/core/transport/pid_controller_test.c b/test/core/transport/pid_controller_test.c deleted file mode 100644 index 831c4b41ce..0000000000 --- a/test/core/transport/pid_controller_test.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "src/core/lib/transport/pid_controller.h" - -#include -#include - -#include -#include -#include -#include -#include "src/core/lib/support/string.h" -#include "test/core/util/test_config.h" - -static void test_noop(void) { - gpr_log(GPR_INFO, "test_noop"); - grpc_pid_controller pid; - grpc_pid_controller_init( - &pid, (grpc_pid_controller_args){.gain_p = 1, - .gain_i = 1, - .gain_d = 1, - .initial_control_value = 1, - .min_control_value = DBL_MIN, - .max_control_value = DBL_MAX, - .integral_range = DBL_MAX}); -} - -static void test_simple_convergence(double gain_p, double gain_i, double gain_d, - double dt, double set_point, double start) { - gpr_log(GPR_INFO, - "test_simple_convergence(p=%lf, i=%lf, d=%lf); dt=%lf set_point=%lf " - "start=%lf", - gain_p, gain_i, gain_d, dt, set_point, start); - grpc_pid_controller pid; - grpc_pid_controller_init( - &pid, (grpc_pid_controller_args){.gain_p = gain_p, - .gain_i = gain_i, - .gain_d = gain_d, - .initial_control_value = start, - .min_control_value = DBL_MIN, - .max_control_value = DBL_MAX, - .integral_range = DBL_MAX}); - - for (int i = 0; i < 100000; i++) { - grpc_pid_controller_update(&pid, set_point - grpc_pid_controller_last(&pid), - 1); - } - - GPR_ASSERT(fabs(set_point - grpc_pid_controller_last(&pid)) < 0.1); - if (gain_i > 0) { - GPR_ASSERT(fabs(pid.error_integral) < 0.1); - } -} - -int main(int argc, char **argv) { - grpc_test_init(argc, argv); - test_noop(); - test_simple_convergence(0.2, 0, 0, 1, 100, 0); - test_simple_convergence(0.2, 0.1, 0, 1, 100, 0); - test_simple_convergence(0.2, 0.1, 0.1, 1, 100, 0); - return 0; -} diff --git a/test/core/transport/pid_controller_test.cc b/test/core/transport/pid_controller_test.cc new file mode 100644 index 0000000000..081d03472a --- /dev/null +++ b/test/core/transport/pid_controller_test.cc @@ -0,0 +1,91 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "src/core/lib/transport/pid_controller.h" + +#include +#include + +#include +#include +#include +#include +#include +#include "src/core/lib/support/string.h" +#include "test/core/util/test_config.h" + +namespace grpc_core { +namespace testing { + +TEST(PidController, NoOp) { + PidController pid(PidController::Args() + .set_gain_p(1) + .set_gain_i(1) + .set_gain_d(1) + .set_initial_control_value(1)); +} + +struct SimpleConvergenceTestArgs { + double gain_p; + double gain_i; + double gain_d; + double dt; + double set_point; + double start; +}; + +std::ostream& operator<<(std::ostream& out, SimpleConvergenceTestArgs args) { + return out << "gain_p:" << args.gain_p << " gain_i:" << args.gain_i + << " gain_d:" << args.gain_d << " dt:" << args.dt + << " set_point:" << args.set_point << " start:" << args.start; +} + +class SimpleConvergenceTest + : public ::testing::TestWithParam {}; + +TEST_P(SimpleConvergenceTest, Converges) { + PidController pid(PidController::Args() + .set_gain_p(GetParam().gain_p) + .set_gain_i(GetParam().gain_i) + .set_gain_d(GetParam().gain_d) + .set_initial_control_value(GetParam().start)); + + for (int i = 0; i < 100000; i++) { + pid.Update(GetParam().set_point - pid.last_control_value(), GetParam().dt); + } + + EXPECT_LT(fabs(GetParam().set_point - pid.last_control_value()), 0.1); + if (GetParam().gain_i > 0) { + EXPECT_LT(fabs(pid.error_integral()), 0.1); + } +} + +INSTANTIATE_TEST_CASE_P( + X, SimpleConvergenceTest, + ::testing::Values(SimpleConvergenceTestArgs{0.2, 0, 0, 1, 100, 0}, + SimpleConvergenceTestArgs{0.2, 0.1, 0, 1, 100, 0}, + SimpleConvergenceTestArgs{0.2, 0.1, 0.1, 1, 100, 0})); + +} // namespace testing +} // namespace grpc_core + +int main(int argc, char** argv) { + grpc_test_init(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 62c0de3e26..55addb77b1 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -2420,40 +2420,6 @@ "third_party": false, "type": "target" }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc_test_util" - ], - "headers": [], - "is_filegroup": false, - "language": "c", - "name": "transport_metadata_test", - "src": [ - "test/core/transport/metadata_test.c" - ], - "third_party": false, - "type": "target" - }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc_test_util" - ], - "headers": [], - "is_filegroup": false, - "language": "c", - "name": "transport_pid_controller_test", - "src": [ - "test/core/transport/pid_controller_test.c" - ], - "third_party": false, - "type": "target" - }, { "deps": [ "gpr", @@ -4220,6 +4186,42 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "transport_metadata_test", + "src": [ + "test/core/transport/metadata_test.c" + ], + "third_party": false, + "type": "target" + }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc++_test_util", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "transport_pid_controller_test", + "src": [ + "test/core/transport/pid_controller_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index d246f6dc11..c9a13ecc87 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -2607,50 +2607,6 @@ "windows" ] }, - { - "args": [], - "ci_platforms": [ - "linux", - "mac", - "posix", - "windows" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "gtest": false, - "language": "c", - "name": "transport_metadata_test", - "platforms": [ - "linux", - "mac", - "posix", - "windows" - ] - }, - { - "args": [], - "ci_platforms": [ - "linux", - "mac", - "posix", - "windows" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "gtest": false, - "language": "c", - "name": "transport_pid_controller_test", - "platforms": [ - "linux", - "mac", - "posix", - "windows" - ] - }, { "args": [], "ci_platforms": [ @@ -4102,6 +4058,50 @@ ], "timeout_seconds": 1200 }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "transport_metadata_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "transport_pid_controller_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ -- cgit v1.2.3 From 4bbd68b20838027a145d1f96b6bff68dfdf84ab9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 12:53:34 -0700 Subject: C++ize FlowControl - WIP --- .../transport/chttp2/transport/chttp2_transport.cc | 8 +- .../ext/transport/chttp2/transport/flow_control.cc | 519 +++++++++------------ .../ext/transport/chttp2/transport/flow_control.h | 294 ++++++++++++ src/core/ext/transport/chttp2/transport/internal.h | 139 +----- 4 files changed, 513 insertions(+), 447 deletions(-) create mode 100644 src/core/ext/transport/chttp2/transport/flow_control.h (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index f6f9242caf..fdbeced445 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -54,7 +54,6 @@ #include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport_impl.h" -#define DEFAULT_WINDOW 65535 #define DEFAULT_CONNECTION_WINDOW_TARGET (1024 * 1024) #define MAX_WINDOW 0x7fffffffu #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) @@ -222,7 +221,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, t->write_cb_pool = next; } - t->flow_control.bdp_estimator.Destroy(); + t->flow_control.Destroy(); gpr_free(t->ping_acks); gpr_free(t->peer_string); @@ -281,10 +280,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->endpoint_reading = 1; t->next_stream_id = is_client ? 1 : 2; t->is_client = is_client; - t->flow_control.remote_window = DEFAULT_WINDOW; - t->flow_control.announced_window = DEFAULT_WINDOW; - t->flow_control.target_initial_window_size = DEFAULT_WINDOW; - t->flow_control.t = t; + t->flow_control.Init(); t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->is_first_frame = true; grpc_connectivity_state_init( diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 716cd71490..3898e53337 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -16,7 +16,7 @@ * */ -#include "src/core/ext/transport/chttp2/transport/internal.h" +#include "src/core/ext/transport/chttp2/transport/flow_control.h" #include #include @@ -28,38 +28,15 @@ #include #include +#include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/lib/support/string.h" -static uint32_t grpc_chttp2_target_announced_window( - const grpc_chttp2_transport_flowctl* tfc); - -#ifndef NDEBUG - -typedef struct { - int64_t remote_window; - int64_t target_window; - int64_t announced_window; - int64_t remote_window_delta; - int64_t local_window_delta; - int64_t announced_window_delta; - uint32_t local_init_window; - uint32_t local_max_frame; -} shadow_flow_control; - -static void pretrace(shadow_flow_control* shadow_fc, - grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc) { - shadow_fc->remote_window = tfc->remote_window; - shadow_fc->target_window = grpc_chttp2_target_announced_window(tfc); - shadow_fc->announced_window = tfc->announced_window; - if (sfc != NULL) { - shadow_fc->remote_window_delta = sfc->remote_window_delta; - shadow_fc->local_window_delta = sfc->local_window_delta; - shadow_fc->announced_window_delta = sfc->announced_window_delta; - } -} +namespace grpc_core { +namespace chttp2 { + +namespace { -#define TRACE_PADDING 30 +static constexpr const int kTracePadding = 30; static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) { char* str; @@ -68,7 +45,7 @@ static char* fmt_int64_diff_str(int64_t old_val, int64_t new_val) { } else { gpr_asprintf(&str, "%" PRId64 "", old_val); } - char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); + char* str_lp = gpr_leftpad(str, ' ', kTracePadding); gpr_free(str); return str_lp; } @@ -80,47 +57,57 @@ static char* fmt_uint32_diff_str(uint32_t old_val, uint32_t new_val) { } else { gpr_asprintf(&str, "%" PRIu32 "", old_val); } - char* str_lp = gpr_leftpad(str, ' ', TRACE_PADDING); + char* str_lp = gpr_leftpad(str, ' ', kTracePadding); gpr_free(str); return str_lp; } +} // namespace + +void FlowControlTrace::Init(const char* reason, TransportFlowControl* tfc, + StreamFlowControl* sfc) { + tfc_ = tfc; + sfc_ = sfc; + remote_window_ = tfc->remote_window(); + target_window_ = tfc->target_window(); + announced_window_ = tfc->announced_window(); + if (sfc != nullptr) { + remote_window_delta_ = sfc->remote_window_delta(); + local_window_delta_ = sfc->local_window_delta(); + announced_window_delta_ = sfc->announced_window_delta(); + } +} -static void posttrace(shadow_flow_control* shadow_fc, - grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc, const char* reason) { +void FlowControlTrace::Finish() { uint32_t acked_local_window = - tfc->t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + tfc_->transport()->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; uint32_t remote_window = - tfc->t->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - char* trw_str = - fmt_int64_diff_str(shadow_fc->remote_window, tfc->remote_window); - char* tlw_str = fmt_int64_diff_str(shadow_fc->target_window, - grpc_chttp2_target_announced_window(tfc)); + tfc_->transport()->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + char* trw_str = fmt_int64_diff_str(remote_window_, tfc_->remote_window()); + char* tlw_str = fmt_int64_diff_str(target_window_, tfc_->target_window()); char* taw_str = - fmt_int64_diff_str(shadow_fc->announced_window, tfc->announced_window); + fmt_int64_diff_str(announced_window_, tfc_->announced_window()); char* srw_str; char* slw_str; char* saw_str; - if (sfc != NULL) { - srw_str = fmt_int64_diff_str(shadow_fc->remote_window_delta + remote_window, - sfc->remote_window_delta + remote_window); - slw_str = - fmt_int64_diff_str(shadow_fc->local_window_delta + acked_local_window, - sfc->local_window_delta + acked_local_window); - saw_str = fmt_int64_diff_str( - shadow_fc->announced_window_delta + acked_local_window, - sfc->announced_window_delta + acked_local_window); + if (sfc_ != nullptr) { + srw_str = fmt_int64_diff_str(remote_window_delta_ + remote_window, + sfc_->remote_window_delta() + remote_window); + slw_str = fmt_int64_diff_str(local_window_delta_ + acked_local_window, + local_window_delta_ + acked_local_window); + saw_str = fmt_int64_diff_str(announced_window_delta_ + acked_local_window, + announced_window_delta_ + acked_local_window); } else { - srw_str = gpr_leftpad("", ' ', TRACE_PADDING); - slw_str = gpr_leftpad("", ' ', TRACE_PADDING); - saw_str = gpr_leftpad("", ' ', TRACE_PADDING); + srw_str = gpr_leftpad("", ' ', kTracePadding); + slw_str = gpr_leftpad("", ' ', kTracePadding); + saw_str = gpr_leftpad("", ' ', kTracePadding); } gpr_log(GPR_DEBUG, "%p[%u][%s] | %s | trw:%s, ttw:%s, taw:%s, srw:%s, slw:%s, saw:%s", - tfc, sfc != NULL ? sfc->s->id : 0, tfc->t->is_client ? "cli" : "svr", - reason, trw_str, tlw_str, taw_str, srw_str, slw_str, saw_str); + tfc_, sfc_ != nullptr ? sfc_->stream()->id : 0, + tfc_->transport()->is_client ? "cli" : "svr", reason_, trw_str, + tlw_str, taw_str, srw_str, slw_str, saw_str); gpr_free(trw_str); gpr_free(tlw_str); gpr_free(taw_str); @@ -129,13 +116,13 @@ static void posttrace(shadow_flow_control* shadow_fc, gpr_free(saw_str); } -static const char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) { - switch (urgency) { - case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: +const char* FlowControlAction::UrgencyString(Urgency u) { + switch (u) { + case Urgency::NO_ACTION_NEEDED: return "no action"; - case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: + case Urgency::UPDATE_IMMEDIATELY: return "update immediately"; - case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: + case Urgency::QUEUE_UPDATE: return "queue update"; default: GPR_UNREACHABLE_CODE(return "unknown"); @@ -143,209 +130,110 @@ static const char* urgency_to_string(grpc_chttp2_flowctl_urgency urgency) { GPR_UNREACHABLE_CODE(return "unknown"); } -static void trace_action(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_flowctl_action action) { +void FlowControlAction::Trace(grpc_chttp2_transport* t) const { char* iw_str = fmt_uint32_diff_str( - tfc->t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], - action.initial_window_size); + t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], + initial_window_size_); char* mf_str = fmt_uint32_diff_str( - tfc->t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - action.max_frame_size); + t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + max_frame_size_); gpr_log(GPR_DEBUG, "t[%s], s[%s], settings[%s] iw:%s mf:%s", - urgency_to_string(action.send_transport_update), - urgency_to_string(action.send_stream_update), - urgency_to_string(action.send_setting_update), iw_str, mf_str); + UrgencyString(send_transport_update_), + UrgencyString(send_stream_update_), + UrgencyString(send_setting_update_), iw_str, mf_str); gpr_free(iw_str); gpr_free(mf_str); } -#define PRETRACE(tfc, sfc) \ - shadow_flow_control shadow_fc; \ - GRPC_FLOW_CONTROL_IF_TRACING(pretrace(&shadow_fc, tfc, sfc)) -#define POSTTRACE(tfc, sfc, reason) \ - GRPC_FLOW_CONTROL_IF_TRACING(posttrace(&shadow_fc, tfc, sfc, reason)) -#define TRACEACTION(tfc, action) \ - GRPC_FLOW_CONTROL_IF_TRACING(trace_action(tfc, action)) -#else -#define PRETRACE(tfc, sfc) -#define POSTTRACE(tfc, sfc, reason) -#define TRACEACTION(tfc, action) -#endif - -/* How many bytes of incoming flow control would we like to advertise */ -static uint32_t grpc_chttp2_target_announced_window( - const grpc_chttp2_transport_flowctl* tfc) { - return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1), - tfc->announced_stream_total_over_incoming_window + - tfc->target_initial_window_size); -} - -// we have sent data on the wire, we must track this in our bookkeeping for the -// remote peer's flow control. -void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc, - int64_t size) { - PRETRACE(tfc, sfc); - tfc->remote_window -= size; - sfc->remote_window_delta -= size; - POSTTRACE(tfc, sfc, " data sent"); -} - -static void announced_window_delta_preupdate(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc) { - if (sfc->announced_window_delta > 0) { - tfc->announced_stream_total_over_incoming_window -= - sfc->announced_window_delta; - } else { - tfc->announced_stream_total_under_incoming_window += - -sfc->announced_window_delta; - } -} - -static void announced_window_delta_postupdate( - grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { - if (sfc->announced_window_delta > 0) { - tfc->announced_stream_total_over_incoming_window += - sfc->announced_window_delta; - } else { - tfc->announced_stream_total_under_incoming_window -= - -sfc->announced_window_delta; +uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) { + FlowControlTrace trace("t updt sent", this, nullptr); + const uint32_t target_announced_window = target_window(); + if ((writing_anyway || announced_window_ <= target_announced_window / 2) && + announced_window_ != target_announced_window) { + const uint32_t announce = (uint32_t)GPR_CLAMP( + target_announced_window - announced_window_, 0, UINT32_MAX); + announced_window_ += announce; + return announce; } + return 0; } -// We have received data from the wire. We must track this in our own flow -// control bookkeeping. -// Returns an error if the incoming frame violates our flow control. -grpc_error* grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc, - int64_t incoming_frame_size) { - uint32_t sent_init_window = - tfc->t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - uint32_t acked_init_window = - tfc->t->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - PRETRACE(tfc, sfc); - if (incoming_frame_size > tfc->announced_window) { +grpc_error* TransportFlowControl::ValidateRecvData( + int64_t incoming_frame_size) { + if (incoming_frame_size > announced_window_) { char* msg; gpr_asprintf(&msg, "frame of size %" PRId64 " overflows local window of %" PRId64, - incoming_frame_size, tfc->announced_window); + incoming_frame_size, announced_window_); grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); gpr_free(msg); return err; } - - if (sfc != NULL) { - int64_t acked_stream_window = - sfc->announced_window_delta + acked_init_window; - int64_t sent_stream_window = sfc->announced_window_delta + sent_init_window; - if (incoming_frame_size > acked_stream_window) { - if (incoming_frame_size <= sent_stream_window) { - gpr_log( - GPR_ERROR, - "Incoming frame of size %" PRId64 - " exceeds local window size of %" PRId64 - ".\n" - "The (un-acked, future) window size would be %" PRId64 - " which is not exceeded.\n" - "This would usually cause a disconnection, but allowing it due to" - "broken HTTP2 implementations in the wild.\n" - "See (for example) https://github.com/netty/netty/issues/6520.", - incoming_frame_size, acked_stream_window, sent_stream_window); - } else { - char* msg; - gpr_asprintf(&msg, "frame of size %" PRId64 - " overflows local window of %" PRId64, - incoming_frame_size, acked_stream_window); - grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); - gpr_free(msg); - return err; - } - } - - announced_window_delta_preupdate(tfc, sfc); - sfc->announced_window_delta -= incoming_frame_size; - announced_window_delta_postupdate(tfc, sfc); - sfc->local_window_delta -= incoming_frame_size; - } - - tfc->announced_window -= incoming_frame_size; - - POSTTRACE(tfc, sfc, " data recv"); return GRPC_ERROR_NONE; } -// Returns a non zero announce integer if we should send a transport window -// update -uint32_t grpc_chttp2_flowctl_maybe_send_transport_update( - grpc_chttp2_transport_flowctl* tfc, bool writing_anyway) { - PRETRACE(tfc, NULL); - uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); - uint32_t threshold_to_send_transport_window_update = - tfc->t->outbuf.count > 0 ? 3 * target_announced_window / 4 - : target_announced_window / 2; - if ((writing_anyway || - tfc->announced_window <= threshold_to_send_transport_window_update) && - tfc->announced_window != target_announced_window) { - uint32_t announce = (uint32_t)GPR_CLAMP( - target_announced_window - tfc->announced_window, 0, UINT32_MAX); - tfc->announced_window += announce; - POSTTRACE(tfc, NULL, "t updt sent"); - return announce; +grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) { + FlowControlTrace trace(" data recv", tfc_, this); + + grpc_error* error = GRPC_ERROR_NONE; + error = tfc_->ValidateRecvData(incoming_frame_size); + if (error != GRPC_ERROR_NONE) return error; + + uint32_t sent_init_window = + tfc_->transport()->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + uint32_t acked_init_window = + tfc_->transport()->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + + int64_t acked_stream_window = announced_window_delta_ + acked_init_window; + int64_t sent_stream_window = announced_window_delta_ + sent_init_window; + if (incoming_frame_size > acked_stream_window) { + if (incoming_frame_size <= sent_stream_window) { + gpr_log(GPR_ERROR, + "Incoming frame of size %" PRId64 + " exceeds local window size of %" PRId64 + ".\n" + "The (un-acked, future) window size would be %" PRId64 + " which is not exceeded.\n" + "This would usually cause a disconnection, but allowing it due to" + "broken HTTP2 implementations in the wild.\n" + "See (for example) https://github.com/netty/netty/issues/6520.", + incoming_frame_size, acked_stream_window, sent_stream_window); + } else { + char* msg; + gpr_asprintf(&msg, "frame of size %" PRId64 + " overflows local window of %" PRId64, + incoming_frame_size, acked_stream_window); + grpc_error* err = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + return err; + } } - GRPC_FLOW_CONTROL_IF_TRACING( - gpr_log(GPR_DEBUG, "%p[0][%s] will not send transport update", tfc, - tfc->t->is_client ? "cli" : "svr")); - return 0; + + UpdateAnnouncedWindowDelta(tfc_, -incoming_frame_size); + local_window_delta_ -= incoming_frame_size; + tfc_->CommitRecvData(incoming_frame_size); } -// Returns a non zero announce integer if we should send a stream window update -uint32_t grpc_chttp2_flowctl_maybe_send_stream_update( - grpc_chttp2_transport_flowctl* tfc, grpc_chttp2_stream_flowctl* sfc) { - PRETRACE(tfc, sfc); - if (sfc->local_window_delta > sfc->announced_window_delta) { +uint32_t StreamFlowControl::MaybeSendUpdate() { + FlowControlTrace trace("s updt sent", tfc_, this); + if (local_window_delta_ > announced_window_delta_) { uint32_t announce = (uint32_t)GPR_CLAMP( - sfc->local_window_delta - sfc->announced_window_delta, 0, UINT32_MAX); - announced_window_delta_preupdate(tfc, sfc); - sfc->announced_window_delta += announce; - announced_window_delta_postupdate(tfc, sfc); - POSTTRACE(tfc, sfc, "s updt sent"); + local_window_delta_ - announced_window_delta_, 0, UINT32_MAX); + UpdateAnnouncedWindowDelta(tfc_, announce); return announce; } - GRPC_FLOW_CONTROL_IF_TRACING( - gpr_log(GPR_DEBUG, "%p[%u][%s] will not send stream update", tfc, - sfc->s->id, tfc->t->is_client ? "cli" : "svr")); return 0; } -// we have received a WINDOW_UPDATE frame for a transport -void grpc_chttp2_flowctl_recv_transport_update( - grpc_chttp2_transport_flowctl* tfc, uint32_t size) { - PRETRACE(tfc, NULL); - tfc->remote_window += size; - POSTTRACE(tfc, NULL, "t updt recv"); -} - -// we have received a WINDOW_UPDATE frame for a stream -void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc, - uint32_t size) { - PRETRACE(tfc, sfc); - sfc->remote_window_delta += size; - POSTTRACE(tfc, sfc, "s updt recv"); -} - -void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc, - size_t max_size_hint, - size_t have_already) { - PRETRACE(tfc, sfc); +void StreamFlowControl::IncomingByteStreamUpdate(size_t max_size_hint, + size_t have_already) { + FlowControlTrace trace("app st recv", tfc_, this); uint32_t max_recv_bytes; uint32_t sent_init_window = - tfc->t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + tfc_->transport()->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; /* clamp max recv hint to an allowable size */ if (max_size_hint >= UINT32_MAX - sent_init_window) { @@ -363,65 +251,18 @@ void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl* tfc, /* add some small lookahead to keep pipelines flowing */ GPR_ASSERT(max_recv_bytes <= UINT32_MAX - sent_init_window); - if (sfc->local_window_delta < max_recv_bytes) { + if (local_window_delta_ < max_recv_bytes) { uint32_t add_max_recv_bytes = - (uint32_t)(max_recv_bytes - sfc->local_window_delta); - sfc->local_window_delta += add_max_recv_bytes; - } - POSTTRACE(tfc, sfc, "app st recv"); -} - -void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc) { - announced_window_delta_preupdate(tfc, sfc); -} - -// Returns an urgency with which to make an update -static grpc_chttp2_flowctl_urgency delta_is_significant( - const grpc_chttp2_transport_flowctl* tfc, int32_t value, - grpc_chttp2_setting_id setting_id) { - int64_t delta = (int64_t)value - - (int64_t)tfc->t->settings[GRPC_LOCAL_SETTINGS][setting_id]; - // TODO(ncteisen): tune this - if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) { - return GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; - } else { - return GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED; + (uint32_t)(max_recv_bytes - local_window_delta_); + local_window_delta_ += add_max_recv_bytes; } } -// Takes in a target and uses the pid controller to return a stabilized -// guess at the new bdp. -static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx, - grpc_chttp2_transport_flowctl* tfc, - double target) { - grpc_millis now = grpc_exec_ctx_now(exec_ctx); - if (!tfc->pid_controller_initialized) { - tfc->last_pid_update = now; - tfc->pid_controller_initialized = true; - tfc->pid_controller.Init(grpc_core::PidController::Args() - .set_gain_p(4) - .set_gain_i(8) - .set_gain_d(0) - .set_initial_control_value(target) - .set_min_control_value(-1) - .set_max_control_value(25) - .set_integral_range(10)); - return pow(2, target); - } - double bdp_error = target - tfc->pid_controller->last_control_value(); - double dt = (double)(now - tfc->last_pid_update) * 1e-3; - double log2_bdp_guess = tfc->pid_controller->Update(bdp_error, dt); - tfc->last_pid_update = now; - return pow(2, log2_bdp_guess); -} - // Take in a target and modifies it based on the memory pressure of the system -static double get_target_under_memory_pressure( - grpc_chttp2_transport_flowctl* tfc, double target) { +static double AdjustForMemoryPressure(grpc_resource_quota* quota, + double target) { // do not increase window under heavy memory pressure. - double memory_pressure = grpc_resource_quota_get_memory_pressure( - grpc_resource_user_quota(grpc_endpoint_get_resource_user(tfc->t->ep))); + double memory_pressure = grpc_resource_quota_get_memory_pressure(quota); static const double kLowMemPressure = 0.1; static const double kZeroTarget = 22; static const double kHighMemPressure = 0.8; @@ -436,35 +277,19 @@ static double get_target_under_memory_pressure( return target; } -grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( - grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc) { - grpc_chttp2_flowctl_action action; - memset(&action, 0, sizeof(action)); - // TODO(ncteisen): tune this - if (sfc != NULL && !sfc->s->read_closed) { - uint32_t sent_init_window = - tfc->t->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - if ((int64_t)sfc->local_window_delta > - (int64_t)sfc->announced_window_delta && - (int64_t)sfc->announced_window_delta + sent_init_window <= - sent_init_window / 2) { - action.send_stream_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY; - } else if (sfc->local_window_delta > sfc->announced_window_delta) { - action.send_stream_update = GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; - } - } - if (tfc->enable_bdp_probe) { +FlowControlAction TransportFlowControl::UpdateForBdp(FlowControlAction action) { + if (enable_bdp_probe_) { // get bdp estimate and update initial_window accordingly. int64_t estimate = -1; - if (tfc->bdp_estimator->EstimateBdp(&estimate)) { + if (bdp_estimator_.EstimateBdp(&estimate)) { double target = 1 + log2((double)estimate); // target might change based on how much memory pressure we are under // TODO(ncteisen): experiment with setting target to be huge under low // memory pressure. - target = get_target_under_memory_pressure(tfc, target); + target = AdjustForMemoryPressure( + grpc_resource_user_quota(grpc_endpoint_get_resource_user(t_->ep)), + target); // run our target through the pid controller to stabilize change. // TODO(ncteisen): experiment with other controllers here. @@ -501,6 +326,80 @@ grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( } } } +} + +FlowControlAction TransportFlowControl::MakeAction(grpc_exec_ctx* exec_ctx) { + FlowControlAction action; + action = UpdateForBdp(exec_ctx, action); + return action; +} + +FlowControlAction StreamFlowControl::UpdateAction(FlowControlAction action) { + // TODO(ncteisen): tune this + if (!s_->read_closed) { + uint32_t sent_init_window = + tfc_->transport()->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + if (local_window_delta_ > announced_window_delta_ && + announced_window_delta_ + sent_init_window <= sent_init_window / 2) { + action.set_send_stream_update( + FlowControlAction::Urgency::UPDATE_IMMEDIATELY); + } else if (local_window_delta_ > announced_window_delta_) { + action.set_send_stream_update(FlowControlAction::Urgency::QUEUE_UPDATE); + } + } + + return action; +} + +} // namespace chttp2 +} // namespace grpc_core + +// Returns an urgency with which to make an update +static grpc_chttp2_flowctl_urgency delta_is_significant( + const grpc_chttp2_transport_flowctl* tfc, int32_t value, + grpc_chttp2_setting_id setting_id) { + int64_t delta = (int64_t)value - + (int64_t)tfc->t->settings[GRPC_LOCAL_SETTINGS][setting_id]; + // TODO(ncteisen): tune this + if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) { + return GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; + } else { + return GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED; + } +} + +// Takes in a target and uses the pid controller to return a stabilized +// guess at the new bdp. +static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx, + grpc_chttp2_transport_flowctl* tfc, + double target) { + grpc_millis now = grpc_exec_ctx_now(exec_ctx); + if (!tfc->pid_controller_initialized) { + tfc->last_pid_update = now; + tfc->pid_controller_initialized = true; + tfc->pid_controller.Init(grpc_core::PidController::Args() + .set_gain_p(4) + .set_gain_i(8) + .set_gain_d(0) + .set_initial_control_value(target) + .set_min_control_value(-1) + .set_max_control_value(25) + .set_integral_range(10)); + return pow(2, target); + } + double bdp_error = target - tfc->pid_controller->last_control_value(); + double dt = (double)(now - tfc->last_pid_update) * 1e-3; + double log2_bdp_guess = tfc->pid_controller->Update(bdp_error, dt); + tfc->last_pid_update = now; + return pow(2, log2_bdp_guess); +} + +grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( + grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc, + grpc_chttp2_stream_flowctl* sfc) { + grpc_chttp2_flowctl_action action; + memset(&action, 0, sizeof(action)); uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); if (tfc->announced_window < target_announced_window / 2) { action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY; diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h new file mode 100644 index 0000000000..be81d3a97b --- /dev/null +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -0,0 +1,294 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H +#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H + +#include + +#include +#include "src/core/lib/support/manual_constructor.h" +#include "src/core/lib/transport/bdp_estimator.h" +#include "src/core/lib/transport/pid_controller.h" + +struct grpc_chttp2_transport; +struct grpc_chttp2_stream; + +extern "C" grpc_tracer_flag grpc_flowctl_trace; + +namespace grpc_core { +namespace chttp2 { + +static constexpr uint32_t kDefaultWindow = 65535; + +class TransportFlowControl; +class StreamFlowControl; + +class FlowControlAction { + public: + enum class Urgency : uint8_t { + // Nothing to be done. + NO_ACTION_NEEDED = 0, + // Initiate a write to update the initial window immediately. + UPDATE_IMMEDIATELY, + // Push the flow control update into a send buffer, to be sent + // out the next time a write is initiated. + QUEUE_UPDATE, + }; + + Urgency send_stream_update() const { return send_stream_update_; } + Urgency send_transport_update() const { return send_transport_update_; } + Urgency send_setting_update() const { return send_setting_update_; } + uint32_t initial_window_size() const { return initial_window_size_; } + uint32_t max_frame_size() const { return max_frame_size_; } + + FlowControlAction& set_send_stream_update(Urgency u) { + send_stream_update_ = u; + return *this; + } + FlowControlAction& send_transport_update(Urgency u) { + send_transport_update_ = u; + return *this; + } + FlowControlAction& send_setting_update(Urgency u) { + send_setting_update_ = u; + return *this; + } + + static const char* UrgencyString(Urgency u); + void Trace(grpc_chttp2_transport* t) const; + + private: + Urgency send_stream_update_ = Urgency::NO_ACTION_NEEDED; + Urgency send_transport_update_ = Urgency::NO_ACTION_NEEDED; + Urgency send_setting_update_ = Urgency::NO_ACTION_NEEDED; + uint32_t initial_window_size_ = 0; + uint32_t max_frame_size_ = 0; +}; + +class FlowControlTrace { + public: + FlowControlTrace(const char* reason, TransportFlowControl* tfc, + StreamFlowControl* sfc) { + if (enabled_) Init(reason, tfc, sfc); + } + + ~FlowControlTrace() { + if (enabled_) Finish(); + } + + private: + void Init(const char* reason, TransportFlowControl* tfc, + StreamFlowControl* sfc); + void Finish(); + + const bool enabled_ = GRPC_TRACER_ON(grpc_flowctl_trace); + + TransportFlowControl* tfc_; + StreamFlowControl* sfc_; + const char* reason_; + int64_t remote_window_; + int64_t target_window_; + int64_t announced_window_; + int64_t remote_window_delta_; + int64_t local_window_delta_; + int64_t announced_window_delta_; + uint32_t local_init_window_; + uint32_t local_max_frame_; +}; + +class TransportFlowControl { + public: + ~TransportFlowControl() { + if (pid_controller_initialized_) { + pid_controller_.Destroy(); + } + } + + // returns an announce if we should send a transport update to our peer, + // else returns zero; writing_anyway indicates if a write would happen + // regardless of the send - if it is false and this function returns non-zero, + // this announce will cause a write to occur + uint32_t MaybeSendUpdate(bool writing_anyway); + + // Reads the flow control data and returns and actionable struct that will + // tell chttp2 exactly what it needs to do + FlowControlAction MakeAction(grpc_exec_ctx* exec_ctx); + + void StreamSentData(int64_t size) { remote_window_ -= size; } + + grpc_error* ValidateRecvData(int64_t incoming_frame_size); + void CommitRecvData(int64_t incoming_frame_size) { + announced_window_ -= incoming_frame_size; + } + + grpc_error* RecvData(int64_t incoming_frame_size) { + FlowControlTrace trace(" data recv", this, nullptr); + grpc_error* error = ValidateRecvData(incoming_frame_size); + if (error != GRPC_ERROR_NONE) return error; + CommitRecvData(incoming_frame_size); + return GRPC_ERROR_NONE; + } + + // we have received a WINDOW_UPDATE frame for a transport + void RecvUpdate(uint32_t size) { + FlowControlTrace trace("t updt recv", this, nullptr); + remote_window_ += size; + } + + int64_t remote_window() const { return remote_window_; } + int64_t target_window() const { + return (uint32_t)GPR_MIN((int64_t)((1u << 31) - 1), + announced_stream_total_over_incoming_window_ + + target_initial_window_size_); + } + int64_t announced_window() const { return announced_window_; } + + const grpc_chttp2_transport* transport() const { return t_; } + + void PreUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) { + if (delta > 0) { + announced_stream_total_over_incoming_window_ -= delta; + } else { + announced_stream_total_under_incoming_window_ += -delta; + } + } + + void PostUpdateAnnouncedWindowOverIncomingWindow(int64_t delta) { + if (delta > 0) { + announced_stream_total_over_incoming_window_ += delta; + } else { + announced_stream_total_under_incoming_window_ -= -delta; + } + } + + private: + FlowControlAction UpdateForBdp(grpc_exec_ctx* exec_ctx, + FlowControlAction action); + double SmoothBdp(grpc_exec_ctx* exec_ctx, double value); + + const grpc_chttp2_transport* const t_; + + /** initial window change. This is tracked as we parse settings frames from + * the remote peer. If there is a positive delta, then we will make all + * streams readable since they may have become unstalled */ + int64_t initial_window_update_ = 0; + + /** Our bookkeeping for the remote peer's available window */ + int64_t remote_window_ = kDefaultWindow; + + /** calculating what we should give for local window: + we track the total amount of flow control over initial window size + across all streams: this is data that we want to receive right now (it + has an outstanding read) + and the total amount of flow control under initial window size across all + streams: this is data we've read early + we want to adjust incoming_window such that: + incoming_window = total_over - max(bdp - total_under, 0) */ + int64_t announced_stream_total_over_incoming_window_ = 0; + int64_t announced_stream_total_under_incoming_window_ = 0; + + /** This is out window according to what we have sent to our remote peer. The + * difference between this and target window is what we use to decide when + * to send WINDOW_UPDATE frames. */ + int64_t announced_window_ = kDefaultWindow; + + int32_t target_initial_window_size_ = kDefaultWindow; + + /** should we probe bdp? */ + bool enable_bdp_probe_; + + /* bdp estimation */ + grpc_core::BdpEstimator bdp_estimator_; + + /* pid controller */ + bool pid_controller_initialized_; + grpc_core::ManualConstructor pid_controller_; + grpc_millis last_pid_update_; +}; + +class StreamFlowControl { + public: + StreamFlowControl(TransportFlowControl* tfc, grpc_chttp2_stream* s); + ~StreamFlowControl() { + tfc_->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_); + } + + FlowControlAction UpdateAction(FlowControlAction action); + FlowControlAction MakeAction() { return UpdateAction(FlowControlAction()); } + + // we have sent data on the wire, we must track this in our bookkeeping for + // the remote peer's flow control. + void SentData(int64_t outgoing_frame_size) { + FlowControlTrace tracer(" data sent", tfc_, this); + tfc_->StreamSentData(outgoing_frame_size); + remote_window_delta_ -= outgoing_frame_size; + } + + // we have received data from the wire + grpc_error* RecvData(int64_t incoming_frame_size); + + // returns an announce if we should send a stream update to our peer, else + // returns zero + uint32_t MaybeSendUpdate(); + + // we have received a WINDOW_UPDATE frame for a stream + void RecvUpdate(uint32_t size) { + FlowControlTrace trace("s updt recv", tfc_, this); + remote_window_delta_ += size; + } + + // the application is asking for a certain amount of bytes + void IncomingByteStreamUpdate(size_t max_size_hint, size_t have_already); + + int64_t remote_window_delta() const { return remote_window_delta_; } + int64_t local_window_delta() const { return local_window_delta_; } + int64_t announced_window_delta() const { return announced_window_delta_; } + + const grpc_chttp2_stream* stream() const { return s_; } + + private: + TransportFlowControl* const tfc_; + const grpc_chttp2_stream* const s_; + + void UpdateAnnouncedWindowDelta(TransportFlowControl* tfc, int64_t change) { + tfc->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_); + announced_window_delta_ += change; + tfc->PostUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_); + } + + /** window available for us to send to peer, over or under the initial + * window + * size of the transport... ie: + * remote_window = remote_window_delta + transport.initial_window_size */ + int64_t remote_window_delta_; + + /** window available for peer to send to us (as a delta on + * transport.initial_window_size) + * local_window = local_window_delta + transport.initial_window_size */ + int64_t local_window_delta_; + + /** window available for peer to send to us over this stream that we have + * announced to the peer */ + int64_t announced_window_delta_; +}; + +} // namespace chttp2 +} // namespace grpc_core + +#endif diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index f0a75dfb45..57c4cfa5f3 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -22,6 +22,7 @@ #include #include +#include "src/core/ext/transport/chttp2/transport/flow_control.h" #include "src/core/ext/transport/chttp2/transport/frame.h" #include "src/core/ext/transport/chttp2/transport/frame_data.h" #include "src/core/ext/transport/chttp2/transport/frame_goaway.h" @@ -38,9 +39,7 @@ #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/support/manual_constructor.h" -#include "src/core/lib/transport/bdp_estimator.h" #include "src/core/lib/transport/connectivity_state.h" -#include "src/core/lib/transport/pid_controller.h" #include "src/core/lib/transport/transport_impl.h" #ifdef __cplusplus @@ -238,48 +237,6 @@ typedef enum { GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED, } grpc_chttp2_keepalive_state; -typedef struct { - /** initial window change. This is tracked as we parse settings frames from - * the remote peer. If there is a positive delta, then we will make all - * streams readable since they may have become unstalled */ - int64_t initial_window_update; - - /** Our bookkeeping for the remote peer's available window */ - int64_t remote_window; - - /** calculating what we should give for local window: - we track the total amount of flow control over initial window size - across all streams: this is data that we want to receive right now (it - has an outstanding read) - and the total amount of flow control under initial window size across all - streams: this is data we've read early - we want to adjust incoming_window such that: - incoming_window = total_over - max(bdp - total_under, 0) */ - int64_t announced_stream_total_over_incoming_window; - int64_t announced_stream_total_under_incoming_window; - - /** This is out window according to what we have sent to our remote peer. The - * difference between this and target window is what we use to decide when - * to send WINDOW_UPDATE frames. */ - int64_t announced_window; - - int32_t target_initial_window_size; - - /** should we probe bdp? */ - bool enable_bdp_probe; - - /* bdp estimation */ - grpc_core::ManualConstructor bdp_estimator; - - /* pid controller */ - bool pid_controller_initialized; - grpc_core::ManualConstructor pid_controller; - grpc_millis last_pid_update; - - // pointer back to transport for tracing - const grpc_chttp2_transport *t; -} grpc_chttp2_transport_flowctl; - struct grpc_chttp2_transport { grpc_transport base; /* must be first */ gpr_refcount refs; @@ -395,7 +352,8 @@ struct grpc_chttp2_transport { /** parser for goaway frames */ grpc_chttp2_goaway_parser goaway_parser; - grpc_chttp2_transport_flowctl flow_control; + grpc_core::ManualConstructor + flow_control; /* deframing */ grpc_chttp2_deframe_transport_state deframe_state; @@ -477,25 +435,6 @@ typedef enum { GPRC_METADATA_PUBLISHED_AT_CLOSE } grpc_published_metadata_method; -typedef struct { - /** window available for us to send to peer, over or under the initial window - * size of the transport... ie: - * remote_window = remote_window_delta + transport.initial_window_size */ - int64_t remote_window_delta; - - /** window available for peer to send to us (as a delta on - * transport.initial_window_size) - * local_window = local_window_delta + transport.initial_window_size */ - int64_t local_window_delta; - - /** window available for peer to send to us over this stream that we have - * announced to the peer */ - int64_t announced_window_delta; - - // read only pointer back to stream for data - const grpc_chttp2_stream *s; -} grpc_chttp2_stream_flowctl; - struct grpc_chttp2_stream { grpc_chttp2_transport *t; grpc_stream_refcount *refcount; @@ -589,7 +528,8 @@ struct grpc_chttp2_stream { bool sent_initial_metadata; bool sent_trailing_metadata; - grpc_chttp2_stream_flowctl flow_control; + grpc_core::ManualConstructor + flow_control; grpc_slice_buffer flow_controlled_buffer; @@ -700,73 +640,10 @@ bool grpc_chttp2_list_remove_stalled_by_stream(grpc_chttp2_transport *t, /********* Flow Control ***************/ -// we have sent data on the wire -void grpc_chttp2_flowctl_sent_data(grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc, - int64_t size); - -// we have received data from the wire -grpc_error *grpc_chttp2_flowctl_recv_data(grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc, - int64_t incoming_frame_size); - -// returns an announce if we should send a transport update to our peer, -// else returns zero -uint32_t grpc_chttp2_flowctl_maybe_send_transport_update( - grpc_chttp2_transport_flowctl *tfc, bool writing_anyway); - -// returns an announce if we should send a stream update to our peer, else -// returns zero -uint32_t grpc_chttp2_flowctl_maybe_send_stream_update( - grpc_chttp2_transport_flowctl *tfc, grpc_chttp2_stream_flowctl *sfc); - -// we have received a WINDOW_UPDATE frame for a transport -void grpc_chttp2_flowctl_recv_transport_update( - grpc_chttp2_transport_flowctl *tfc, uint32_t size); - -// we have received a WINDOW_UPDATE frame for a stream -void grpc_chttp2_flowctl_recv_stream_update(grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc, - uint32_t size); - -// the application is asking for a certain amount of bytes -void grpc_chttp2_flowctl_incoming_bs_update(grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc, - size_t max_size_hint, - size_t have_already); - -void grpc_chttp2_flowctl_destroy_stream(grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc); - -typedef enum { - // Nothing to be done. - GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED = 0, - // Initiate a write to update the initial window immediately. - GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY, - // Push the flow control update into a send buffer, to be sent - // out the next time a write is initiated. - GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE, -} grpc_chttp2_flowctl_urgency; - -typedef struct { - grpc_chttp2_flowctl_urgency send_stream_update; - grpc_chttp2_flowctl_urgency send_transport_update; - grpc_chttp2_flowctl_urgency send_setting_update; - uint32_t initial_window_size; - uint32_t max_frame_size; -} grpc_chttp2_flowctl_action; - -// Reads the flow control data and returns and actionable struct that will tell -// chttp2 exactly what it needs to do -grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_flowctl *tfc, - grpc_chttp2_stream_flowctl *sfc); - // Takes in a flow control action and performs all the needed operations. -void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, - grpc_chttp2_flowctl_action action, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s); +void grpc_chttp2_act_on_flowctl_action( + grpc_exec_ctx *exec_ctx, const grpc_core::chttp2::FlowControlAction &action, + grpc_chttp2_transport *t, grpc_chttp2_stream *s); /********* End of Flow Control ***************/ -- cgit v1.2.3 From e4b893b1a612fcad85487845acd1c990bf69df2e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 16:07:27 -0700 Subject: Progress --- .../transport/chttp2/transport/chttp2_transport.cc | 125 ++++++++--------- .../ext/transport/chttp2/transport/flow_control.cc | 148 +++++++++------------ .../ext/transport/chttp2/transport/flow_control.h | 53 ++++++-- 3 files changed, 156 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index fdbeced445..a8dfb1ba0c 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -280,7 +280,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->endpoint_reading = 1; t->next_stream_id = is_client ? 1 : 2; t->is_client = is_client; - t->flow_control.Init(); + t->flow_control.Init(t); t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->is_first_frame = true; grpc_connectivity_state_init( @@ -320,8 +320,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, keepalive_watchdog_fired_locked, t, grpc_combiner_scheduler(t->combiner)); - t->flow_control.bdp_estimator.Init(t->peer_string); - grpc_chttp2_goaway_parser_init(&t->goaway_parser); grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser); @@ -345,8 +343,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, window -- this should by rights be 0 */ t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; t->sent_local_settings = 0; - t->write_buffer_size = DEFAULT_WINDOW; - t->flow_control.enable_bdp_probe = true; + t->write_buffer_size = grpc_core::chttp2::kDefaultWindow; if (is_client) { grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string( @@ -451,8 +448,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}); } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { - t->flow_control.enable_bdp_probe = - grpc_channel_arg_get_integer(&channel_args->args[i], {1, 0, 1}); + t->flow_control->SetBdpProbe( + grpc_channel_arg_get_bool(&channel_args->args[i], true)); } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) { const int value = grpc_channel_arg_get_integer( @@ -570,9 +567,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, schedule_bdp_ping_locked(exec_ctx, t); grpc_chttp2_act_on_flowctl_action( - exec_ctx, - grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t, - NULL); + exec_ctx, t->flow_control->MakeAction(exec_ctx), t, NULL); grpc_chttp2_initiate_write(exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); @@ -708,7 +703,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, post_destructive_reclaimer(exec_ctx, t); } - s->flow_control.s = s; + s->flow_control.Init(t->flow_control.get(), s); GPR_TIMER_END("init_stream", 0); return 0; @@ -759,7 +754,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, GRPC_ERROR_UNREF(s->write_closed_error); GRPC_ERROR_UNREF(s->byte_stream_error); - grpc_chttp2_flowctl_destroy_stream(&t->flow_control, &s->flow_control); + s->flow_control.Destroy(); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream"); @@ -1626,13 +1621,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, if (s->id != 0) { if (!s->read_closed) { already_received = s->frame_storage.length; - grpc_chttp2_flowctl_incoming_bs_update( - &t->flow_control, &s->flow_control, GRPC_HEADER_SIZE_IN_BYTES, - already_received); + s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES, + already_received); grpc_chttp2_act_on_flowctl_action( - exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, - &s->flow_control), - t, s); + exec_ctx, s->flow_control->MakeAction(exec_ctx), t, s); } } grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); @@ -2399,49 +2391,44 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, * INPUT PROCESSING - PARSING */ -void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx, - grpc_chttp2_flowctl_action action, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - switch (action.send_stream_update) { - case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: - break; - case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: - grpc_chttp2_mark_stream_writable(exec_ctx, t, s); - grpc_chttp2_initiate_write( - exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL); - break; - case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: - grpc_chttp2_mark_stream_writable(exec_ctx, t, s); - break; - } - switch (action.send_transport_update) { - case GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED: - break; - case GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY: - grpc_chttp2_initiate_write( - exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL); +template +static void WithUrgency(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_core::chttp2::FlowControlAction::Urgency urgency, + grpc_chttp2_initiate_write_reason reason, F action) { + switch (urgency) { + case grpc_core::chttp2::FlowControlAction::Urgency::NO_ACTION_NEEDED: break; - // this is the same as no action b/c every time the transport enters the - // writing path it will maybe do an update - case GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE: + case grpc_core::chttp2::FlowControlAction::Urgency::UPDATE_IMMEDIATELY: + grpc_chttp2_initiate_write(exec_ctx, t, reason); + // fallthrough + case grpc_core::chttp2::FlowControlAction::Urgency::QUEUE_UPDATE: + action(); break; } - if (action.send_setting_update != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { - if (action.initial_window_size > 0) { - queue_setting_update(exec_ctx, t, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, - (uint32_t)action.initial_window_size); - } - if (action.max_frame_size > 0) { - queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, - (uint32_t)action.max_frame_size); - } - if (action.send_setting_update == GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY) { - grpc_chttp2_initiate_write(exec_ctx, t, - GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS); - } - } +} + +void grpc_chttp2_act_on_flowctl_action( + grpc_exec_ctx *exec_ctx, const grpc_core::chttp2::FlowControlAction &action, + grpc_chttp2_transport *t, grpc_chttp2_stream *s) { + WithUrgency( + exec_ctx, t, action.send_stream_update(), + GRPC_CHTTP2_INITIATE_WRITE_STREAM_FLOW_CONTROL, + [exec_ctx, t, s]() { grpc_chttp2_mark_stream_writable(exec_ctx, t, s); }); + WithUrgency(exec_ctx, t, action.send_transport_update(), + GRPC_CHTTP2_INITIATE_WRITE_TRANSPORT_FLOW_CONTROL, []() {}); + WithUrgency(exec_ctx, t, action.send_initial_window_update(), + GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, + [exec_ctx, t, &action]() { + queue_setting_update(exec_ctx, t, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, + action.initial_window_size()); + }); + WithUrgency( + exec_ctx, t, action.send_max_frame_size_update(), + GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS, [exec_ctx, t, &action]() { + queue_setting_update(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, + action.max_frame_size()); + }); } static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, @@ -2497,7 +2484,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, GRPC_ERROR_NONE}; for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) { - t->flow_control.bdp_estimator->AddIncomingBytes( + t->flow_control->bdp_estimator()->AddIncomingBytes( (int64_t)GRPC_SLICE_LENGTH(t->read_buffer.slices[i])); errors[1] = grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]); @@ -2547,9 +2534,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_locked); grpc_chttp2_act_on_flowctl_action( - exec_ctx, - grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t, - NULL); + exec_ctx, t->flow_control->MakeAction(exec_ctx), t, NULL); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); @@ -2565,7 +2550,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); - t->flow_control.bdp_estimator->SchedulePing(); + t->flow_control->bdp_estimator()->SchedulePing(); send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked); } @@ -2580,7 +2565,7 @@ static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) { grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer); } - t->flow_control.bdp_estimator->StartPing(); + t->flow_control->bdp_estimator()->StartPing(); } static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, @@ -2593,7 +2578,8 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); return; } - grpc_millis next_ping = t->flow_control.bdp_estimator->CompletePing(exec_ctx); + grpc_millis next_ping = + t->flow_control->bdp_estimator()->CompletePing(exec_ctx); GPR_ASSERT(!t->have_next_bdp_ping_timer); t->have_next_bdp_ping_timer = true; grpc_timer_init(exec_ctx, &t->next_bdp_ping_timer, next_ping, @@ -2816,13 +2802,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, size_t cur_length = s->frame_storage.length; if (!s->read_closed) { - grpc_chttp2_flowctl_incoming_bs_update(&t->flow_control, &s->flow_control, - bs->next_action.max_size_hint, - cur_length); + s->flow_control->IncomingByteStreamUpdate(bs->next_action.max_size_hint, + cur_length); grpc_chttp2_act_on_flowctl_action( - exec_ctx, grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, - &s->flow_control), - t, s); + exec_ctx, s->flow_control->MakeAction(exec_ctx), t, s); } GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); if (s->frame_storage.length > 0) { diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 3898e53337..4deff04b18 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -137,14 +137,18 @@ void FlowControlAction::Trace(grpc_chttp2_transport* t) const { char* mf_str = fmt_uint32_diff_str( t->settings[GRPC_SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], max_frame_size_); - gpr_log(GPR_DEBUG, "t[%s], s[%s], settings[%s] iw:%s mf:%s", + gpr_log(GPR_DEBUG, "t[%s], s[%s], iw:%s:%s mf:%s:%s", UrgencyString(send_transport_update_), UrgencyString(send_stream_update_), - UrgencyString(send_setting_update_), iw_str, mf_str); + UrgencyString(send_initial_window_update_), iw_str, + UrgencyString(send_max_frame_size_update_), mf_str); gpr_free(iw_str); gpr_free(mf_str); } +TransportFlowControl::TransportFlowControl(const grpc_chttp2_transport* t) + : t_(t), bdp_estimator_(t->peer_string) {} + uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) { FlowControlTrace trace("t updt sent", this, nullptr); const uint32_t target_announced_window = target_window(); @@ -172,6 +176,10 @@ grpc_error* TransportFlowControl::ValidateRecvData( return GRPC_ERROR_NONE; } +StreamFlowControl::StreamFlowControl(TransportFlowControl* tfc, + const grpc_chttp2_stream* s) + : tfc_(tfc), s_(s) {} + grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) { FlowControlTrace trace(" data recv", tfc_, this); @@ -277,53 +285,76 @@ static double AdjustForMemoryPressure(grpc_resource_quota* quota, return target; } -FlowControlAction TransportFlowControl::UpdateForBdp(FlowControlAction action) { +double TransportFlowControl::SmoothLogBdp(grpc_exec_ctx* exec_ctx, + double value) { + grpc_millis now = grpc_exec_ctx_now(exec_ctx); + if (!pid_controller_initialized_) { + last_pid_update_ = now; + pid_controller_initialized_ = true; + pid_controller_.Init(grpc_core::PidController::Args() + .set_gain_p(4) + .set_gain_i(8) + .set_gain_d(0) + .set_initial_control_value(value) + .set_min_control_value(-1) + .set_max_control_value(25) + .set_integral_range(10)); + return value; + } + double bdp_error = value - pid_controller_->last_control_value(); + const double dt = (double)(now - last_pid_update_) * 1e-3; + last_pid_update_ = now; + return pid_controller_->Update(bdp_error, dt); +} + +FlowControlAction::Urgency TransportFlowControl::DeltaUrgency( + int32_t value, grpc_chttp2_setting_id setting_id) { + int64_t delta = + (int64_t)value - (int64_t)t_->settings[GRPC_LOCAL_SETTINGS][setting_id]; + // TODO(ncteisen): tune this + if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) { + return FlowControlAction::Urgency::QUEUE_UPDATE; + } else { + return FlowControlAction::Urgency::NO_ACTION_NEEDED; + } +} + +FlowControlAction TransportFlowControl::UpdateForBdp(grpc_exec_ctx* exec_ctx, + FlowControlAction action) { if (enable_bdp_probe_) { // get bdp estimate and update initial_window accordingly. int64_t estimate = -1; if (bdp_estimator_.EstimateBdp(&estimate)) { - double target = 1 + log2((double)estimate); - // target might change based on how much memory pressure we are under // TODO(ncteisen): experiment with setting target to be huge under low // memory pressure. - target = AdjustForMemoryPressure( - grpc_resource_user_quota(grpc_endpoint_get_resource_user(t_->ep)), - target); - - // run our target through the pid controller to stabilize change. - // TODO(ncteisen): experiment with other controllers here. - double bdp_guess = get_pid_controller_guess(exec_ctx, tfc, target); + const double target = + pow(2, SmoothLogBdp(exec_ctx, + AdjustForMemoryPressure( + grpc_resource_user_quota( + grpc_endpoint_get_resource_user(t_->ep)), + 1 + log2((double)estimate)))); // Though initial window 'could' drop to 0, we keep the floor at 128 - tfc->target_initial_window_size = - (int32_t)GPR_CLAMP(bdp_guess, 128, INT32_MAX); - - grpc_chttp2_flowctl_urgency init_window_update_urgency = - delta_is_significant(tfc, tfc->target_initial_window_size, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE); - if (init_window_update_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { - action.send_setting_update = init_window_update_urgency; - action.initial_window_size = (uint32_t)tfc->target_initial_window_size; - } + target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX); + + action.set_send_initial_window_update( + DeltaUrgency(target_initial_window_size_, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE), + target_initial_window_size_); } // get bandwidth estimate and update max_frame accordingly. double bw_dbl = -1; - if (tfc->bdp_estimator->EstimateBandwidth(&bw_dbl)) { + if (bdp_estimator_.EstimateBandwidth(&bw_dbl)) { // we target the max of BDP or bandwidth in microseconds. int32_t frame_size = (int32_t)GPR_CLAMP( GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000, - tfc->target_initial_window_size), + target_initial_window_size_), 16384, 16777215); - grpc_chttp2_flowctl_urgency frame_size_urgency = delta_is_significant( - tfc, frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE); - if (frame_size_urgency != GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED) { - if (frame_size_urgency > action.send_setting_update) { - action.send_setting_update = frame_size_urgency; - } - action.max_frame_size = (uint32_t)frame_size; - } + action.set_send_max_frame_size_update( + DeltaUrgency(frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE), + frame_size); } } } @@ -354,56 +385,3 @@ FlowControlAction StreamFlowControl::UpdateAction(FlowControlAction action) { } // namespace chttp2 } // namespace grpc_core - -// Returns an urgency with which to make an update -static grpc_chttp2_flowctl_urgency delta_is_significant( - const grpc_chttp2_transport_flowctl* tfc, int32_t value, - grpc_chttp2_setting_id setting_id) { - int64_t delta = (int64_t)value - - (int64_t)tfc->t->settings[GRPC_LOCAL_SETTINGS][setting_id]; - // TODO(ncteisen): tune this - if (delta != 0 && (delta <= -value / 5 || delta >= value / 5)) { - return GRPC_CHTTP2_FLOWCTL_QUEUE_UPDATE; - } else { - return GRPC_CHTTP2_FLOWCTL_NO_ACTION_NEEDED; - } -} - -// Takes in a target and uses the pid controller to return a stabilized -// guess at the new bdp. -static double get_pid_controller_guess(grpc_exec_ctx* exec_ctx, - grpc_chttp2_transport_flowctl* tfc, - double target) { - grpc_millis now = grpc_exec_ctx_now(exec_ctx); - if (!tfc->pid_controller_initialized) { - tfc->last_pid_update = now; - tfc->pid_controller_initialized = true; - tfc->pid_controller.Init(grpc_core::PidController::Args() - .set_gain_p(4) - .set_gain_i(8) - .set_gain_d(0) - .set_initial_control_value(target) - .set_min_control_value(-1) - .set_max_control_value(25) - .set_integral_range(10)); - return pow(2, target); - } - double bdp_error = target - tfc->pid_controller->last_control_value(); - double dt = (double)(now - tfc->last_pid_update) * 1e-3; - double log2_bdp_guess = tfc->pid_controller->Update(bdp_error, dt); - tfc->last_pid_update = now; - return pow(2, log2_bdp_guess); -} - -grpc_chttp2_flowctl_action grpc_chttp2_flowctl_get_action( - grpc_exec_ctx* exec_ctx, grpc_chttp2_transport_flowctl* tfc, - grpc_chttp2_stream_flowctl* sfc) { - grpc_chttp2_flowctl_action action; - memset(&action, 0, sizeof(action)); - uint32_t target_announced_window = grpc_chttp2_target_announced_window(tfc); - if (tfc->announced_window < target_announced_window / 2) { - action.send_transport_update = GRPC_CHTTP2_FLOWCTL_UPDATE_IMMEDIATELY; - } - TRACEACTION(tfc, action); - return action; -} diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index be81d3a97b..21bdbc428e 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -22,6 +22,7 @@ #include #include +#include "src/core/ext/transport/chttp2/transport/http2_settings.h" #include "src/core/lib/support/manual_constructor.h" #include "src/core/lib/transport/bdp_estimator.h" #include "src/core/lib/transport/pid_controller.h" @@ -53,7 +54,12 @@ class FlowControlAction { Urgency send_stream_update() const { return send_stream_update_; } Urgency send_transport_update() const { return send_transport_update_; } - Urgency send_setting_update() const { return send_setting_update_; } + Urgency send_initial_window_update() const { + return send_initial_window_update_; + } + Urgency send_max_frame_size_update() const { + return send_max_frame_size_update_; + } uint32_t initial_window_size() const { return initial_window_size_; } uint32_t max_frame_size() const { return max_frame_size_; } @@ -61,12 +67,20 @@ class FlowControlAction { send_stream_update_ = u; return *this; } - FlowControlAction& send_transport_update(Urgency u) { + FlowControlAction& set_send_transport_update(Urgency u) { send_transport_update_ = u; return *this; } - FlowControlAction& send_setting_update(Urgency u) { - send_setting_update_ = u; + FlowControlAction& set_send_initial_window_update(Urgency u, + uint32_t update) { + send_initial_window_update_ = u; + initial_window_size_ = update; + return *this; + } + FlowControlAction& set_send_max_frame_size_update(Urgency u, + uint32_t update) { + send_max_frame_size_update_ = u; + max_frame_size_ = update; return *this; } @@ -76,7 +90,8 @@ class FlowControlAction { private: Urgency send_stream_update_ = Urgency::NO_ACTION_NEEDED; Urgency send_transport_update_ = Urgency::NO_ACTION_NEEDED; - Urgency send_setting_update_ = Urgency::NO_ACTION_NEEDED; + Urgency send_initial_window_update_ = Urgency::NO_ACTION_NEEDED; + Urgency send_max_frame_size_update_ = Urgency::NO_ACTION_NEEDED; uint32_t initial_window_size_ = 0; uint32_t max_frame_size_ = 0; }; @@ -114,12 +129,16 @@ class FlowControlTrace { class TransportFlowControl { public: + TransportFlowControl(const grpc_chttp2_transport* t); ~TransportFlowControl() { if (pid_controller_initialized_) { pid_controller_.Destroy(); } } + // toggle bdp probing + void SetBdpProbe(bool enable); + // returns an announce if we should send a transport update to our peer, // else returns zero; writing_anyway indicates if a write would happen // regardless of the send - if it is false and this function returns non-zero, @@ -177,10 +196,14 @@ class TransportFlowControl { } } + BdpEstimator* bdp_estimator() { return &bdp_estimator_; } + private: FlowControlAction UpdateForBdp(grpc_exec_ctx* exec_ctx, FlowControlAction action); - double SmoothBdp(grpc_exec_ctx* exec_ctx, double value); + double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value); + FlowControlAction::Urgency DeltaUrgency(int32_t value, + grpc_chttp2_setting_id setting_id); const grpc_chttp2_transport* const t_; @@ -211,26 +234,28 @@ class TransportFlowControl { int32_t target_initial_window_size_ = kDefaultWindow; /** should we probe bdp? */ - bool enable_bdp_probe_; + bool enable_bdp_probe_ = true; /* bdp estimation */ grpc_core::BdpEstimator bdp_estimator_; /* pid controller */ - bool pid_controller_initialized_; + bool pid_controller_initialized_ = false; grpc_core::ManualConstructor pid_controller_; - grpc_millis last_pid_update_; + grpc_millis last_pid_update_ = 0; }; class StreamFlowControl { public: - StreamFlowControl(TransportFlowControl* tfc, grpc_chttp2_stream* s); + StreamFlowControl(TransportFlowControl* tfc, const grpc_chttp2_stream* s); ~StreamFlowControl() { tfc_->PreUpdateAnnouncedWindowOverIncomingWindow(announced_window_delta_); } FlowControlAction UpdateAction(FlowControlAction action); - FlowControlAction MakeAction() { return UpdateAction(FlowControlAction()); } + FlowControlAction MakeAction(grpc_exec_ctx* exec_ctx) { + return UpdateAction(tfc_->MakeAction(exec_ctx)); + } // we have sent data on the wire, we must track this in our bookkeeping for // the remote peer's flow control. @@ -276,16 +301,16 @@ class StreamFlowControl { * window * size of the transport... ie: * remote_window = remote_window_delta + transport.initial_window_size */ - int64_t remote_window_delta_; + int64_t remote_window_delta_ = 0; /** window available for peer to send to us (as a delta on * transport.initial_window_size) * local_window = local_window_delta + transport.initial_window_size */ - int64_t local_window_delta_; + int64_t local_window_delta_ = 0; /** window available for peer to send to us over this stream that we have * announced to the peer */ - int64_t announced_window_delta_; + int64_t announced_window_delta_ = 0; }; } // namespace chttp2 -- cgit v1.2.3 From e3b4d4a8d8849b2d222a0d6408902140b4f67a5d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 19:31:58 -0700 Subject: Fixes --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 6 +++--- src/core/ext/transport/chttp2/transport/flow_control.cc | 1 + src/core/ext/transport/chttp2/transport/flow_control.h | 5 ----- src/core/ext/transport/chttp2/transport/frame_window_update.cc | 10 ++++------ src/core/ext/transport/chttp2/transport/internal.h | 4 ++++ 5 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index a8dfb1ba0c..4edd699ed4 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -2501,8 +2501,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action.parse", 0); GPR_TIMER_BEGIN("post_parse_locked", 0); - if (t->flow_control.initial_window_update != 0) { - if (t->flow_control.initial_window_update > 0) { + if (t->initial_window_update != 0) { + if (t->initial_window_update > 0) { grpc_chttp2_stream *s; while (grpc_chttp2_list_pop_stalled_by_stream(t, &s)) { grpc_chttp2_mark_stream_writable(exec_ctx, t, s); @@ -2511,7 +2511,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GRPC_CHTTP2_INITIATE_WRITE_FLOW_CONTROL_UNSTALLED_BY_SETTING); } } - t->flow_control.initial_window_update = 0; + t->initial_window_update = 0; } GPR_TIMER_END("post_parse_locked", 0); } diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 4deff04b18..7fadc305e2 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -222,6 +222,7 @@ grpc_error* StreamFlowControl::RecvData(int64_t incoming_frame_size) { UpdateAnnouncedWindowDelta(tfc_, -incoming_frame_size); local_window_delta_ -= incoming_frame_size; tfc_->CommitRecvData(incoming_frame_size); + return GRPC_ERROR_NONE; } uint32_t StreamFlowControl::MaybeSendUpdate() { diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 21bdbc428e..212416c7e5 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -207,11 +207,6 @@ class TransportFlowControl { const grpc_chttp2_transport* const t_; - /** initial window change. This is tracked as we parse settings frames from - * the remote peer. If there is a positive delta, then we will make all - * streams readable since they may have become unstalled */ - int64_t initial_window_update_ = 0; - /** Our bookkeeping for the remote peer's available window */ int64_t remote_window_ = kDefaultWindow; diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.cc b/src/core/ext/transport/chttp2/transport/frame_window_update.cc index c9ab8d1b50..15eaf59285 100644 --- a/src/core/ext/transport/chttp2/transport/frame_window_update.cc +++ b/src/core/ext/transport/chttp2/transport/frame_window_update.cc @@ -96,8 +96,7 @@ grpc_error *grpc_chttp2_window_update_parser_parse( if (t->incoming_stream_id != 0) { if (s != NULL) { - grpc_chttp2_flowctl_recv_stream_update( - &t->flow_control, &s->flow_control, received_update); + s->flow_control->RecvUpdate(received_update); if (grpc_chttp2_list_remove_stalled_by_stream(t, s)) { grpc_chttp2_mark_stream_writable(exec_ctx, t, s); grpc_chttp2_initiate_write( @@ -106,10 +105,9 @@ grpc_error *grpc_chttp2_window_update_parser_parse( } } } else { - bool was_zero = t->flow_control.remote_window <= 0; - grpc_chttp2_flowctl_recv_transport_update(&t->flow_control, - received_update); - bool is_zero = t->flow_control.remote_window <= 0; + bool was_zero = t->flow_control->remote_window() <= 0; + t->flow_control->RecvUpdate(received_update); + bool is_zero = t->flow_control->remote_window() <= 0; if (was_zero && !is_zero) { grpc_chttp2_initiate_write( exec_ctx, t, diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 57c4cfa5f3..382201bd7a 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -354,6 +354,10 @@ struct grpc_chttp2_transport { grpc_core::ManualConstructor flow_control; + /** initial window change. This is tracked as we parse settings frames from + * the remote peer. If there is a positive delta, then we will make all + * streams readable since they may have become unstalled */ + int64_t initial_window_update = 0; /* deframing */ grpc_chttp2_deframe_transport_state deframe_state; -- cgit v1.2.3 From 0578154eedd0d32cd99fa43f4bedc9004b069d50 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 9 Oct 2017 19:45:38 -0700 Subject: Fixes --- .../ext/transport/chttp2/transport/flow_control.cc | 5 ++++ .../ext/transport/chttp2/transport/flow_control.h | 5 ++-- .../transport/chttp2/transport/frame_settings.cc | 4 +-- src/core/ext/transport/chttp2/transport/parsing.cc | 17 +++++++------ src/core/ext/transport/chttp2/transport/writing.cc | 29 ++++++++++------------ 5 files changed, 31 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 7fadc305e2..b6f081dd23 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -358,10 +358,15 @@ FlowControlAction TransportFlowControl::UpdateForBdp(grpc_exec_ctx* exec_ctx, frame_size); } } + return action; } FlowControlAction TransportFlowControl::MakeAction(grpc_exec_ctx* exec_ctx) { FlowControlAction action; + if (announced_window_ < target_window() / 2) { + action.set_send_transport_update( + FlowControlAction::Urgency::UPDATE_IMMEDIATELY); + } action = UpdateForBdp(exec_ctx, action); return action; } diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 212416c7e5..6c49723dfa 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -123,8 +123,6 @@ class FlowControlTrace { int64_t remote_window_delta_; int64_t local_window_delta_; int64_t announced_window_delta_; - uint32_t local_init_window_; - uint32_t local_max_frame_; }; class TransportFlowControl { @@ -137,7 +135,8 @@ class TransportFlowControl { } // toggle bdp probing - void SetBdpProbe(bool enable); + // TODO(ctiller): make this safe to dynamically toggle + void SetBdpProbe(bool enable) { enable_bdp_probe_ = enable; } // returns an announce if we should send a transport update to our peer, // else returns zero; writing_anyway indicates if a write would happen diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc index 2995bf7310..db0245bb57 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.cc +++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc @@ -202,13 +202,13 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, } if (id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && parser->incoming_settings[id] != parser->value) { - t->flow_control.initial_window_update += + t->initial_window_update += (int64_t)parser->value - parser->incoming_settings[id]; if (GRPC_TRACER_ON(grpc_http_trace) || GRPC_TRACER_ON(grpc_flowctl_trace)) { gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change", t, t->is_client ? "cli" : "svr", - (int)t->flow_control.initial_window_update); + (int)t->initial_window_update); } } parser->incoming_settings[id] = parser->value; diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc index 78886b497a..2807c154e6 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.cc +++ b/src/core/ext/transport/chttp2/transport/parsing.cc @@ -355,14 +355,15 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); grpc_error *err = GRPC_ERROR_NONE; - err = grpc_chttp2_flowctl_recv_data(&t->flow_control, - s == NULL ? NULL : &s->flow_control, - t->incoming_frame_size); - grpc_chttp2_act_on_flowctl_action( - exec_ctx, - grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, - s == NULL ? NULL : &s->flow_control), - t, s); + grpc_core::chttp2::FlowControlAction action; + if (s == nullptr) { + err = t->flow_control->RecvData(t->incoming_frame_size); + action = t->flow_control->MakeAction(exec_ctx); + } else { + err = s->flow_control->RecvData(t->incoming_frame_size); + action = s->flow_control->MakeAction(exec_ctx); + } + grpc_chttp2_act_on_flowctl_action(exec_ctx, action, t, s); if (err != GRPC_ERROR_NONE) { goto error_handler; } diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 25c1a5ef05..fe82b6fd60 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -146,13 +146,13 @@ static void report_stall(grpc_chttp2_transport *t, grpc_chttp2_stream *s, s->flow_controlled_bytes_flowed, t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], - t->flow_control.remote_window, + t->flow_control->remote_window(), (uint32_t)GPR_MAX( 0, - s->flow_control.remote_window_delta + + s->flow_control->remote_window_delta() + (int64_t)t->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]), - s->flow_control.remote_window_delta); + s->flow_control->remote_window_delta()); } static bool stream_ref_if_not_destroyed(gpr_refcount *r) { @@ -216,8 +216,7 @@ class WriteContext { void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) { uint32_t transport_announce = - grpc_chttp2_flowctl_maybe_send_transport_update(&t_->flow_control, - t_->outbuf.count > 0); + t_->flow_control->MaybeSendUpdate(t_->outbuf.count > 0); if (transport_announce) { grpc_transport_one_way_stats throwaway_stats; grpc_slice_buffer_add( @@ -311,7 +310,7 @@ class DataSendContext { uint32_t stream_remote_window() const { return (uint32_t)GPR_MAX( - 0, s_->flow_control.remote_window_delta + + 0, s_->flow_control->remote_window_delta() + (int64_t)t_->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); } @@ -319,7 +318,7 @@ class DataSendContext { uint32_t max_outgoing() const { return (uint32_t)GPR_MIN( t_->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], - GPR_MIN(stream_remote_window(), t_->flow_control.remote_window)); + GPR_MIN(stream_remote_window(), t_->flow_control->remote_window())); } bool AnyOutgoing() const { return max_outgoing() != 0; } @@ -351,8 +350,7 @@ class DataSendContext { grpc_metadata_batch_is_empty(s_->send_trailing_metadata); grpc_chttp2_encode_data(s_->id, &s_->compressed_data_buffer, send_bytes, is_last_frame_, &s_->stats.outgoing, &t_->outbuf); - grpc_chttp2_flowctl_sent_data(&t_->flow_control, &s_->flow_control, - send_bytes); + s_->flow_control->SentData(send_bytes); if (s_->compressed_data_buffer.length == 0) { s_->sending_bytes += s_->uncompressed_data_size; } @@ -399,8 +397,8 @@ class StreamWriteContext { gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t_, t_->is_client ? "CLIENT" : "SERVER", s->id, s->sent_initial_metadata, s->send_initial_metadata != NULL, - (int)(s->flow_control.local_window_delta - - s->flow_control.announced_window_delta))); + (int)(s->flow_control->local_window_delta() - + s->flow_control->announced_window_delta()))); } void FlushInitialMetadata(grpc_exec_ctx *exec_ctx) { @@ -446,8 +444,7 @@ class StreamWriteContext { void FlushWindowUpdates(grpc_exec_ctx *exec_ctx) { /* send any window updates */ - uint32_t stream_announce = grpc_chttp2_flowctl_maybe_send_stream_update( - &t_->flow_control, &s_->flow_control); + const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate(); if (stream_announce == 0) return; grpc_slice_buffer_add( @@ -468,10 +465,10 @@ class StreamWriteContext { DataSendContext data_send_context(write_context_, t_, s_); if (!data_send_context.AnyOutgoing()) { - if (t_->flow_control.remote_window == 0) { + if (t_->flow_control->remote_window() <= 0) { report_stall(t_, s_, "transport"); grpc_chttp2_list_add_stalled_by_transport(t_, s_); - } else if (data_send_context.stream_remote_window() == 0) { + } else if (data_send_context.stream_remote_window() <= 0) { report_stall(t_, s_, "stream"); grpc_chttp2_list_add_stalled_by_stream(t_, s_); } @@ -587,7 +584,7 @@ grpc_chttp2_begin_write_result grpc_chttp2_begin_write( ctx.FlushQueuedBuffers(exec_ctx); ctx.EnactHpackSettings(exec_ctx); - if (t->flow_control.remote_window > 0) { + if (t->flow_control->remote_window() > 0) { ctx.UpdateStreamsNoLongerStalled(); } -- cgit v1.2.3 From 0ca5d863e1853fd54023ac6c094eaa31e59b949c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 11 Oct 2017 08:55:30 -0700 Subject: Fix leak --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index f6f9242caf..eea7f1f609 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -571,6 +571,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; } + GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); schedule_bdp_ping_locked(exec_ctx, t); grpc_chttp2_act_on_flowctl_action( @@ -2568,7 +2569,6 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); t->flow_control.bdp_estimator->SchedulePing(); send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked, &t->finish_bdp_ping_locked); @@ -2578,7 +2578,8 @@ static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; if (GRPC_TRACER_ON(grpc_http_trace)) { - gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string); + gpr_log(GPR_DEBUG, "%s: Start BDP ping err=%s", t->peer_string, + grpc_error_string(error)); } /* Reset the keepalive ping timer */ if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) { @@ -2591,9 +2592,10 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; if (GRPC_TRACER_ON(grpc_http_trace)) { - gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string); + gpr_log(GPR_DEBUG, "%s: Complete BDP ping err=%s", t->peer_string, + grpc_error_string(error)); } - if (error == GRPC_ERROR_CANCELLED) { + if (error != GRPC_ERROR_NONE) { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); return; } -- cgit v1.2.3 From e94374d0a5a3040ca71392be4c61b17f6ef99030 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 11 Oct 2017 08:55:43 -0700 Subject: Fix leak --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index eea7f1f609..fbd3c328a0 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -2611,7 +2611,7 @@ static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp; GPR_ASSERT(t->have_next_bdp_ping_timer); t->have_next_bdp_ping_timer = false; - if (error == GRPC_ERROR_CANCELLED) { + if (error != GRPC_ERROR_NONE) { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); return; } -- cgit v1.2.3 From a6481f4d73cbba8ca5898160602bf7a972d341b7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 11 Oct 2017 09:13:19 -0700 Subject: Fix uninitialized variable --- src/core/ext/transport/chttp2/transport/flow_control.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index b6f081dd23..b950d63f04 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -67,6 +67,7 @@ void FlowControlTrace::Init(const char* reason, TransportFlowControl* tfc, StreamFlowControl* sfc) { tfc_ = tfc; sfc_ = sfc; + reason_ = reason; remote_window_ = tfc->remote_window(); target_window_ = tfc->target_window(); announced_window_ = tfc->announced_window(); -- cgit v1.2.3 From bfec10fdcf00a6fdb196b29b3b759a3e113fc66b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 11 Oct 2017 17:31:06 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.cc | 13 ++++++------- src/core/lib/iomgr/ev_posix.cc | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index a44cdb8597..53e214db37 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -927,10 +927,10 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, #define WORKER_PTR (&worker) #endif if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRIdPTR " deadline=%" PRIdPTR " kwp=%d pollable=%p", - pollset, worker_hdl, WORKER_PTR,grpc_exec_ctx_now(exec_ctx), - deadline, pollset->kicked_without_poller, - pollset->active_pollable); + gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRIdPTR + " deadline=%" PRIdPTR " kwp=%d pollable=%p", + pollset, worker_hdl, WORKER_PTR, grpc_exec_ctx_now(exec_ctx), + deadline, pollset->kicked_without_poller, pollset->active_pollable); } static const char *err_desc = "pollset_work"; grpc_error *error = GRPC_ERROR_NONE; @@ -943,9 +943,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, GPR_ASSERT(!pollset->shutdown_closure); gpr_mu_unlock(&pollset->mu); if (pollset->event_cursor == pollset->event_count) { - append_error(&error, - pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, - deadline), + append_error(&error, pollset_epoll(exec_ctx, pollset, + WORKER_PTR->pollable_obj, deadline), err_desc); } append_error(&error, pollset_process_events(exec_ctx, pollset, false), diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc index 5656ebb340..86eae5f95b 100644 --- a/src/core/lib/iomgr/ev_posix.cc +++ b/src/core/lib/iomgr/ev_posix.cc @@ -81,8 +81,7 @@ const grpc_event_engine_vtable *init_non_polling(bool explicit_request) { static const event_engine_factory g_factories[] = { {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux}, {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix}, - {"poll-cv", grpc_init_poll_cv_posix}, - {"none", init_non_polling}, + {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling}, }; static void add(const char *beg, const char *end, char ***ss, size_t *ns) { -- cgit v1.2.3 From 79c4f1fb141762272d72eea5f3a5c39bb3bb0043 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 01:12:40 +0000 Subject: Fix use after free --- src/core/lib/iomgr/ev_epollex_linux.cc | 59 ++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 53e214db37..a3de936eb9 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -1172,34 +1172,6 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, gpr_mu_unlock(&pss->mu); } -static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, - grpc_pollset_set *pss, grpc_pollset *ps) { - if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps); - } - grpc_error *error = GRPC_ERROR_NONE; - static const char *err_desc = "pollset_set_add_pollset"; - pollable *pollable_obj = NULL; - if (!GRPC_LOG_IF_ERROR( - err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { - GPR_ASSERT(pollable_obj == NULL); - return; - } - pss = pss_lock_adam(pss); - for (size_t i = 0; i < pss->fd_count; i++) { - append_error(&error, pollable_add_fd(pollable_obj, pss->fds[i]), err_desc); - } - if (pss->pollset_count == pss->pollset_capacity) { - pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); - pss->pollsets = (pollable **)gpr_realloc( - pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets)); - } - pss->pollsets[pss->pollset_count++] = pollable_obj; - gpr_mu_unlock(&pss->mu); - - GRPC_LOG_IF_ERROR(err_desc, error); -} - static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, grpc_pollset *ps) { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -1244,6 +1216,37 @@ static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, return error; } +static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, + grpc_pollset_set *pss, grpc_pollset *ps) { + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps); + } + grpc_error *error = GRPC_ERROR_NONE; + static const char *err_desc = "pollset_set_add_pollset"; + pollable *pollable_obj = NULL; + if (!GRPC_LOG_IF_ERROR( + err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { + GPR_ASSERT(pollable_obj == NULL); + return; + } + pss = pss_lock_adam(pss); + size_t initial_fd_count = pss->fd_count; + pss->fd_count = 0; + append_error(&error, add_fds_to_pollables( + exec_ctx, pss->fds, initial_fd_count, &pollable_obj, + 1, err_desc, pss->fds, &pss->fd_count), + err_desc); + if (pss->pollset_count == pss->pollset_capacity) { + pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); + pss->pollsets = (pollable **)gpr_realloc( + pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets)); + } + pss->pollsets[pss->pollset_count++] = pollable_obj; + gpr_mu_unlock(&pss->mu); + + GRPC_LOG_IF_ERROR(err_desc, error); +} + static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, grpc_pollset_set *a, grpc_pollset_set *b) { -- cgit v1.2.3 From 85516af26ae38d8f628d70a4bf30c7e7c29a99b1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 11 Oct 2017 18:16:21 -0700 Subject: Fix tests --- .../transport/chttp2/transport/chttp2_transport.cc | 54 ++++++++++++++-------- src/core/ext/transport/chttp2/transport/internal.h | 10 ++-- src/core/ext/transport/chttp2/transport/writing.cc | 3 +- test/core/end2end/bad_server_response_test.c | 6 +-- test/core/end2end/tests/bad_ping.c | 3 +- test/core/end2end/tests/keepalive_timeout.c | 2 +- test/core/end2end/tests/max_connection_age.c | 3 +- test/core/end2end/tests/shutdown_finishes_calls.c | 2 +- 8 files changed, 49 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index fbd3c328a0..659208ccf0 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -224,6 +224,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, t->flow_control.bdp_estimator.Destroy(); + GRPC_ERROR_UNREF(t->closed_with_error); gpr_free(t->ping_acks); gpr_free(t->peer_string); gpr_free(t); @@ -571,8 +572,10 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; } - GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); - schedule_bdp_ping_locked(exec_ctx, t); + if (t->flow_control.enable_bdp_probe) { + GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); + schedule_bdp_ping_locked(exec_ctx, t); + } grpc_chttp2_act_on_flowctl_action( exec_ctx, @@ -607,7 +610,9 @@ static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { - if (!t->closed) { + end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); + cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); + if (t->closed_with_error == nullptr) { if (!grpc_error_has_clear_grpc_status(error)) { error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); @@ -622,10 +627,10 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_error_add_child(t->close_transport_on_writes_finished, error); return; } - t->closed = 1; + GPR_ASSERT(error != GRPC_ERROR_NONE); + t->closed_with_error = GRPC_ERROR_REF(error); connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), "close_transport"); - grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error)); if (t->ping_state.is_delayed_ping_timer_set) { grpc_timer_cancel(exec_ctx, &t->ping_state.delayed_ping_timer); } @@ -651,8 +656,9 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, while (grpc_chttp2_list_pop_writable_stream(t, &s)) { GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); } - end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); - cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); + if (t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE) { + grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error)); + } } GRPC_ERROR_UNREF(error); } @@ -848,6 +854,10 @@ static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->close_transport_on_writes_finished = NULL; close_transport_locked(exec_ctx, t, err); } + if (t->closed_with_error != GRPC_ERROR_NONE) { + grpc_endpoint_shutdown(exec_ctx, t->ep, + GRPC_ERROR_REF(t->closed_with_error)); + } } } @@ -955,7 +965,8 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, void grpc_chttp2_mark_stream_writable(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s) { - if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) { + if (t->closed_with_error == GRPC_ERROR_NONE && + grpc_chttp2_list_add_writable_stream(t, s)) { GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become"); } } @@ -1008,7 +1019,7 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt, grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE); grpc_chttp2_begin_write_result r; - if (t->closed) { + if (t->closed_with_error != GRPC_ERROR_NONE) { r.writing = false; } else { r = grpc_chttp2_begin_write(exec_ctx, t); @@ -1471,7 +1482,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, } if (!s->write_closed) { if (t->is_client) { - if (!t->closed) { + if (t->closed_with_error == GRPC_ERROR_NONE) { GPR_ASSERT(s->id == 0); grpc_chttp2_list_add_waiting_for_concurrency(t, s); maybe_start_some_streams(exec_ctx, t); @@ -1479,7 +1490,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_chttp2_cancel_stream( exec_ctx, t, s, grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"), + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Transport closed", &t->closed_with_error, 1), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } else { @@ -1768,7 +1780,10 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); /*The transport will be closed after the write is done */ close_transport_locked( - exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings")); + exec_ctx, t, + grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), + GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); } } @@ -2496,7 +2511,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, } GPR_SWAP(grpc_error *, err, error); GRPC_ERROR_UNREF(err); - if (!t->closed) { + if (t->closed_with_error == GRPC_ERROR_NONE) { GPR_TIMER_BEGIN("reading_action.parse", 0); size_t i = 0; grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, @@ -2536,13 +2551,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_BEGIN("post_reading_action_locked", 0); bool keep_reading = false; - if (error == GRPC_ERROR_NONE && t->closed) { - error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"); + if (error == GRPC_ERROR_NONE && t->closed_with_error != GRPC_ERROR_NONE) { + error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Transport closed", &t->closed_with_error, 1); } if (error != GRPC_ERROR_NONE) { close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); t->endpoint_reading = 0; - } else if (!t->closed) { + } else if (t->closed_with_error == GRPC_ERROR_NONE) { keep_reading = true; GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading"); } @@ -2680,7 +2696,7 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg; GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING); - if (t->destroying || t->closed) { + if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; } else if (error == GRPC_ERROR_NONE) { if (t->keepalive_permit_without_calls || @@ -2738,8 +2754,8 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg, if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (error == GRPC_ERROR_NONE) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; - close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "keepalive watchdog timeout")); + close_transport_locked(exec_ctx, t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "keepalive watchdog timeout"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); } } else { /* The watchdog timer should have been cancelled by diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 739da497c1..703f3ba348 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -298,7 +298,7 @@ struct grpc_chttp2_transport { /** is the transport destroying itself? */ uint8_t destroying; /** has the upper layer closed the transport? */ - uint8_t closed; + grpc_error *closed_with_error; /** is there a read request to the endpoint outstanding? */ uint8_t endpoint_reading; @@ -340,7 +340,7 @@ struct grpc_chttp2_transport { /** hpack encoding */ grpc_chttp2_hpack_compressor hpack_compressor; /** is this a client? */ - uint8_t is_client; + bool is_client; /** data to write next write */ grpc_slice_buffer qbuf; @@ -350,14 +350,14 @@ struct grpc_chttp2_transport { uint32_t write_buffer_size; /** have we seen a goaway */ - uint8_t seen_goaway; + bool seen_goaway; /** have we sent a goaway */ grpc_chttp2_sent_goaway_state sent_goaway_state; /** are the local settings dirty and need to be sent? */ - uint8_t dirtied_local_settings; + bool dirtied_local_settings; /** have local settings been sent? */ - uint8_t sent_local_settings; + bool sent_local_settings; /** bitmask of setting indexes to send out */ uint32_t force_send_settings; /** settings values */ diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 25c1a5ef05..c6fecf2ee9 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -245,7 +245,8 @@ class WriteContext { void UpdateStreamsNoLongerStalled() { grpc_chttp2_stream *s; while (grpc_chttp2_list_pop_stalled_by_transport(t_, &s)) { - if (!t_->closed && grpc_chttp2_list_add_writable_stream(t_, s)) { + if (t_->closed_with_error == GRPC_ERROR_NONE && + grpc_chttp2_list_add_writable_stream(t_, s)) { if (!stream_ref_if_not_destroyed(&s->refcount->refs)) { grpc_chttp2_list_remove_writable_stream(t_, s); } diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c index eeabc769d3..554d8aa45b 100644 --- a/test/core/end2end/bad_server_response_test.c +++ b/test/core/end2end/bad_server_response_test.c @@ -62,8 +62,6 @@ #define HTTP2_DETAIL_MSG(STATUS_CODE) \ "Received http2 header with status: " #STATUS_CODE -#define UNPARSEABLE_DETAIL_MSG "Failed parsing HTTP/2" - #define HTTP1_DETAIL_MSG "Trying to connect an http1.x server" /* TODO(zyc) Check the content of incomming data instead of using this length */ @@ -208,8 +206,10 @@ static void start_rpc(int target_port, grpc_status_code expected_status, cq_verify(cqv); GPR_ASSERT(status == expected_status); + if (expected_detail != NULL) { GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( expected_detail))); + } grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv); @@ -331,7 +331,7 @@ int main(int argc, char **argv) { /* unparseable response */ run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, - GRPC_STATUS_UNAVAILABLE, UNPARSEABLE_DETAIL_MSG); + GRPC_STATUS_UNKNOWN, NULL); /* http1 response */ run_test(HTTP1_RESP, sizeof(HTTP1_RESP) - 1, GRPC_STATUS_UNAVAILABLE, diff --git a/test/core/end2end/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c index d442f12480..56c76b70d0 100644 --- a/test/core/end2end/tests/bad_ping.c +++ b/test/core/end2end/tests/bad_ping.c @@ -202,8 +202,7 @@ static void test_bad_ping(grpc_end2end_test_config config) { // The connection should be closed immediately after the misbehaved pings, // the in-progress RPC should fail. - GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); - GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed")); + GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c index c4280149c7..0053368ecc 100644 --- a/test/core/end2end/tests/keepalive_timeout.c +++ b/test/core/end2end/tests/keepalive_timeout.c @@ -193,7 +193,7 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { char *details_str = grpc_slice_to_c_string(details); char *method_str = grpc_slice_to_c_string(call_details.method); - GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); + GPR_ASSERT(status == GRPC_STATUS_INTERNAL); GPR_ASSERT(0 == grpc_slice_str_cmp(details, "keepalive watchdog timeout")); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, diff --git a/test/core/end2end/tests/max_connection_age.c b/test/core/end2end/tests/max_connection_age.c index 4119087619..b6daa59d7b 100644 --- a/test/core/end2end/tests/max_connection_age.c +++ b/test/core/end2end/tests/max_connection_age.c @@ -203,8 +203,7 @@ static void test_max_age_forcibly_close(grpc_end2end_test_config config) { /* The connection should be closed immediately after the max age grace period, the in-progress RPC should fail. */ - GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); - GPR_ASSERT(0 == grpc_slice_str_cmp(details, "Endpoint read failed")); + GPR_ASSERT(status == GRPC_STATUS_INTERNAL); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c index cef571b490..652695cfcd 100644 --- a/test/core/end2end/tests/shutdown_finishes_calls.c +++ b/test/core/end2end/tests/shutdown_finishes_calls.c @@ -159,7 +159,7 @@ static void test_early_server_shutdown_finishes_inflight_calls( grpc_server_destroy(f.server); - GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); + GPR_ASSERT(status == GRPC_STATUS_INTERNAL || status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); -- cgit v1.2.3 From 3ca9115c2a030bf613b3c962985398445ab13e3e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 09:09:54 -0700 Subject: Fix sanity --- src/core/lib/iomgr/ev_epollex_linux.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index a3de936eb9..8ec0947946 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -1232,9 +1232,9 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, pss = pss_lock_adam(pss); size_t initial_fd_count = pss->fd_count; pss->fd_count = 0; - append_error(&error, add_fds_to_pollables( - exec_ctx, pss->fds, initial_fd_count, &pollable_obj, - 1, err_desc, pss->fds, &pss->fd_count), + append_error(&error, add_fds_to_pollables(exec_ctx, pss->fds, + initial_fd_count, &pollable_obj, 1, + err_desc, pss->fds, &pss->fd_count), err_desc); if (pss->pollset_count == pss->pollset_capacity) { pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); -- cgit v1.2.3 From ad059f70f8bccee3ae1a0ef1568c8d89c0c1004d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 22:47:05 +0000 Subject: Fix threading --- include/grpc/support/sync.h | 18 ++++++- src/core/lib/iomgr/ev_epollex_linux.cc | 85 +++++++++++++++++----------------- 2 files changed, 60 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h index fe8a59a5d6..3e3f1925ce 100644 --- a/include/grpc/support/sync.h +++ b/include/grpc/support/sync.h @@ -274,7 +274,23 @@ GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c); #endif /* 0 */ #ifdef __cplusplus -} +} // extern "C" + +namespace grpc_core { + +class mu_guard { +public: + mu_guard(gpr_mu *mu) : mu_(mu) { gpr_mu_lock(mu); } + ~mu_guard() { gpr_mu_unlock(mu_); } + + mu_guard(const mu_guard&) = delete; + mu_guard& operator=(const mu_guard&) = delete; + +private: + gpr_mu* const mu_; +}; + +} // namespace grpc_core #endif #endif /* GRPC_SUPPORT_SYNC_H */ diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 8ec0947946..bc2e665f06 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -24,6 +24,7 @@ #include "src/core/lib/iomgr/ev_epollex_linux.h" #include +#include #include #include #include @@ -165,6 +166,7 @@ typedef enum { PWLINK_POLLABLE = 0, PWLINK_POLLSET, PWLINK_COUNT } pwlinks; struct grpc_pollset_worker { bool kicked; bool initialized_cv; + pid_t originator; gpr_cv cv; grpc_pollset *pollset; pollable *pollable_obj; @@ -181,6 +183,7 @@ struct grpc_pollset { bool kicked_without_poller; grpc_closure *shutdown_closure; grpc_pollset_worker *root_worker; + int containing_pollset_set_count; int event_cursor; int event_count; @@ -542,39 +545,42 @@ static void pollset_global_shutdown(void) { static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL) { + if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && pollset->containing_pollset_set_count == 0) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); pollset->shutdown_closure = NULL; } } -/* both pollset->active_pollable->mu, pollset->mu must be held before calling - * this function */ +/* pollset->mu must be held before calling this function, pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be held */ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { pollable *p = specific_worker->pollable_obj; + grpc_core::mu_guard lock(&p->mu); GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); } return GRPC_ERROR_NONE; - } else if (gpr_tls_get(&g_current_thread_worker) == + } + if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); } specific_worker->kicked = true; return GRPC_ERROR_NONE; - } else if (specific_worker == p->root_worker) { + } +if (specific_worker == p->root_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); } specific_worker->kicked = true; - return grpc_wakeup_fd_wakeup(&p->wakeup); - } else { - GPR_ASSERT(specific_worker->initialized_cv); + grpc_error *error = grpc_wakeup_fd_wakeup(&p->wakeup); + return error; + } +if (specific_worker->initialized_cv) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); } @@ -582,13 +588,12 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, gpr_cv_signal(&specific_worker->cv); return GRPC_ERROR_NONE; } + // we can get here during end_worker after removing specific_worker from the pollable list but before removing it from the pollset list + return GRPC_ERROR_NONE; } -/* both pollset->active_pollable->mu, pollset->mu must be held before calling - * this function */ -static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - grpc_pollset_worker *specific_worker) { +static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, + grpc_pollset_worker *specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p", @@ -619,21 +624,10 @@ static grpc_error *pollset_kick_inner(grpc_exec_ctx *exec_ctx, } } -static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - grpc_pollset_worker *specific_worker) { - pollable *p = pollset->active_pollable; - gpr_mu_lock(&p->mu); - grpc_error *error = pollset_kick_inner(exec_ctx, pollset, specific_worker); - gpr_mu_unlock(&p->mu); - return error; -} - static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - pollable *p = pollset->active_pollable; grpc_error *error = GRPC_ERROR_NONE; const char *err_desc = "pollset_kick_all"; - gpr_mu_lock(&p->mu); grpc_pollset_worker *w = pollset->root_worker; if (w != NULL) { do { @@ -641,7 +635,6 @@ static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, w = w->links[PWLINK_POLLSET].next; } while (w != pollset->root_worker); } - gpr_mu_unlock(&p->mu); return error; } @@ -855,6 +848,7 @@ static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, PWLINK_POLLABLE)) { worker->initialized_cv = true; gpr_cv_init(&worker->cv); + gpr_mu_unlock(&pollset->mu); if (GRPC_TRACER_ON(grpc_polling_trace) && worker->pollable_obj->root_worker != worker) { gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset, @@ -882,11 +876,13 @@ static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } } grpc_exec_ctx_invalidate_now(exec_ctx); + } else { + gpr_mu_unlock(&pollset->mu); } gpr_mu_unlock(&worker->pollable_obj->mu); - return do_poll && pollset->shutdown_closure == NULL && - pollset->active_pollable == worker->pollable_obj; + return do_poll; +// && pollset->shutdown_closure == NULL && pollset->active_pollable == worker->pollable_obj; } static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, @@ -899,18 +895,19 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, GPR_ASSERT(new_root->initialized_cv); gpr_cv_signal(&new_root->cv); } + gpr_mu_unlock(&worker->pollable_obj->mu); + POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); + gpr_mu_lock(&pollset->mu); + if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET) == WRR_EMPTIED) { + pollset_maybe_finish_shutdown(exec_ctx, pollset); + } if (worker->initialized_cv) { gpr_cv_destroy(&worker->cv); } - if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET)) { - gpr_mu_unlock(&worker->pollable_obj->mu); - pollset_maybe_finish_shutdown(exec_ctx, pollset); - } else { - gpr_mu_unlock(&worker->pollable_obj->mu); - } - POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); } +static long gettid(void) { return syscall(__NR_gettid); } + /* 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 @@ -926,6 +923,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker worker; #define WORKER_PTR (&worker) #endif + WORKER_PTR->originator = gettid(); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRIdPTR " deadline=%" PRIdPTR " kwp=%d pollable=%p", @@ -940,8 +938,6 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (begin_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl, deadline)) { gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); - GPR_ASSERT(!pollset->shutdown_closure); - gpr_mu_unlock(&pollset->mu); if (pollset->event_cursor == pollset->event_count) { append_error(&error, pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, deadline), @@ -950,7 +946,6 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, append_error(&error, pollset_process_events(exec_ctx, pollset, false), err_desc); grpc_exec_ctx_flush(exec_ctx); - gpr_mu_lock(&pollset->mu); gpr_tls_set(&g_current_thread_pollset, 0); gpr_tls_set(&g_current_thread_worker, 0); } @@ -1044,11 +1039,10 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, return error; } -static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, +static grpc_error *pollset_as_multipollable_locked(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollable **pollable_obj) { grpc_error *error = GRPC_ERROR_NONE; - gpr_mu_lock(&pollset->mu); pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable"); switch (pollset->active_pollable->type) { @@ -1079,7 +1073,6 @@ static grpc_error *pollset_as_multipollable(grpc_exec_ctx *exec_ctx, *pollable_obj = POLLABLE_REF(pollset->active_pollable, "pollset_set"); POLLABLE_UNREF(po_at_start, "pollset_as_multipollable"); } - gpr_mu_unlock(&pollset->mu); return error; } @@ -1191,6 +1184,11 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, } pss->pollset_count--; gpr_mu_unlock(&pss->mu); + gpr_mu_lock(&ps->mu); + if (0 == --ps->containing_pollset_set_count) { + pollset_maybe_finish_shutdown(exec_ctx, ps); + } + gpr_mu_unlock(&ps->mu); } // add all fds to pollables, and output a new array of unorphaned out_fds @@ -1224,11 +1222,15 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_pollset"; pollable *pollable_obj = NULL; +gpr_mu_lock(&ps->mu); if (!GRPC_LOG_IF_ERROR( - err_desc, pollset_as_multipollable(exec_ctx, ps, &pollable_obj))) { + err_desc, pollset_as_multipollable_locked(exec_ctx, ps, &pollable_obj))) { GPR_ASSERT(pollable_obj == NULL); +gpr_mu_unlock(&ps->mu); return; } +ps->containing_pollset_set_count++; +gpr_mu_unlock(&ps->mu); pss = pss_lock_adam(pss); size_t initial_fd_count = pss->fd_count; pss->fd_count = 0; @@ -1311,7 +1313,6 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } memcpy(a->pollsets + a->pollset_count, b->pollsets, b->pollset_count * sizeof(*b->pollsets)); - a->fd_count += b->fd_count; a->pollset_count += b->pollset_count; gpr_free(b->fds); gpr_free(b->pollsets); -- cgit v1.2.3 From 1e8c2ab769129b1d4e43cdbc1af89eb0082741fd Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 15:50:13 -0700 Subject: clang-format --- include/grpc/support/sync.h | 14 +++++------ src/core/lib/iomgr/ev_epollex_linux.cc | 43 +++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h index 3e3f1925ce..ddb85808c7 100644 --- a/include/grpc/support/sync.h +++ b/include/grpc/support/sync.h @@ -274,23 +274,23 @@ GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c); #endif /* 0 */ #ifdef __cplusplus -} // extern "C" +} // extern "C" namespace grpc_core { class mu_guard { -public: + public: mu_guard(gpr_mu *mu) : mu_(mu) { gpr_mu_lock(mu); } ~mu_guard() { gpr_mu_unlock(mu_); } - mu_guard(const mu_guard&) = delete; - mu_guard& operator=(const mu_guard&) = delete; + mu_guard(const mu_guard &) = delete; + mu_guard &operator=(const mu_guard &) = delete; -private: - gpr_mu* const mu_; + private: + gpr_mu *const mu_; }; -} // namespace grpc_core +} // namespace grpc_core #endif #endif /* GRPC_SUPPORT_SYNC_H */ diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index bc2e665f06..12004127be 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -24,13 +24,13 @@ #include "src/core/lib/iomgr/ev_epollex_linux.h" #include -#include #include #include #include #include #include #include +#include #include #include @@ -545,13 +545,16 @@ static void pollset_global_shutdown(void) { static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { - if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && pollset->containing_pollset_set_count == 0) { + if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && + pollset->containing_pollset_set_count == 0) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); pollset->shutdown_closure = NULL; } } -/* pollset->mu must be held before calling this function, pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be held */ +/* pollset->mu must be held before calling this function, + * pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be + * held */ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *specific_worker) { @@ -564,15 +567,14 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, } return GRPC_ERROR_NONE; } - if (gpr_tls_get(&g_current_thread_worker) == - (intptr_t)specific_worker) { + if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); } specific_worker->kicked = true; return GRPC_ERROR_NONE; - } -if (specific_worker == p->root_worker) { + } + if (specific_worker == p->root_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); } @@ -580,7 +582,7 @@ if (specific_worker == p->root_worker) { grpc_error *error = grpc_wakeup_fd_wakeup(&p->wakeup); return error; } -if (specific_worker->initialized_cv) { + if (specific_worker->initialized_cv) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); } @@ -588,7 +590,8 @@ if (specific_worker->initialized_cv) { gpr_cv_signal(&specific_worker->cv); return GRPC_ERROR_NONE; } - // we can get here during end_worker after removing specific_worker from the pollable list but before removing it from the pollset list + // we can get here during end_worker after removing specific_worker from the + // pollable list but before removing it from the pollset list return GRPC_ERROR_NONE; } @@ -882,7 +885,8 @@ static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_unlock(&worker->pollable_obj->mu); return do_poll; -// && pollset->shutdown_closure == NULL && pollset->active_pollable == worker->pollable_obj; + // && pollset->shutdown_closure == NULL && pollset->active_pollable == + // worker->pollable_obj; } static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, @@ -898,7 +902,8 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_unlock(&worker->pollable_obj->mu); POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); gpr_mu_lock(&pollset->mu); - if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET) == WRR_EMPTIED) { + if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET) == + WRR_EMPTIED) { pollset_maybe_finish_shutdown(exec_ctx, pollset); } if (worker->initialized_cv) { @@ -1040,8 +1045,8 @@ static grpc_error *pollset_add_fd_locked(grpc_exec_ctx *exec_ctx, } static grpc_error *pollset_as_multipollable_locked(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - pollable **pollable_obj) { + grpc_pollset *pollset, + pollable **pollable_obj) { grpc_error *error = GRPC_ERROR_NONE; pollable *po_at_start = POLLABLE_REF(pollset->active_pollable, "pollset_as_multipollable"); @@ -1222,15 +1227,15 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, grpc_error *error = GRPC_ERROR_NONE; static const char *err_desc = "pollset_set_add_pollset"; pollable *pollable_obj = NULL; -gpr_mu_lock(&ps->mu); - if (!GRPC_LOG_IF_ERROR( - err_desc, pollset_as_multipollable_locked(exec_ctx, ps, &pollable_obj))) { + gpr_mu_lock(&ps->mu); + if (!GRPC_LOG_IF_ERROR(err_desc, pollset_as_multipollable_locked( + exec_ctx, ps, &pollable_obj))) { GPR_ASSERT(pollable_obj == NULL); -gpr_mu_unlock(&ps->mu); + gpr_mu_unlock(&ps->mu); return; } -ps->containing_pollset_set_count++; -gpr_mu_unlock(&ps->mu); + ps->containing_pollset_set_count++; + gpr_mu_unlock(&ps->mu); pss = pss_lock_adam(pss); size_t initial_fd_count = pss->fd_count; pss->fd_count = 0; -- cgit v1.2.3 From 1c3dd002b9c1af714dc45050f49e9fd59e384abc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 16:08:56 -0700 Subject: Be consistent with Java --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 2 +- test/core/end2end/tests/bad_ping.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 659208ccf0..abc30022c0 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -1783,7 +1783,7 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, exec_ctx, t, grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), - GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } diff --git a/test/core/end2end/tests/bad_ping.c b/test/core/end2end/tests/bad_ping.c index 56c76b70d0..34cc8e78cd 100644 --- a/test/core/end2end/tests/bad_ping.c +++ b/test/core/end2end/tests/bad_ping.c @@ -202,7 +202,7 @@ static void test_bad_ping(grpc_end2end_test_config config) { // The connection should be closed immediately after the misbehaved pings, // the in-progress RPC should fail. - GPR_ASSERT(status == GRPC_STATUS_RESOURCE_EXHAUSTED); + GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); -- cgit v1.2.3 From b278bc701810a790d9a00486cb997abb099a47dc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 19:01:46 -0700 Subject: First attempt at periodic updates to flow control --- .../transport/chttp2/transport/chttp2_transport.cc | 32 ++++++++++++---------- .../ext/transport/chttp2/transport/flow_control.cc | 17 +++--------- .../ext/transport/chttp2/transport/flow_control.h | 20 ++++++++++---- src/core/ext/transport/chttp2/transport/parsing.cc | 4 +-- 4 files changed, 38 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 7815ff123e..6ff3ec280e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -565,13 +565,13 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; } - if (t->flow_control.enable_bdp_probe) { + if (t->flow_control->bdp_probe()) { GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); schedule_bdp_ping_locked(exec_ctx, t); } grpc_chttp2_act_on_flowctl_action( - exec_ctx, t->flow_control->MakeAction(exec_ctx), t, NULL); + exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, NULL); grpc_chttp2_initiate_write(exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); @@ -1636,8 +1636,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, already_received = s->frame_storage.length; s->flow_control->IncomingByteStreamUpdate(GRPC_HEADER_SIZE_IN_BYTES, already_received); - grpc_chttp2_act_on_flowctl_action( - exec_ctx, s->flow_control->MakeAction(exec_ctx), t, s); + grpc_chttp2_act_on_flowctl_action(exec_ctx, + s->flow_control->MakeAction(), t, s); } } grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); @@ -1768,10 +1768,9 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); /*The transport will be closed after the write is done */ close_transport_locked( - exec_ctx, t, - grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); + exec_ctx, t, grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } @@ -2550,8 +2549,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, if (keep_reading) { grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_locked); - grpc_chttp2_act_on_flowctl_action( - exec_ctx, t->flow_control->MakeAction(exec_ctx), t, NULL); + grpc_chttp2_act_on_flowctl_action(exec_ctx, t->flow_control->MakeAction(), + t, NULL); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); @@ -2598,6 +2597,8 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, } grpc_millis next_ping = t->flow_control->bdp_estimator()->CompletePing(exec_ctx); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, nullptr); GPR_ASSERT(!t->have_next_bdp_ping_timer); t->have_next_bdp_ping_timer = true; grpc_timer_init(exec_ctx, &t->next_bdp_ping_timer, next_ping, @@ -2736,8 +2737,11 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg, if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (error == GRPC_ERROR_NONE) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; - close_transport_locked(exec_ctx, t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "keepalive watchdog timeout"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); + close_transport_locked( + exec_ctx, t, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "keepalive watchdog timeout"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); } } else { /* The watchdog timer should have been cancelled by @@ -2822,8 +2826,8 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, if (!s->read_closed) { s->flow_control->IncomingByteStreamUpdate(bs->next_action.max_size_hint, cur_length); - grpc_chttp2_act_on_flowctl_action( - exec_ctx, s->flow_control->MakeAction(exec_ctx), t, s); + grpc_chttp2_act_on_flowctl_action(exec_ctx, s->flow_control->MakeAction(), + t, s); } GPR_ASSERT(s->unprocessed_incoming_frames_buffer.length == 0); if (s->frame_storage.length > 0) { diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index b950d63f04..3b39eb2fdf 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -321,8 +321,9 @@ FlowControlAction::Urgency TransportFlowControl::DeltaUrgency( } } -FlowControlAction TransportFlowControl::UpdateForBdp(grpc_exec_ctx* exec_ctx, - FlowControlAction action) { +FlowControlAction TransportFlowControl::PeriodicUpdate( + grpc_exec_ctx* exec_ctx) { + FlowControlAction action; if (enable_bdp_probe_) { // get bdp estimate and update initial_window accordingly. int64_t estimate = -1; @@ -359,17 +360,7 @@ FlowControlAction TransportFlowControl::UpdateForBdp(grpc_exec_ctx* exec_ctx, frame_size); } } - return action; -} - -FlowControlAction TransportFlowControl::MakeAction(grpc_exec_ctx* exec_ctx) { - FlowControlAction action; - if (announced_window_ < target_window() / 2) { - action.set_send_transport_update( - FlowControlAction::Urgency::UPDATE_IMMEDIATELY); - } - action = UpdateForBdp(exec_ctx, action); - return action; + return UpdateAction(action); } FlowControlAction StreamFlowControl::UpdateAction(FlowControlAction action) { diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 6c49723dfa..13a3341122 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -138,6 +138,8 @@ class TransportFlowControl { // TODO(ctiller): make this safe to dynamically toggle void SetBdpProbe(bool enable) { enable_bdp_probe_ = enable; } + bool bdp_probe() const { return enable_bdp_probe_; } + // returns an announce if we should send a transport update to our peer, // else returns zero; writing_anyway indicates if a write would happen // regardless of the send - if it is false and this function returns non-zero, @@ -146,7 +148,7 @@ class TransportFlowControl { // Reads the flow control data and returns and actionable struct that will // tell chttp2 exactly what it needs to do - FlowControlAction MakeAction(grpc_exec_ctx* exec_ctx); + FlowControlAction MakeAction() { return UpdateAction(FlowControlAction()); } void StreamSentData(int64_t size) { remote_window_ -= size; } @@ -197,13 +199,21 @@ class TransportFlowControl { BdpEstimator* bdp_estimator() { return &bdp_estimator_; } + FlowControlAction PeriodicUpdate(grpc_exec_ctx* exec_ctx); + private: - FlowControlAction UpdateForBdp(grpc_exec_ctx* exec_ctx, - FlowControlAction action); double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value); FlowControlAction::Urgency DeltaUrgency(int32_t value, grpc_chttp2_setting_id setting_id); + FlowControlAction UpdateAction(FlowControlAction action) { + if (announced_window_ < target_window() / 2) { + action.set_send_transport_update( + FlowControlAction::Urgency::UPDATE_IMMEDIATELY); + } + return action; + } + const grpc_chttp2_transport* const t_; /** Our bookkeeping for the remote peer's available window */ @@ -247,9 +257,7 @@ class StreamFlowControl { } FlowControlAction UpdateAction(FlowControlAction action); - FlowControlAction MakeAction(grpc_exec_ctx* exec_ctx) { - return UpdateAction(tfc_->MakeAction(exec_ctx)); - } + FlowControlAction MakeAction() { return UpdateAction(tfc_->MakeAction()); } // we have sent data on the wire, we must track this in our bookkeeping for // the remote peer's flow control. diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc index 2807c154e6..ace71f8b4d 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.cc +++ b/src/core/ext/transport/chttp2/transport/parsing.cc @@ -358,10 +358,10 @@ static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, grpc_core::chttp2::FlowControlAction action; if (s == nullptr) { err = t->flow_control->RecvData(t->incoming_frame_size); - action = t->flow_control->MakeAction(exec_ctx); + action = t->flow_control->MakeAction(); } else { err = s->flow_control->RecvData(t->incoming_frame_size); - action = s->flow_control->MakeAction(exec_ctx); + action = s->flow_control->MakeAction(); } grpc_chttp2_act_on_flowctl_action(exec_ctx, action, t, s); if (err != GRPC_ERROR_NONE) { -- cgit v1.2.3 From 3273648a87a34a166f7ef83955a9700f2c9dd45e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 12 Oct 2017 22:02:28 -0700 Subject: flow control fixes --- BUILD | 1 + build.yaml | 1 + gRPC-Core.podspec | 2 ++ grpc.gemspec | 1 + package.xml | 1 + .../ext/transport/chttp2/transport/flow_control.h | 11 +++++++ test/core/end2end/bad_server_response_test.c | 8 ++--- test/core/end2end/tests/shutdown_finishes_calls.c | 3 +- test/cpp/microbenchmarks/bm_chttp2_transport.cc | 36 ++++++++++------------ tools/doxygen/Doxyfile.core.internal | 1 + tools/run_tests/generated/sources_and_headers.json | 2 ++ 11 files changed, 43 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/BUILD b/BUILD index d8bb109492..a3299f4eef 100644 --- a/BUILD +++ b/BUILD @@ -1259,6 +1259,7 @@ grpc_cc_library( "src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/frame.h", + "src/core/ext/transport/chttp2/transport/flow_control.h", "src/core/ext/transport/chttp2/transport/frame_data.h", "src/core/ext/transport/chttp2/transport/frame_goaway.h", "src/core/ext/transport/chttp2/transport/frame_ping.h", diff --git a/build.yaml b/build.yaml index 78b18ff35a..e5e0757855 100644 --- a/build.yaml +++ b/build.yaml @@ -777,6 +777,7 @@ filegroups: - src/core/ext/transport/chttp2/transport/bin_decoder.h - src/core/ext/transport/chttp2/transport/bin_encoder.h - src/core/ext/transport/chttp2/transport/chttp2_transport.h + - src/core/ext/transport/chttp2/transport/flow_control.h - src/core/ext/transport/chttp2/transport/frame.h - src/core/ext/transport/chttp2/transport/frame_data.h - src/core/ext/transport/chttp2/transport/frame_goaway.h diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index ce1425a483..74f3e5b7d0 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -249,6 +249,7 @@ Pod::Spec.new do |s| 'src/core/ext/transport/chttp2/transport/bin_decoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.h', + 'src/core/ext/transport/chttp2/transport/flow_control.h', 'src/core/ext/transport/chttp2/transport/frame.h', 'src/core/ext/transport/chttp2/transport/frame_data.h', 'src/core/ext/transport/chttp2/transport/frame_goaway.h', @@ -750,6 +751,7 @@ Pod::Spec.new do |s| 'src/core/ext/transport/chttp2/transport/bin_decoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.h', + 'src/core/ext/transport/chttp2/transport/flow_control.h', 'src/core/ext/transport/chttp2/transport/frame.h', 'src/core/ext/transport/chttp2/transport/frame_data.h', 'src/core/ext/transport/chttp2/transport/frame_goaway.h', diff --git a/grpc.gemspec b/grpc.gemspec index ab51cc8420..6d7235028d 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -181,6 +181,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h ) s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h ) + s.files += %w( src/core/ext/transport/chttp2/transport/flow_control.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.h ) diff --git a/package.xml b/package.xml index e590745a67..0c5b1918b5 100644 --- a/package.xml +++ b/package.xml @@ -193,6 +193,7 @@ + diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 13a3341122..33542a31e4 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -201,6 +201,11 @@ class TransportFlowControl { FlowControlAction PeriodicUpdate(grpc_exec_ctx* exec_ctx); + void TestOnlyForceHugeWindow() { + announced_window_ = 1024 * 1024 * 1024; + remote_window_ = 1024 * 1024 * 1024; + } + private: double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value); FlowControlAction::Urgency DeltaUrgency(int32_t value, @@ -289,6 +294,12 @@ class StreamFlowControl { const grpc_chttp2_stream* stream() const { return s_; } + void TestOnlyForceHugeWindow() { + announced_window_delta_ = 1024 * 1024 * 1024; + local_window_delta_ = 1024 * 1024 * 1024; + remote_window_delta_ = 1024 * 1024 * 1024; + } + private: TransportFlowControl* const tfc_; const grpc_chttp2_stream* const s_; diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c index 554d8aa45b..2070fa5b02 100644 --- a/test/core/end2end/bad_server_response_test.c +++ b/test/core/end2end/bad_server_response_test.c @@ -207,8 +207,8 @@ static void start_rpc(int target_port, grpc_status_code expected_status, GPR_ASSERT(status == expected_status); if (expected_detail != NULL) { - GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( - expected_detail))); + GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( + expected_detail))); } grpc_metadata_array_destroy(&initial_metadata_recv); @@ -330,8 +330,8 @@ int main(int argc, char **argv) { HTTP2_DETAIL_MSG(502)); /* unparseable response */ - run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, - GRPC_STATUS_UNKNOWN, NULL); + run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, GRPC_STATUS_UNKNOWN, + NULL); /* http1 response */ run_test(HTTP1_RESP, sizeof(HTTP1_RESP) - 1, GRPC_STATUS_UNAVAILABLE, diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c index 652695cfcd..1312a2dd68 100644 --- a/test/core/end2end/tests/shutdown_finishes_calls.c +++ b/test/core/end2end/tests/shutdown_finishes_calls.c @@ -159,7 +159,8 @@ static void test_early_server_shutdown_finishes_inflight_calls( grpc_server_destroy(f.server); - GPR_ASSERT(status == GRPC_STATUS_INTERNAL || status == GRPC_STATUS_UNAVAILABLE); + GPR_ASSERT(status == GRPC_STATUS_INTERNAL || + status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc index 8ee3ae7268..3a484bb790 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc @@ -428,9 +428,8 @@ static void BM_TransportStreamSend(benchmark::State &state) { return; } // force outgoing window to be yuge - s->chttp2_stream()->flow_control.remote_window_delta = - 1024 * 1024 * 1024; - f.chttp2_transport()->flow_control.remote_window = 1024 * 1024 * 1024; + s->chttp2_stream()->flow_control->TestOnlyForceHugeWindow(); + f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow(); grpc_slice_buffer_stream_init(&send_stream, &send_buffer, 0); reset_op(); op.on_complete = c.get(); @@ -560,22 +559,21 @@ static void BM_TransportStreamRecv(benchmark::State &state) { std::unique_ptr drain_continue; grpc_slice recv_slice; - std::unique_ptr c = MakeClosure([&](grpc_exec_ctx *exec_ctx, - grpc_error *error) { - if (!state.KeepRunning()) return; - // force outgoing window to be yuge - s.chttp2_stream()->flow_control.local_window_delta = 1024 * 1024 * 1024; - s.chttp2_stream()->flow_control.announced_window_delta = 1024 * 1024 * 1024; - f.chttp2_transport()->flow_control.announced_window = 1024 * 1024 * 1024; - received = 0; - reset_op(); - op.on_complete = do_nothing.get(); - op.recv_message = true; - op.payload->recv_message.recv_message = &recv_stream; - op.payload->recv_message.recv_message_ready = drain_start.get(); - s.Op(exec_ctx, &op); - f.PushInput(grpc_slice_ref(incoming_data)); - }); + std::unique_ptr c = + MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { + if (!state.KeepRunning()) return; + // force outgoing window to be yuge + s.chttp2_stream()->flow_control->TestOnlyForceHugeWindow(); + f.chttp2_transport()->flow_control->TestOnlyForceHugeWindow(); + received = 0; + reset_op(); + op.on_complete = do_nothing.get(); + op.recv_message = true; + op.payload->recv_message.recv_message = &recv_stream; + op.payload->recv_message.recv_message_ready = drain_start.get(); + s.Op(exec_ctx, &op); + f.PushInput(grpc_slice_ref(incoming_data)); + }); drain_start = MakeClosure([&](grpc_exec_ctx *exec_ctx, grpc_error *error) { if (recv_stream == NULL) { diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 8435178d2e..87dadb39b8 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1020,6 +1020,7 @@ src/core/ext/transport/chttp2/transport/chttp2_plugin.cc \ src/core/ext/transport/chttp2/transport/chttp2_transport.cc \ src/core/ext/transport/chttp2/transport/chttp2_transport.h \ src/core/ext/transport/chttp2/transport/flow_control.cc \ +src/core/ext/transport/chttp2/transport/flow_control.h \ src/core/ext/transport/chttp2/transport/frame.h \ src/core/ext/transport/chttp2/transport/frame_data.cc \ src/core/ext/transport/chttp2/transport/frame_data.h \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 82b3800507..ffd2de9949 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -9007,6 +9007,7 @@ "src/core/ext/transport/chttp2/transport/bin_decoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h", + "src/core/ext/transport/chttp2/transport/flow_control.h", "src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame_data.h", "src/core/ext/transport/chttp2/transport/frame_goaway.h", @@ -9036,6 +9037,7 @@ "src/core/ext/transport/chttp2/transport/chttp2_transport.cc", "src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/flow_control.cc", + "src/core/ext/transport/chttp2/transport/flow_control.h", "src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame_data.cc", "src/core/ext/transport/chttp2/transport/frame_data.h", -- cgit v1.2.3 From 9f9f0f82f31d7dd3cfe58d1ba5a0c181c601e5c0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 13 Oct 2017 13:39:07 -0700 Subject: Review feedback --- .../transport/chttp2/transport/chttp2_transport.cc | 27 +++++++++++----------- test/core/end2end/bad_server_response_test.c | 8 +++---- test/core/end2end/tests/shutdown_finishes_calls.c | 4 +++- 3 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index abc30022c0..9e91a1c55e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -612,7 +612,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_error *error) { end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error)); - if (t->closed_with_error == nullptr) { + if (t->closed_with_error == GRPC_ERROR_NONE) { if (!grpc_error_has_clear_grpc_status(error)) { error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); @@ -656,9 +656,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, while (grpc_chttp2_list_pop_writable_stream(t, &s)) { GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); } - if (t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE) { - grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error)); - } + GPR_ASSERT(t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE); + grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); } @@ -854,10 +853,6 @@ static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->close_transport_on_writes_finished = NULL; close_transport_locked(exec_ctx, t, err); } - if (t->closed_with_error != GRPC_ERROR_NONE) { - grpc_endpoint_shutdown(exec_ctx, t->ep, - GRPC_ERROR_REF(t->closed_with_error)); - } } } @@ -1780,10 +1775,9 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx, GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); /*The transport will be closed after the write is done */ close_transport_locked( - exec_ctx, t, - grpc_error_set_int( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); + exec_ctx, t, grpc_error_set_int( + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); } } @@ -2583,6 +2577,8 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, GPR_TIMER_END("reading_action_locked", 0); } +// t is reffed prior to calling the first time, and once the callback chain +// that kicks off finishes, it's unreffed static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { t->flow_control.bdp_estimator->SchedulePing(); @@ -2754,8 +2750,11 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg, if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (error == GRPC_ERROR_NONE) { t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING; - close_transport_locked(exec_ctx, t, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "keepalive watchdog timeout"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); + close_transport_locked( + exec_ctx, t, + grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "keepalive watchdog timeout"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL)); } } else { /* The watchdog timer should have been cancelled by diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c index 554d8aa45b..2070fa5b02 100644 --- a/test/core/end2end/bad_server_response_test.c +++ b/test/core/end2end/bad_server_response_test.c @@ -207,8 +207,8 @@ static void start_rpc(int target_port, grpc_status_code expected_status, GPR_ASSERT(status == expected_status); if (expected_detail != NULL) { - GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( - expected_detail))); + GPR_ASSERT(-1 != grpc_slice_slice(details, grpc_slice_from_static_string( + expected_detail))); } grpc_metadata_array_destroy(&initial_metadata_recv); @@ -330,8 +330,8 @@ int main(int argc, char **argv) { HTTP2_DETAIL_MSG(502)); /* unparseable response */ - run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, - GRPC_STATUS_UNKNOWN, NULL); + run_test(UNPARSEABLE_RESP, sizeof(UNPARSEABLE_RESP) - 1, GRPC_STATUS_UNKNOWN, + NULL); /* http1 response */ run_test(HTTP1_RESP, sizeof(HTTP1_RESP) - 1, GRPC_STATUS_UNAVAILABLE, diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c index 652695cfcd..f90359f09a 100644 --- a/test/core/end2end/tests/shutdown_finishes_calls.c +++ b/test/core/end2end/tests/shutdown_finishes_calls.c @@ -159,7 +159,9 @@ static void test_early_server_shutdown_finishes_inflight_calls( grpc_server_destroy(f.server); - GPR_ASSERT(status == GRPC_STATUS_INTERNAL || status == GRPC_STATUS_UNAVAILABLE); + // new code should give INTERNAL, some older code will give UNAVAILABLE + GPR_ASSERT(status == GRPC_STATUS_INTERNAL || + status == GRPC_STATUS_UNAVAILABLE); GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo")); validate_host_override_string("foo.test.google.fr:1234", call_details.host, config); -- cgit v1.2.3 From 1f708a6adef0a34feeb8641c328ae05f1e81d461 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 15 Oct 2017 22:32:32 +0000 Subject: Prefer to kick waiters not pollers --- src/core/lib/iomgr/ev_epollex_linux.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index bc2e665f06..07ba9dd2cc 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -557,11 +557,13 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset_worker *specific_worker) { pollable *p = specific_worker->pollable_obj; grpc_core::mu_guard lock(&p->mu); +GRPC_STATS_INC_POLLSET_KICK(exec_ctx); GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); } +GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx); return GRPC_ERROR_NONE; } if (gpr_tls_get(&g_current_thread_worker) == @@ -569,10 +571,12 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); } +GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx); specific_worker->kicked = true; return GRPC_ERROR_NONE; } if (specific_worker == p->root_worker) { +GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); } @@ -581,6 +585,7 @@ if (specific_worker == p->root_worker) { return error; } if (specific_worker->initialized_cv) { +GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); } @@ -611,7 +616,7 @@ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; } else { - return pollset_kick_one(exec_ctx, pollset, pollset->root_worker); + return pollset_kick_one(exec_ctx, pollset, pollset->root_worker->links[PWLINK_POLLSET].next); } } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { -- cgit v1.2.3 From 97633744fa8d6c25b2c62024355d98ef7a24e8a5 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 15 Oct 2017 15:34:40 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index fc4c875df2..1e8de8910e 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -560,25 +560,25 @@ static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, grpc_pollset_worker *specific_worker) { pollable *p = specific_worker->pollable_obj; grpc_core::mu_guard lock(&p->mu); -GRPC_STATS_INC_POLLSET_KICK(exec_ctx); + GRPC_STATS_INC_POLLSET_KICK(exec_ctx); GPR_ASSERT(specific_worker != NULL); if (specific_worker->kicked) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p); } -GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx); + GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx); return GRPC_ERROR_NONE; } if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p); } -GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx); + GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx); specific_worker->kicked = true; return GRPC_ERROR_NONE; - } -if (specific_worker == p->root_worker) { -GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx); + } + if (specific_worker == p->root_worker) { + GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p); } @@ -586,8 +586,8 @@ GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx); grpc_error *error = grpc_wakeup_fd_wakeup(&p->wakeup); return error; } -if (specific_worker->initialized_cv) { -GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx); + if (specific_worker->initialized_cv) { + GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx); if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p); } @@ -619,7 +619,9 @@ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; } else { - return pollset_kick_one(exec_ctx, pollset, pollset->root_worker->links[PWLINK_POLLSET].next); + return pollset_kick_one( + exec_ctx, pollset, + pollset->root_worker->links[PWLINK_POLLSET].next); } } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { -- cgit v1.2.3 From a584d992890a6d7b51bcff16876addcd49cfe3cf Mon Sep 17 00:00:00 2001 From: Ian Coolidge Date: Mon, 16 Oct 2017 10:28:13 -0700 Subject: cpu_linux: Don't spam sched_getcpu failures on qemu __NR_getcpu isn't implemented on qemu, and for some reason sysconf(_SC_NPROCESSORS_ONLN) returns the number of processers of the host system, giving a false indication that there is more than one cpu for the qemu case. Expand the init_num_cpus sequence to also run sched_getcpu once, and if that call isn't supported, initialize 'ncpus' to 1. Later, in gpr_cpu_current_cpu, use gpr_cpu_num_cores to avoid the system call in cases where we know it isn't supported, or if the ncpus is otherwise 1. --- src/core/lib/support/cpu_linux.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/lib/support/cpu_linux.cc b/src/core/lib/support/cpu_linux.cc index 2280668442..53619caa5f 100644 --- a/src/core/lib/support/cpu_linux.cc +++ b/src/core/lib/support/cpu_linux.cc @@ -38,8 +38,9 @@ static int ncpus = 0; static void init_num_cpus() { /* This must be signed. sysconf returns -1 when the number cannot be determined */ + int cpu = sched_getcpu(); ncpus = (int)sysconf(_SC_NPROCESSORS_ONLN); - if (ncpus < 1) { + if (ncpus < 1 || cpu < 0) { gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); ncpus = 1; } @@ -56,6 +57,9 @@ unsigned gpr_cpu_current_cpu(void) { // sched_getcpu() is undefined on musl return 0; #else + if (gpr_cpu_num_cores() == 1) { + return 0; + } int cpu = sched_getcpu(); if (cpu < 0) { gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); -- cgit v1.2.3 From ccfdfb3a41c7e0d34878d82320058eea910f26aa Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 16 Oct 2017 13:26:13 -0700 Subject: Add comparison function for security connectors. --- src/core/lib/http/httpcli_security_connector.cc | 15 ++- .../security/credentials/fake/fake_credentials.cc | 5 +- .../security/credentials/ssl/ssl_credentials.cc | 6 +- .../lib/security/transport/security_connector.cc | 126 ++++++++++++++++++--- .../lib/security/transport/security_connector.h | 34 ++++-- 5 files changed, 153 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc index ef6c4a509b..d832dacb69 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/lib/http/httpcli_security_connector.cc @@ -91,8 +91,17 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, tsi_peer_destruct(&peer); } +static int httpcli_ssl_cmp(grpc_security_connector *sc1, + grpc_security_connector *sc2) { + grpc_httpcli_ssl_channel_security_connector *c1 = + (grpc_httpcli_ssl_channel_security_connector *)sc1; + grpc_httpcli_ssl_channel_security_connector *c2 = + (grpc_httpcli_ssl_channel_security_connector *)sc2; + return strcmp(c1->secure_peer_name, c2->secure_peer_name); +} + static grpc_security_connector_vtable httpcli_ssl_vtable = { - httpcli_ssl_destroy, httpcli_ssl_check_peer}; + httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp}; static grpc_security_status httpcli_ssl_channel_security_connector_create( grpc_exec_ctx *exec_ctx, const char *pem_root_certs, @@ -123,6 +132,10 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create( *sc = NULL; return GRPC_SECURITY_ERROR; } + // We don't actually need a channel credentials object in this case, + // but we set it to a non-NULL address so that we don't trigger + // assertions in grpc_channel_security_connector_cmp(). + c->base.channel_creds = (grpc_channel_credentials *)1; c->base.add_handshakers = httpcli_ssl_add_handshakers; *sc = &c->base; return GRPC_SECURITY_OK; diff --git a/src/core/lib/security/credentials/fake/fake_credentials.cc b/src/core/lib/security/credentials/fake/fake_credentials.cc index 795ca0660a..cf10bf24c8 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.cc +++ b/src/core/lib/security/credentials/fake/fake_credentials.cc @@ -38,7 +38,8 @@ static grpc_security_status fake_transport_security_create_security_connector( grpc_call_credentials *call_creds, const char *target, const grpc_channel_args *args, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { - *sc = grpc_fake_channel_security_connector_create(call_creds, target, args); + *sc = + grpc_fake_channel_security_connector_create(c, call_creds, target, args); return GRPC_SECURITY_OK; } @@ -46,7 +47,7 @@ static grpc_security_status fake_transport_security_server_create_security_connector( grpc_exec_ctx *exec_ctx, grpc_server_credentials *c, grpc_server_security_connector **sc) { - *sc = grpc_fake_server_security_connector_create(); + *sc = grpc_fake_server_security_connector_create(c); return GRPC_SECURITY_OK; } diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/src/core/lib/security/credentials/ssl/ssl_credentials.cc index 9df69a2a3d..290336adc0 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.cc +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.cc @@ -62,7 +62,8 @@ static grpc_security_status ssl_create_security_connector( } } status = grpc_ssl_channel_security_connector_create( - exec_ctx, call_creds, &c->config, target, overridden_target_name, sc); + exec_ctx, creds, call_creds, &c->config, target, overridden_target_name, + sc); if (status != GRPC_SECURITY_OK) { return status; } @@ -128,7 +129,8 @@ static grpc_security_status ssl_server_create_security_connector( grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, grpc_server_security_connector **sc) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return grpc_ssl_server_security_connector_create(exec_ctx, &c->config, sc); + return grpc_ssl_server_security_connector_create(exec_ctx, creds, &c->config, + sc); } static grpc_server_credentials_vtable ssl_server_vtable = { diff --git a/src/core/lib/security/transport/security_connector.cc b/src/core/lib/security/transport/security_connector.cc index 51844fb91f..80d9a7b77f 100644 --- a/src/core/lib/security/transport/security_connector.cc +++ b/src/core/lib/security/transport/security_connector.cc @@ -136,6 +136,39 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, } } +int grpc_security_connector_cmp(grpc_security_connector *sc, + grpc_security_connector *other) { + if (sc == NULL || other == NULL) return GPR_ICMP(sc, other); + int c = GPR_ICMP(sc->vtable, other->vtable); + if (c != 0) return c; + return sc->vtable->cmp(sc, other); +} + +int grpc_channel_security_connector_cmp(grpc_channel_security_connector *sc1, + grpc_channel_security_connector *sc2) { + GPR_ASSERT(sc1->channel_creds != NULL); + GPR_ASSERT(sc2->channel_creds != NULL); + int c = GPR_ICMP(sc1->channel_creds, sc2->channel_creds); + if (c != 0) return c; + c = GPR_ICMP(sc1->request_metadata_creds, sc2->request_metadata_creds); + if (c != 0) return c; + c = GPR_ICMP((void *)sc1->check_call_host, (void *)sc2->check_call_host); + if (c != 0) return c; + c = GPR_ICMP((void *)sc1->cancel_check_call_host, + (void *)sc2->cancel_check_call_host); + if (c != 0) return c; + return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers); +} + +int grpc_server_security_connector_cmp(grpc_server_security_connector *sc1, + grpc_server_security_connector *sc2) { + GPR_ASSERT(sc1->server_creds != NULL); + GPR_ASSERT(sc2->server_creds != NULL); + int c = GPR_ICMP(sc1->server_creds, sc2->server_creds); + if (c != 0) return c; + return GPR_ICMP((void *)sc1->add_handshakers, (void *)sc2->add_handshakers); +} + bool grpc_channel_security_connector_check_call_host( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, @@ -199,25 +232,27 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc); } -static void connector_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { +static void connector_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) { GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, (grpc_security_connector *)p, - "connector_pointer_arg_destroy"); + "connector_arg_destroy"); } -static void *connector_pointer_arg_copy(void *p) { +static void *connector_arg_copy(void *p) { return GRPC_SECURITY_CONNECTOR_REF((grpc_security_connector *)p, - "connector_pointer_arg_copy"); + "connector_arg_copy"); } -static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } +static int connector_cmp(void *a, void *b) { + return grpc_security_connector_cmp((grpc_security_connector *)a, + (grpc_security_connector *)b); +} -static const grpc_arg_pointer_vtable connector_pointer_vtable = { - connector_pointer_arg_copy, connector_pointer_arg_destroy, - connector_pointer_cmp}; +static const grpc_arg_pointer_vtable connector_arg_vtable = { + connector_arg_copy, connector_arg_destroy, connector_cmp}; grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { return grpc_channel_arg_pointer_create((char *)GRPC_ARG_SECURITY_CONNECTOR, - sc, &connector_pointer_vtable); + sc, &connector_arg_vtable); } grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) { @@ -382,6 +417,32 @@ static void fake_server_check_peer(grpc_exec_ctx *exec_ctx, fake_check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); } +static int fake_channel_cmp(grpc_security_connector *sc1, + grpc_security_connector *sc2) { + grpc_fake_channel_security_connector *c1 = + (grpc_fake_channel_security_connector *)sc1; + grpc_fake_channel_security_connector *c2 = + (grpc_fake_channel_security_connector *)sc2; + int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); + if (c != 0) return c; + c = strcmp(c1->target, c2->target); + if (c != 0) return c; + if (c1->expected_targets == NULL || c2->expected_targets == NULL) { + c = GPR_ICMP(c1->expected_targets, c2->expected_targets); + } else { + c = strcmp(c1->expected_targets, c2->expected_targets); + } + if (c != 0) return c; + return GPR_ICMP(c1->is_lb_channel, c2->is_lb_channel); +} + +static int fake_server_cmp(grpc_security_connector *sc1, + grpc_security_connector *sc2) { + return grpc_server_security_connector_cmp( + (grpc_server_security_connector *)sc1, + (grpc_server_security_connector *)sc2); +} + static bool fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, @@ -418,12 +479,13 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx, } static grpc_security_connector_vtable fake_channel_vtable = { - fake_channel_destroy, fake_channel_check_peer}; + fake_channel_destroy, fake_channel_check_peer, fake_channel_cmp}; static grpc_security_connector_vtable fake_server_vtable = { - fake_server_destroy, fake_server_check_peer}; + fake_server_destroy, fake_server_check_peer, fake_server_cmp}; grpc_channel_security_connector *grpc_fake_channel_security_connector_create( + grpc_channel_credentials *channel_creds, grpc_call_credentials *request_metadata_creds, const char *target, const grpc_channel_args *args) { grpc_fake_channel_security_connector *c = @@ -431,6 +493,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.vtable = &fake_channel_vtable; + c->base.channel_creds = channel_creds; c->base.request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = fake_channel_check_call_host; @@ -444,13 +507,14 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( } grpc_server_security_connector *grpc_fake_server_security_connector_create( - void) { + grpc_server_credentials *server_creds) { grpc_server_security_connector *c = (grpc_server_security_connector *)gpr_zalloc( sizeof(grpc_server_security_connector)); gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &fake_server_vtable; c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; + c->server_creds = server_creds; c->add_handshakers = fake_server_add_handshakers; return c; } @@ -473,6 +537,7 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; + grpc_channel_credentials_unref(exec_ctx, c->base.channel_creds); grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds); tsi_ssl_client_handshaker_factory_unref(c->client_handshaker_factory); c->client_handshaker_factory = NULL; @@ -485,6 +550,7 @@ static void ssl_server_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; + grpc_server_credentials_unref(exec_ctx, c->base.server_creds); tsi_ssl_server_handshaker_factory_unref(c->server_handshaker_factory); c->server_handshaker_factory = NULL; gpr_free(sc); @@ -641,6 +707,29 @@ static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, GRPC_CLOSURE_SCHED(exec_ctx, on_peer_checked, error); } +static int ssl_channel_cmp(grpc_security_connector *sc1, + grpc_security_connector *sc2) { + grpc_ssl_channel_security_connector *c1 = + (grpc_ssl_channel_security_connector *)sc1; + grpc_ssl_channel_security_connector *c2 = + (grpc_ssl_channel_security_connector *)sc2; + int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base); + if (c != 0) return c; + c = strcmp(c1->target_name, c2->target_name); + if (c != 0) return c; + return (c1->overridden_target_name == NULL || + c2->overridden_target_name == NULL) + ? GPR_ICMP(c1->overridden_target_name, c2->overridden_target_name) + : strcmp(c1->overridden_target_name, c2->overridden_target_name); +} + +static int ssl_server_cmp(grpc_security_connector *sc1, + grpc_security_connector *sc2) { + return grpc_server_security_connector_cmp( + (grpc_server_security_connector *)sc1, + (grpc_server_security_connector *)sc2); +} + static void add_shallow_auth_property_to_peer(tsi_peer *peer, const grpc_auth_property *prop, const char *tsi_prop_name) { @@ -717,10 +806,10 @@ static void ssl_channel_cancel_check_call_host( } static grpc_security_connector_vtable ssl_channel_vtable = { - ssl_channel_destroy, ssl_channel_check_peer}; + ssl_channel_destroy, ssl_channel_check_peer, ssl_channel_cmp}; static grpc_security_connector_vtable ssl_server_vtable = { - ssl_server_destroy, ssl_server_check_peer}; + ssl_server_destroy, ssl_server_check_peer, ssl_server_cmp}; /* returns a NULL terminated slice. */ static grpc_slice compute_default_pem_root_certs_once(void) { @@ -804,7 +893,8 @@ const char *grpc_get_default_ssl_roots(void) { } grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, + grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds, + grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); @@ -840,6 +930,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; + c->base.channel_creds = grpc_channel_credentials_ref(channel_creds); c->base.request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; @@ -874,8 +965,8 @@ error: } grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, - grpc_server_security_connector **sc) { + grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, + const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); const char **alpn_protocol_strings = (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); @@ -897,6 +988,7 @@ grpc_security_status grpc_ssl_server_security_connector_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.vtable = &ssl_server_vtable; + c->base.server_creds = grpc_server_credentials_ref(server_creds); result = tsi_create_ssl_server_handshaker_factory_ex( config->pem_key_cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, get_tsi_client_certificate_request_type( diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index 4d87cd0c80..216bb35e81 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -60,13 +60,9 @@ typedef struct { void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, grpc_auth_context **auth_context, grpc_closure *on_peer_checked); + int (*cmp)(grpc_security_connector *sc, grpc_security_connector *other); } grpc_security_connector_vtable; -typedef struct grpc_security_connector_handshake_list { - void *handshake; - struct grpc_security_connector_handshake_list *next; -} grpc_security_connector_handshake_list; - struct grpc_security_connector { const grpc_security_connector_vtable *vtable; gpr_refcount refcount; @@ -104,6 +100,10 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, grpc_auth_context **auth_context, grpc_closure *on_peer_checked); +/* Compares two security connectors. */ +int grpc_security_connector_cmp(grpc_security_connector *sc, + grpc_security_connector *other); + /* Util to encapsulate the connector in a channel arg. */ grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); @@ -116,13 +116,14 @@ grpc_security_connector *grpc_security_connector_find_in_args( /* --- channel_security_connector object. --- - A channel security connector object represents away to configure the + A channel security connector object represents a way to configure the underlying transport security mechanism on the client side. */ typedef struct grpc_channel_security_connector grpc_channel_security_connector; struct grpc_channel_security_connector { grpc_security_connector base; + grpc_channel_credentials *channel_creds; grpc_call_credentials *request_metadata_creds; bool (*check_call_host)(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, const char *host, @@ -138,6 +139,10 @@ struct grpc_channel_security_connector { grpc_handshake_manager *handshake_mgr); }; +/// A helper function for use in grpc_security_connector_cmp() implementations. +int grpc_channel_security_connector_cmp(grpc_channel_security_connector *sc1, + grpc_channel_security_connector *sc2); + /// Checks that the host that will be set for a call is acceptable. /// Returns true if completed synchronously, in which case \a error will /// be set to indicate the result. Otherwise, \a on_call_host_checked @@ -161,18 +166,23 @@ void grpc_channel_security_connector_add_handshakers( /* --- server_security_connector object. --- - A server security connector object represents away to configure the + A server security connector object represents a way to configure the underlying transport security mechanism on the server side. */ typedef struct grpc_server_security_connector grpc_server_security_connector; struct grpc_server_security_connector { grpc_security_connector base; + grpc_server_credentials *server_creds; void (*add_handshakers)(grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr); }; +/// A helper function for use in grpc_security_connector_cmp() implementations. +int grpc_server_security_connector_cmp(grpc_server_security_connector *sc1, + grpc_server_security_connector *sc2); + void grpc_server_security_connector_add_handshakers( grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr); @@ -182,13 +192,14 @@ void grpc_server_security_connector_add_handshakers( /* For TESTING ONLY! Creates a fake connector that emulates real channel security. */ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( + grpc_channel_credentials *channel_creds, grpc_call_credentials *request_metadata_creds, const char *target, const grpc_channel_args *args); /* For TESTING ONLY! Creates a fake connector that emulates real server security. */ grpc_server_security_connector *grpc_fake_server_security_connector_create( - void); + grpc_server_credentials *server_creds); /* Config for ssl clients. */ @@ -211,7 +222,8 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_channel_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, + grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds, + grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc); @@ -236,8 +248,8 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, - grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, + const grpc_ssl_server_config *config, grpc_server_security_connector **sc); /* Util. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, -- cgit v1.2.3 From 8232492cce70bcf833dc82254d53d00b3544a751 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 16 Oct 2017 21:37:28 +0000 Subject: Fix leak --- src/core/lib/iomgr/ev_epollex_linux.cc | 42 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 1e8de8910e..8b0ebc2d17 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -201,7 +201,7 @@ struct grpc_pollset_set { size_t pollset_count; size_t pollset_capacity; - pollable **pollsets; + grpc_pollset **pollsets; size_t fd_count; size_t fd_capacity; @@ -545,6 +545,9 @@ static void pollset_global_shutdown(void) { static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { +if (GRPC_TRACER_ON(grpc_polling_trace)) { +gpr_log(GPR_DEBUG, "PS:%p (pollable:%p) maybe_finish_shutdown sc=%p (target:!NULL) rw=%p (target:NULL) cpsc=%d (target:0)", pollset, pollset->active_pollable, pollset->shutdown_closure, pollset->root_worker, pollset->containing_pollset_set_count); +} if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && pollset->containing_pollset_set_count == 0) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); @@ -1123,7 +1126,11 @@ static void pollset_set_unref(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss) { pollset_set_unref(exec_ctx, pss->parent); gpr_mu_destroy(&pss->mu); for (size_t i = 0; i < pss->pollset_count; i++) { - POLLABLE_UNREF(pss->pollsets[i], "pollset_set"); + gpr_mu_lock(&pss->pollsets[i]->mu); + if (0==--pss->pollsets[i]->containing_pollset_set_count) { + pollset_maybe_finish_shutdown(exec_ctx, pss->pollsets[i]); + } + gpr_mu_unlock(&pss->pollsets[i]->mu); } for (size_t i = 0; i < pss->fd_count; i++) { UNREF_BY(exec_ctx, pss->fds[i], 2, "pollset_set"); @@ -1142,7 +1149,7 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static const char *err_desc = "pollset_set_add_fd"; pss = pss_lock_adam(pss); for (size_t i = 0; i < pss->pollset_count; i++) { - append_error(&error, pollable_add_fd(pss->pollsets[i], fd), err_desc); + append_error(&error, pollable_add_fd(pss->pollsets[i]->active_pollable, fd), err_desc); } if (pss->fd_count == pss->fd_capacity) { pss->fd_capacity = GPR_MAX(pss->fd_capacity * 2, 8); @@ -1185,8 +1192,7 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, pss = pss_lock_adam(pss); size_t i; for (i = 0; i < pss->pollset_count; i++) { - if (pss->pollsets[i] == ps->active_pollable) { - POLLABLE_UNREF(pss->pollsets[i], "pollset_set"); + if (pss->pollsets[i] == ps) { break; } } @@ -1204,9 +1210,10 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, } // add all fds to pollables, and output a new array of unorphaned out_fds -static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, - size_t fd_count, pollable **pollables, - size_t pollable_count, +// assumes pollsets are multipollable +static grpc_error *add_fds_to_pollsets(grpc_exec_ctx *exec_ctx, grpc_fd **fds, + size_t fd_count, grpc_pollset **pollsets, + size_t pollset_count, const char *err_desc, grpc_fd **out_fds, size_t *out_fd_count) { grpc_error *error = GRPC_ERROR_NONE; @@ -1216,8 +1223,8 @@ static grpc_error *add_fds_to_pollables(grpc_exec_ctx *exec_ctx, grpc_fd **fds, gpr_mu_unlock(&fds[i]->orphan_mu); UNREF_BY(exec_ctx, fds[i], 2, "pollset_set"); } else { - for (size_t j = 0; j < pollable_count; j++) { - append_error(&error, pollable_add_fd(pollables[j], fds[i]), err_desc); + for (size_t j = 0; j < pollset_count; j++) { + append_error(&error, pollable_add_fd(pollsets[j]->active_pollable, fds[i]), err_desc); } gpr_mu_unlock(&fds[i]->orphan_mu); out_fds[(*out_fd_count)++] = fds[i]; @@ -1246,17 +1253,18 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, pss = pss_lock_adam(pss); size_t initial_fd_count = pss->fd_count; pss->fd_count = 0; - append_error(&error, add_fds_to_pollables(exec_ctx, pss->fds, - initial_fd_count, &pollable_obj, 1, + append_error(&error, add_fds_to_pollsets(exec_ctx, pss->fds, + initial_fd_count, &ps, 1, err_desc, pss->fds, &pss->fd_count), err_desc); if (pss->pollset_count == pss->pollset_capacity) { pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); - pss->pollsets = (pollable **)gpr_realloc( + pss->pollsets = (grpc_pollset **)gpr_realloc( pss->pollsets, pss->pollset_capacity * sizeof(*pss->pollsets)); } - pss->pollsets[pss->pollset_count++] = pollable_obj; + pss->pollsets[pss->pollset_count++] = ps; gpr_mu_unlock(&pss->mu); +POLLABLE_UNREF(pollable_obj, "pollset_set"); GRPC_LOG_IF_ERROR(err_desc, error); } @@ -1309,18 +1317,18 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } size_t initial_a_fd_count = a->fd_count; a->fd_count = 0; - append_error(&error, add_fds_to_pollables( + append_error(&error, add_fds_to_pollsets( exec_ctx, a->fds, initial_a_fd_count, b->pollsets, b->pollset_count, "merge_a2b", a->fds, &a->fd_count), err_desc); - append_error(&error, add_fds_to_pollables(exec_ctx, b->fds, b->fd_count, + append_error(&error, add_fds_to_pollsets(exec_ctx, b->fds, b->fd_count, a->pollsets, a->pollset_count, "merge_b2a", a->fds, &a->fd_count), err_desc); if (a->pollset_capacity < a->pollset_count + b->pollset_count) { a->pollset_capacity = GPR_MAX(2 * a->pollset_capacity, a->pollset_count + b->pollset_count); - a->pollsets = (pollable **)gpr_realloc( + a->pollsets = (grpc_pollset **)gpr_realloc( a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); } memcpy(a->pollsets + a->pollset_count, b->pollsets, -- cgit v1.2.3 From b653dff0bddfe452ca27f91cbe186335e087ae25 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 16 Oct 2017 14:38:36 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.cc | 45 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 8b0ebc2d17..1b3122176d 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -545,9 +545,13 @@ static void pollset_global_shutdown(void) { static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { -if (GRPC_TRACER_ON(grpc_polling_trace)) { -gpr_log(GPR_DEBUG, "PS:%p (pollable:%p) maybe_finish_shutdown sc=%p (target:!NULL) rw=%p (target:NULL) cpsc=%d (target:0)", pollset, pollset->active_pollable, pollset->shutdown_closure, pollset->root_worker, pollset->containing_pollset_set_count); -} + if (GRPC_TRACER_ON(grpc_polling_trace)) { + gpr_log(GPR_DEBUG, + "PS:%p (pollable:%p) maybe_finish_shutdown sc=%p (target:!NULL) " + "rw=%p (target:NULL) cpsc=%d (target:0)", + pollset, pollset->active_pollable, pollset->shutdown_closure, + pollset->root_worker, pollset->containing_pollset_set_count); + } if (pollset->shutdown_closure != NULL && pollset->root_worker == NULL && pollset->containing_pollset_set_count == 0) { GRPC_CLOSURE_SCHED(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); @@ -1127,7 +1131,7 @@ static void pollset_set_unref(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss) { gpr_mu_destroy(&pss->mu); for (size_t i = 0; i < pss->pollset_count; i++) { gpr_mu_lock(&pss->pollsets[i]->mu); - if (0==--pss->pollsets[i]->containing_pollset_set_count) { + if (0 == --pss->pollsets[i]->containing_pollset_set_count) { pollset_maybe_finish_shutdown(exec_ctx, pss->pollsets[i]); } gpr_mu_unlock(&pss->pollsets[i]->mu); @@ -1149,7 +1153,8 @@ static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset_set *pss, static const char *err_desc = "pollset_set_add_fd"; pss = pss_lock_adam(pss); for (size_t i = 0; i < pss->pollset_count; i++) { - append_error(&error, pollable_add_fd(pss->pollsets[i]->active_pollable, fd), err_desc); + append_error(&error, pollable_add_fd(pss->pollsets[i]->active_pollable, fd), + err_desc); } if (pss->fd_count == pss->fd_capacity) { pss->fd_capacity = GPR_MAX(pss->fd_capacity * 2, 8); @@ -1212,10 +1217,10 @@ static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, // add all fds to pollables, and output a new array of unorphaned out_fds // assumes pollsets are multipollable static grpc_error *add_fds_to_pollsets(grpc_exec_ctx *exec_ctx, grpc_fd **fds, - size_t fd_count, grpc_pollset **pollsets, - size_t pollset_count, - const char *err_desc, grpc_fd **out_fds, - size_t *out_fd_count) { + size_t fd_count, grpc_pollset **pollsets, + size_t pollset_count, + const char *err_desc, grpc_fd **out_fds, + size_t *out_fd_count) { grpc_error *error = GRPC_ERROR_NONE; for (size_t i = 0; i < fd_count; i++) { gpr_mu_lock(&fds[i]->orphan_mu); @@ -1224,7 +1229,9 @@ static grpc_error *add_fds_to_pollsets(grpc_exec_ctx *exec_ctx, grpc_fd **fds, UNREF_BY(exec_ctx, fds[i], 2, "pollset_set"); } else { for (size_t j = 0; j < pollset_count; j++) { - append_error(&error, pollable_add_fd(pollsets[j]->active_pollable, fds[i]), err_desc); + append_error(&error, + pollable_add_fd(pollsets[j]->active_pollable, fds[i]), + err_desc); } gpr_mu_unlock(&fds[i]->orphan_mu); out_fds[(*out_fd_count)++] = fds[i]; @@ -1253,9 +1260,9 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, pss = pss_lock_adam(pss); size_t initial_fd_count = pss->fd_count; pss->fd_count = 0; - append_error(&error, add_fds_to_pollsets(exec_ctx, pss->fds, - initial_fd_count, &ps, 1, - err_desc, pss->fds, &pss->fd_count), + append_error(&error, + add_fds_to_pollsets(exec_ctx, pss->fds, initial_fd_count, &ps, 1, + err_desc, pss->fds, &pss->fd_count), err_desc); if (pss->pollset_count == pss->pollset_capacity) { pss->pollset_capacity = GPR_MAX(pss->pollset_capacity * 2, 8); @@ -1264,7 +1271,7 @@ static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, } pss->pollsets[pss->pollset_count++] = ps; gpr_mu_unlock(&pss->mu); -POLLABLE_UNREF(pollable_obj, "pollset_set"); + POLLABLE_UNREF(pollable_obj, "pollset_set"); GRPC_LOG_IF_ERROR(err_desc, error); } @@ -1317,13 +1324,13 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, } size_t initial_a_fd_count = a->fd_count; a->fd_count = 0; - append_error(&error, add_fds_to_pollsets( - exec_ctx, a->fds, initial_a_fd_count, b->pollsets, - b->pollset_count, "merge_a2b", a->fds, &a->fd_count), + append_error(&error, add_fds_to_pollsets(exec_ctx, a->fds, initial_a_fd_count, + b->pollsets, b->pollset_count, + "merge_a2b", a->fds, &a->fd_count), err_desc); append_error(&error, add_fds_to_pollsets(exec_ctx, b->fds, b->fd_count, - a->pollsets, a->pollset_count, - "merge_b2a", a->fds, &a->fd_count), + a->pollsets, a->pollset_count, + "merge_b2a", a->fds, &a->fd_count), err_desc); if (a->pollset_capacity < a->pollset_count + b->pollset_count) { a->pollset_capacity = -- cgit v1.2.3 From 6acc0ab3305c45d4b390ee8c5f6b6049acbff58f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 16 Oct 2017 14:42:17 -0700 Subject: Fix memory leak --- src/core/ext/transport/chttp2/transport/chttp2_transport.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 9e91a1c55e..9462d1085e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -1708,6 +1708,7 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, /* callback remaining pings: they're not allowed to call into the transpot, and maybe they hold resources that need to be freed */ grpc_chttp2_ping_queue *pq = &t->ping_queue; + GPR_ASSERT(error != GRPC_ERROR_NONE); for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) { grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error)); GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]); @@ -1717,6 +1718,12 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_closure *on_initiate, grpc_closure *on_ack) { + if (t->closed_with_error != GRPC_ERROR_NONE) { + GRPC_CLOSURE_SCHED(exec_ctx, on_initiate, + GRPC_ERROR_REF(t->closed_with_error)); + GRPC_CLOSURE_SCHED(exec_ctx, on_ack, GRPC_ERROR_REF(t->closed_with_error)); + return; + } grpc_chttp2_ping_queue *pq = &t->ping_queue; grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate, GRPC_ERROR_NONE); -- cgit v1.2.3 From fd42ceb1ff3d0a80487ee81d86afbde97b19fe42 Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 10 Oct 2017 16:55:13 -0700 Subject: Use key in dynamic table if available --- .../transport/chttp2/transport/hpack_encoder.cc | 146 ++++++++++++--------- src/core/lib/transport/metadata.cc | 7 +- src/core/lib/transport/metadata.h | 3 +- test/core/transport/chttp2/hpack_encoder_test.c | 99 +++++++++----- test/core/transport/metadata_test.c | 4 +- 5 files changed, 156 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc index 17b8c4ab85..e667d8829a 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc @@ -180,14 +180,12 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) { /* add an element to the decoder table */ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem elem) { - GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem)); - + grpc_mdelem elem, size_t elem_size, bool only_add_key) { uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); - uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); - uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); + uint32_t value_hash = only_add_key ? 0 : grpc_slice_hash(GRPC_MDVALUE(elem)); + uint32_t elem_hash = + only_add_key ? 0 : GRPC_MDSTR_KV_HASH(key_hash, value_hash); uint32_t new_index = c->tail_remote_index + c->table_elems + 1; - size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); GPR_ASSERT(elem_size < 65536); @@ -209,37 +207,7 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, c->table_size = (uint16_t)(c->table_size + elem_size); c->table_elems++; - /* Store this element into {entries,indices}_elem */ - if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { - /* already there: update with new index */ - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], - elem)) { - /* already there (cuckoo): update with new index */ - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { - /* not there, but a free element: add */ - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { - /* not there (cuckoo), but a free element: add */ - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < - c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } - - /* do exactly the same for the key (so we can find by that again too) */ - + /* Store the key into {entries,indices}_keys */ if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) { c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index; @@ -270,6 +238,37 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } + + if (!only_add_key) { + /* Store this element into {entries,indices}_elem */ + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { + /* already there: update with new index */ + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], + elem)) { + /* already there (cuckoo): update with new index */ + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { + /* not there, but a free element: add */ + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { + /* not there (cuckoo), but a free element: add */ + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < + c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } + } } static void emit_indexed(grpc_exec_ctx *exec_ctx, @@ -430,9 +429,14 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, "Reserved header (colon-prefixed) happening after regular ones."); } - if (GRPC_TRACER_ON(grpc_http_trace) && !GRPC_MDELEM_IS_INTERNED(elem)) { + if (GRPC_TRACER_ON(grpc_http_trace)) { char *k = grpc_slice_to_c_string(GRPC_MDKEY(elem)); - char *v = grpc_slice_to_c_string(GRPC_MDVALUE(elem)); + char *v = NULL; + if (grpc_is_binary_header(GRPC_MDKEY(elem))) { + v = grpc_dump_slice(GRPC_MDVALUE(elem), GPR_DUMP_HEX); + } else { + v = grpc_slice_to_c_string(GRPC_MDVALUE(elem)); + } gpr_log( GPR_DEBUG, "Encode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d", @@ -442,7 +446,12 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, gpr_free(k); gpr_free(v); } - if (!GRPC_MDELEM_IS_INTERNED(elem)) { + + bool elem_interned = GRPC_MDELEM_IS_INTERNED(elem); + bool key_interned = elem_interned || grpc_slice_is_interned(GRPC_MDKEY(elem)); + + // Key is not interned, emit literals. + if (!key_interned) { emit_lithdr_noidx_v(exec_ctx, c, elem, st); return; } @@ -452,37 +461,46 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, uint32_t elem_hash; size_t decoder_space_usage; uint32_t indices_key; - int should_add_elem; + bool should_add_elem; + bool should_add_key; key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); - value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); - elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); - inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems); + if (elem_interned) { + value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); - /* is this elem currently in the decoders table? */ + inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, + c->filter_elems); - if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) && - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { - /* HIT: complete element (first cuckoo hash) */ - emit_indexed(exec_ctx, c, - dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st); - return; - } + /* is this elem currently in the decoders table? */ - if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) && - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { - /* HIT: complete element (second cuckoo hash) */ - emit_indexed(exec_ctx, c, - dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st); - return; + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem) && + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) { + /* HIT: complete element (first cuckoo hash) */ + emit_indexed(exec_ctx, c, + dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]), st); + return; + } + + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], elem) && + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) { + /* HIT: complete element (second cuckoo hash) */ + emit_indexed(exec_ctx, c, + dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]), st); + return; + } } /* should this elem be in the table? */ - decoder_space_usage = grpc_mdelem_get_size_in_hpack_table(elem); - should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE && + decoder_space_usage = + grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata); + should_add_elem = elem_interned && + decoder_space_usage < MAX_DECODER_SPACE_USAGE && c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; + should_add_key = + !elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE; /* no hits for the elem... maybe there's a key? */ @@ -493,7 +511,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - add_elem(exec_ctx, c, elem); + add_elem(exec_ctx, c, elem, decoder_space_usage, false); return; } else { emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st); @@ -509,7 +527,7 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, /* HIT: key (first cuckoo hash) */ if (should_add_elem) { emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - add_elem(exec_ctx, c, elem); + add_elem(exec_ctx, c, elem, decoder_space_usage, false); return; } else { emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st); @@ -520,9 +538,9 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, /* no elem, key in the table... fall back to literal emission */ - if (should_add_elem) { + if (should_add_elem || should_add_key) { emit_lithdr_incidx_v(exec_ctx, c, elem, st); - add_elem(exec_ctx, c, elem); + add_elem(exec_ctx, c, elem, decoder_space_usage, should_add_key); return; } else { emit_lithdr_noidx_v(exec_ctx, c, elem, st); diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc index 5455b2481b..2392f26c0b 100644 --- a/src/core/lib/transport/metadata.cc +++ b/src/core/lib/transport/metadata.cc @@ -352,11 +352,14 @@ static size_t get_base64_encoded_size(size_t raw_length) { return raw_length / 3 * 4 + tail_xtra[raw_length % 3]; } -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem) { +size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem, + bool use_true_binary_metadata) { size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem)); if (grpc_is_binary_header(GRPC_MDKEY(elem))) { - return overhead_and_key + get_base64_encoded_size(value_len); + return overhead_and_key + (use_true_binary_metadata + ? value_len + 1 + : get_base64_encoded_size(value_len)); } else { return overhead_and_key + value_len; } diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h index 9f82225dc3..3f1032ab8a 100644 --- a/src/core/lib/transport/metadata.h +++ b/src/core/lib/transport/metadata.h @@ -132,7 +132,8 @@ grpc_mdelem grpc_mdelem_create( bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); -size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem); +size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem, + bool use_true_binary_metadata); /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ diff --git a/test/core/transport/chttp2/hpack_encoder_test.c b/test/core/transport/chttp2/hpack_encoder_test.c index ed51dd1859..a2af83b6cb 100644 --- a/test/core/transport/chttp2/hpack_encoder_test.c +++ b/test/core/transport/chttp2/hpack_encoder_test.c @@ -43,10 +43,15 @@ void **to_delete = NULL; size_t num_to_delete = 0; size_t cap_to_delete = 0; +typedef struct { + bool eof; + bool use_true_binary_metadata; + bool only_intern_key; +} verify_params; + /* verify that the output generated by encoding the stream matches the hexstring passed in */ -static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof, - bool use_true_binary_metadata, size_t expect_window_used, +static void verify(grpc_exec_ctx *exec_ctx, const verify_params params, const char *expected, size_t nheaders, ...) { grpc_slice_buffer output; grpc_slice merged; @@ -66,9 +71,13 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof, e[i - 1].next = &e[i]; e[i].prev = &e[i - 1]; } + grpc_slice value_slice = grpc_slice_from_static_string(value); + if (!params.only_intern_key) { + value_slice = grpc_slice_intern(value_slice); + } e[i].md = grpc_mdelem_from_slices( exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)), - grpc_slice_intern(grpc_slice_from_static_string(value))); + value_slice); } e[0].prev = NULL; e[nheaders - 1].next = NULL; @@ -90,8 +99,8 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof, memset(&stats, 0, sizeof(stats)); grpc_encode_header_options hopt = { .stream_id = 0xdeadbeef, - .is_eof = eof, - .use_true_binary_metadata = use_true_binary_metadata, + .is_eof = params.eof, + .use_true_binary_metadata = params.use_true_binary_metadata, .max_frame_size = 16384, .stats = &stats, }; @@ -119,28 +128,27 @@ static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, bool eof, static void test_basic_headers(grpc_exec_ctx *exec_ctx) { int i; - verify(exec_ctx, 0, false, false, 0, "000005 0104 deadbeef 40 0161 0161", 1, - "a", "a"); - verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a"); - verify(exec_ctx, 0, false, false, 0, "000001 0104 deadbeef be", 1, "a", "a"); - verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef be 40 0162 0163", - 2, "a", "a", "b", "c"); - verify(exec_ctx, 0, false, false, 0, "000002 0104 deadbeef bf be", 2, "a", - "a", "b", "c"); - verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 7f 00 0164", 1, - "a", "d"); + verify_params params = { + .eof = false, .use_true_binary_metadata = false, .only_intern_key = false, + }; + verify(exec_ctx, params, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a"); + verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a"); + verify(exec_ctx, params, "000001 0104 deadbeef be", 1, "a", "a"); + verify(exec_ctx, params, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a", + "b", "c"); + verify(exec_ctx, params, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c"); + verify(exec_ctx, params, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d"); /* flush out what's there to make a few values look very popular */ for (i = 0; i < 350; i++) { - verify(exec_ctx, 0, false, false, 0, "000003 0104 deadbeef c0 bf be", 3, - "a", "a", "b", "c", "a", "d"); + verify(exec_ctx, params, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b", + "c", "a", "d"); } - verify(exec_ctx, 0, false, false, 0, "000006 0104 deadbeef c0 00 016b 0176", - 2, "a", "a", "k", "v"); + verify(exec_ctx, params, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a", + "k", "v"); /* this could be 000004 0104 deadbeef 0f 30 0176 also */ - verify(exec_ctx, 0, false, false, 0, "000004 0104 deadbeef 0f 2f 0176", 1, - "a", "v"); + verify(exec_ctx, params, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v"); } static void encode_int_to_str(int i, char *p) { @@ -156,6 +164,10 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) { char key[3], value[3]; char *expect; + verify_params params = { + .eof = false, .use_true_binary_metadata = false, .only_intern_key = false, + }; + for (i = 0; i < 114; i++) { encode_int_to_str(i, key); encode_int_to_str(i + 1, value); @@ -174,27 +186,28 @@ static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) { } if (i > 0) { - verify(exec_ctx, 0, false, false, 0, expect, 2, "aa", "ba", key, value); + verify(exec_ctx, params, expect, 2, "aa", "ba", key, value); } else { - verify(exec_ctx, 0, false, false, 0, expect, 1, key, value); + verify(exec_ctx, params, expect, 1, key, value); } gpr_free(expect); } /* if the above passes, then we must have just knocked this pair out of the decoder stack, and so we'll be forced to re-encode it */ - verify(exec_ctx, 0, false, false, 0, "000007 0104 deadbeef 40 026161 026261", - 1, "aa", "ba"); + verify(exec_ctx, params, "000007 0104 deadbeef 40 026161 026261", 1, "aa", + "ba"); } static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx, const char *key, - const char *value) { + const char *value, + bool use_true_binary) { grpc_slice_buffer output; grpc_mdelem elem = grpc_mdelem_from_slices( exec_ctx, grpc_slice_intern(grpc_slice_from_static_string(key)), grpc_slice_intern(grpc_slice_from_static_string(value))); - size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); + size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary); size_t initial_table_size = g_compressor.table_size; grpc_linked_mdelem *e = gpr_malloc(sizeof(*e)); grpc_metadata_batch b; @@ -209,11 +222,12 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx, grpc_transport_one_way_stats stats; memset(&stats, 0, sizeof(stats)); - grpc_encode_header_options hopt = {.stream_id = 0xdeadbeef, - .is_eof = false, - .use_true_binary_metadata = false, - .max_frame_size = 16384, - .stats = &stats}; + grpc_encode_header_options hopt = { + .stream_id = 0xdeadbeef, + .is_eof = false, + .use_true_binary_metadata = use_true_binary, + .max_frame_size = 16384, + .stats = &stats}; grpc_chttp2_encode_header(exec_ctx, &g_compressor, NULL, 0, &b, &hopt, &output); grpc_slice_buffer_destroy_internal(exec_ctx, &output); @@ -224,8 +238,24 @@ static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx, } static void test_encode_header_size(grpc_exec_ctx *exec_ctx) { - verify_table_size_change_match_elem_size(exec_ctx, "hello", "world"); - verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world"); + verify_table_size_change_match_elem_size(exec_ctx, "hello", "world", false); + verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world", + false); + verify_table_size_change_match_elem_size(exec_ctx, "true-binary-bin", + "I_am_true_binary_value", true); +} + +static void test_interned_key_indexed(grpc_exec_ctx *exec_ctx) { + int i; + verify_params params = { + .eof = false, .use_true_binary_metadata = false, .only_intern_key = true, + }; + verify(exec_ctx, params, "000009 0104 deadbeef 40 0161 0162 0f2f 0163", 2, + "a", "b", "a", "c"); + for (i = 0; i < 10; i++) { + verify(exec_ctx, params, "000008 0104 deadbeef 0f2f 0162 0f2f 0163", 2, "a", + "b", "a", "c"); + } } static void run_test(void (*test)(grpc_exec_ctx *exec_ctx), const char *name) { @@ -245,6 +275,7 @@ int main(int argc, char **argv) { TEST(test_basic_headers); TEST(test_decode_table_overflow); TEST(test_encode_header_size); + TEST(test_interned_key_indexed); grpc_shutdown(); for (i = 0; i < num_to_delete; i++) { gpr_free(to_delete[i]); diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c index cb06fce30b..f7124d29a7 100644 --- a/test/core/transport/metadata_test.c +++ b/test/core/transport/metadata_test.c @@ -302,7 +302,7 @@ static void verify_ascii_header_size(grpc_exec_ctx *exec_ctx, const char *key, grpc_mdelem elem = grpc_mdelem_from_slices( exec_ctx, maybe_intern(grpc_slice_from_static_string(key), intern_key), maybe_intern(grpc_slice_from_static_string(value), intern_value)); - size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); + size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false); size_t expected_size = 32 + strlen(key) + strlen(value); GPR_ASSERT(expected_size == elem_size); GRPC_MDELEM_UNREF(exec_ctx, elem); @@ -316,7 +316,7 @@ static void verify_binary_header_size(grpc_exec_ctx *exec_ctx, const char *key, maybe_intern(grpc_slice_from_static_buffer(value, value_len), intern_value)); GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem))); - size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem); + size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false); grpc_slice value_slice = grpc_slice_from_copied_buffer((const char *)value, value_len); grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice); -- cgit v1.2.3 From b7cc8b0b8de063a37ccbeffd21f4225d48161cbf Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 11 Oct 2017 15:50:58 -0700 Subject: Resolve comments --- .../transport/chttp2/transport/hpack_encoder.cc | 204 ++++++++++++--------- 1 file changed, 117 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc index e667d8829a..0ea50e394b 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc @@ -178,22 +178,19 @@ static void evict_entry(grpc_chttp2_hpack_compressor *c) { c->table_elems--; } -/* add an element to the decoder table */ -static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem elem, size_t elem_size, bool only_add_key) { - uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); - uint32_t value_hash = only_add_key ? 0 : grpc_slice_hash(GRPC_MDVALUE(elem)); - uint32_t elem_hash = - only_add_key ? 0 : GRPC_MDSTR_KV_HASH(key_hash, value_hash); +// Reserve space in table for the new element, evict entries if needed. +// Return the new index of the element. Return 0 to indicate not adding to +// table. +static uint32_t prepare_space_for_new_elem(grpc_chttp2_hpack_compressor *c, + size_t elem_size) { uint32_t new_index = c->tail_remote_index + c->table_elems + 1; - GPR_ASSERT(elem_size < 65536); if (elem_size > c->max_table_size) { while (c->table_size > 0) { evict_entry(c); } - return; + return 0; } /* Reserve space for this element in the remote table: if this overflows @@ -207,6 +204,25 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, c->table_size = (uint16_t)(c->table_size + elem_size); c->table_elems++; + return new_index; +} + +/* dummy function */ +static void add_nothing(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, grpc_mdelem elem, + size_t elem_size) {} + +// Add a key to the dynamic table. Both key and value will be added to table at +// the decoder. +static void add_key_with_index(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem, uint32_t new_index) { + if (new_index == 0) { + return; + } + + uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + /* Store the key into {entries,indices}_keys */ if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem))) { @@ -238,37 +254,63 @@ static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, grpc_slice_ref_internal(GRPC_MDKEY(elem)); c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index; } +} - if (!only_add_key) { - /* Store this element into {entries,indices}_elem */ - if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { - /* already there: update with new index */ - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], - elem)) { - /* already there (cuckoo): update with new index */ - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { - /* not there, but a free element: add */ - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { - /* not there (cuckoo), but a free element: add */ - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < - c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; - } else { - /* not there: replace oldest */ - GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); - c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); - c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; - } +/* add an element to the decoder table */ +static void add_elem_with_index(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem, uint32_t new_index) { + if (new_index == 0) { + return; } + GPR_ASSERT(GRPC_MDELEM_IS_INTERNED(elem)); + + uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); + + /* Store this element into {entries,indices}_elem */ + if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_2(elem_hash)], elem)) { + /* already there: update with new index */ + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (grpc_mdelem_eq(c->entries_elems[HASH_FRAGMENT_3(elem_hash)], + elem)) { + /* already there (cuckoo): update with new index */ + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_2(elem_hash)])) { + /* not there, but a free element: add */ + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else if (GRPC_MDISNULL(c->entries_elems[HASH_FRAGMENT_3(elem_hash)])) { + /* not there (cuckoo), but a free element: add */ + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] < + c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index; + } else { + /* not there: replace oldest */ + GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]); + c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem); + c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index; + } + + add_key_with_index(exec_ctx, c, elem, new_index); +} + +static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem, size_t elem_size) { + uint32_t new_index = prepare_space_for_new_elem(c, elem_size); + add_elem_with_index(exec_ctx, c, elem, new_index); +} + +static void add_key(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, + grpc_mdelem elem, size_t elem_size) { + uint32_t new_index = prepare_space_for_new_elem(c, elem_size); + add_key_with_index(exec_ctx, c, elem, new_index); } static void emit_indexed(grpc_exec_ctx *exec_ctx, @@ -362,7 +404,9 @@ static void emit_lithdr_noidx(grpc_exec_ctx *exec_ctx, static void emit_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem elem, framer_state *st) { + uint32_t unused_index, grpc_mdelem elem, + framer_state *st) { + GPR_ASSERT(unused_index == 0); GRPC_STATS_INC_HPACK_SEND_LITHDR_INCIDX_V(exec_ctx); GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx); uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); @@ -384,7 +428,9 @@ static void emit_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, static void emit_lithdr_noidx_v(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, - grpc_mdelem elem, framer_state *st) { + uint32_t unused_index, grpc_mdelem elem, + framer_state *st) { + GPR_ASSERT(unused_index == 0); GRPC_STATS_INC_HPACK_SEND_LITHDR_NOTIDX_V(exec_ctx); GRPC_STATS_INC_HPACK_SEND_UNCOMPRESSED(exec_ctx); uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(GRPC_MDKEY(elem)); @@ -452,22 +498,15 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, // Key is not interned, emit literals. if (!key_interned) { - emit_lithdr_noidx_v(exec_ctx, c, elem, st); + emit_lithdr_noidx_v(exec_ctx, c, 0, elem, st); return; } - uint32_t key_hash; - uint32_t value_hash; - uint32_t elem_hash; - size_t decoder_space_usage; - uint32_t indices_key; - bool should_add_elem; - bool should_add_key; - - key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + uint32_t key_hash = grpc_slice_hash(GRPC_MDKEY(elem)); + uint32_t elem_hash = 0; if (elem_interned) { - value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); + uint32_t value_hash = grpc_slice_hash(GRPC_MDVALUE(elem)); elem_hash = GRPC_MDSTR_KV_HASH(key_hash, value_hash); inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, @@ -492,32 +531,31 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, } } + uint32_t indices_key; + /* should this elem be in the table? */ - decoder_space_usage = + size_t decoder_space_usage = grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata); - should_add_elem = elem_interned && - decoder_space_usage < MAX_DECODER_SPACE_USAGE && - c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= - c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; - should_add_key = - !elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE; + bool should_add_elem = elem_interned && + decoder_space_usage < MAX_DECODER_SPACE_USAGE && + c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >= + c->filter_elems_sum / ONE_ON_ADD_PROBABILITY; + void (*maybe_add)(grpc_exec_ctx *, grpc_chttp2_hpack_compressor *, + grpc_mdelem, size_t) = + should_add_elem ? add_elem : add_nothing; + void (*emit)(grpc_exec_ctx *, grpc_chttp2_hpack_compressor *, uint32_t, + grpc_mdelem, framer_state *) = + should_add_elem ? emit_lithdr_incidx : emit_lithdr_noidx; /* no hits for the elem... maybe there's a key? */ - indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)]; if (grpc_slice_eq(c->entries_keys[HASH_FRAGMENT_2(key_hash)], GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ - if (should_add_elem) { - emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - add_elem(exec_ctx, c, elem, decoder_space_usage, false); - return; - } else { - emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); + emit(exec_ctx, c, dynidx(c, indices_key), elem, st); + maybe_add(exec_ctx, c, elem, decoder_space_usage); + return; } indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)]; @@ -525,28 +563,20 @@ static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c, GRPC_MDKEY(elem)) && indices_key > c->tail_remote_index) { /* HIT: key (first cuckoo hash) */ - if (should_add_elem) { - emit_lithdr_incidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - add_elem(exec_ctx, c, elem, decoder_space_usage, false); - return; - } else { - emit_lithdr_noidx(exec_ctx, c, dynidx(c, indices_key), elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); + emit(exec_ctx, c, dynidx(c, indices_key), elem, st); + maybe_add(exec_ctx, c, elem, decoder_space_usage); + return; } /* no elem, key in the table... fall back to literal emission */ - - if (should_add_elem || should_add_key) { - emit_lithdr_incidx_v(exec_ctx, c, elem, st); - add_elem(exec_ctx, c, elem, decoder_space_usage, should_add_key); - return; - } else { - emit_lithdr_noidx_v(exec_ctx, c, elem, st); - return; - } - GPR_UNREACHABLE_CODE(return ); + bool should_add_key = + !elem_interned && decoder_space_usage < MAX_DECODER_SPACE_USAGE; + emit = (should_add_elem || should_add_key) ? emit_lithdr_incidx_v + : emit_lithdr_noidx_v; + maybe_add = + should_add_elem ? add_elem : (should_add_key ? add_key : add_nothing); + emit(exec_ctx, c, 0, elem, st); + maybe_add(exec_ctx, c, elem, decoder_space_usage); } #define STRLEN_LIT(x) (sizeof(x) - 1) -- cgit v1.2.3 From a33eb8d7004c432880ffaaa11b591e59348df68d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 16 Oct 2017 19:18:50 -0700 Subject: Fix breakage --- src/core/lib/security/credentials/oauth2/oauth2_credentials.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index f52a424e36..7867105f56 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -262,7 +262,7 @@ static bool oauth2_token_fetcher_get_request_metadata( grpc_mdelem cached_access_token_md = GRPC_MDNULL; gpr_mu_lock(&c->mu); if (!GRPC_MDISNULL(c->access_token_md) && - (c->token_expiration + grpc_exec_ctx_now(exec_ctx) > refresh_threshold)) { + (c->token_expiration - grpc_exec_ctx_now(exec_ctx) > refresh_threshold)) { cached_access_token_md = GRPC_MDELEM_REF(c->access_token_md); } if (!GRPC_MDISNULL(cached_access_token_md)) { -- cgit v1.2.3 From 1f42fae4c5125c33f7b953d0d0073af8f8e4397e Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Tue, 17 Oct 2017 08:38:20 +0200 Subject: Fix initialization bug in channel creation --- src/cpp/client/create_channel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index e2893c8f3c..142d7beabe 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -38,7 +38,7 @@ std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { - internal::GrpcLibrary + GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds. return creds ? creds->CreateChannel(target, args) -- cgit v1.2.3 From ce9bd53910199fe945461e0115b5314ef69b4f4e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 17 Oct 2017 11:28:37 +0200 Subject: fix grpc_millis_to_timespec on 32bit --- src/core/lib/iomgr/exec_ctx.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc index 3d17afcb8f..0394a00f3e 100644 --- a/src/core/lib/iomgr/exec_ctx.cc +++ b/src/core/lib/iomgr/exec_ctx.cc @@ -152,6 +152,15 @@ void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx) { gpr_timespec grpc_millis_to_timespec(grpc_millis millis, gpr_clock_type clock_type) { + // special-case infinities as grpc_millis can be 32bit on some platforms + // while gpr_time_from_millis always takes an int64_t. + if (millis == GRPC_MILLIS_INF_FUTURE) { + return gpr_inf_future(clock_type); + } + if (millis == GRPC_MILLIS_INF_PAST) { + return gpr_inf_past(clock_type); + } + if (clock_type == GPR_TIMESPAN) { return gpr_time_from_millis(millis, GPR_TIMESPAN); } -- cgit v1.2.3 From 53cec0fc8fa170aefc641aaade014d8642f33302 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Tue, 17 Oct 2017 06:46:19 -0700 Subject: Update create_channel.cc --- src/cpp/client/create_channel.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 142d7beabe..de67281dd4 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -38,8 +38,7 @@ std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { - GrpcLibraryCodegen - init_lib; // We need to call init in case of a bad creds. + GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds. return creds ? creds->CreateChannel(target, args) : CreateChannelInternal("", grpc_lame_client_channel_create( -- cgit v1.2.3 From 658f5bd85adc34475c1f2d06e46d56fdf79c10eb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 17 Oct 2017 09:12:34 -0700 Subject: Fix ubsan reported failure --- src/core/lib/iomgr/ev_epollex_linux.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 1e8de8910e..8035159b5a 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -1323,8 +1323,10 @@ static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx, a->pollsets = (pollable **)gpr_realloc( a->pollsets, a->pollset_capacity * sizeof(*a->pollsets)); } - memcpy(a->pollsets + a->pollset_count, b->pollsets, - b->pollset_count * sizeof(*b->pollsets)); + if (b->pollset_count > 0) { + memcpy(a->pollsets + a->pollset_count, b->pollsets, + b->pollset_count * sizeof(*b->pollsets)); + } a->pollset_count += b->pollset_count; gpr_free(b->fds); gpr_free(b->pollsets); -- cgit v1.2.3 From 1c0a3367d473f889600796826827c806a57298c4 Mon Sep 17 00:00:00 2001 From: Ryan Gordon Date: Tue, 17 Oct 2017 09:23:09 -0700 Subject: Fixing return value documentation on PHP addSecureHttp2Port and addHttp2Port --- src/php/ext/grpc/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c index e46037743d..a65d233017 100644 --- a/src/php/ext/grpc/server.c +++ b/src/php/ext/grpc/server.c @@ -169,7 +169,7 @@ PHP_METHOD(Server, requestCall) { /** * Add a http2 over tcp listener. * @param string $addr The address to add - * @return bool True on success, false on failure + * @return int Port on success, 0 on failure */ PHP_METHOD(Server, addHttp2Port) { const char *addr; @@ -190,7 +190,7 @@ PHP_METHOD(Server, addHttp2Port) { * Add a secure http2 over tcp listener. * @param string $addr The address to add * @param ServerCredentials The ServerCredentials object - * @return bool True on success, false on failure + * @return int Port on success, 0 on failure */ PHP_METHOD(Server, addSecureHttp2Port) { const char *addr; -- cgit v1.2.3 From 8223f4172f0a5739813fe6bb82863e68a2f588c9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 17 Oct 2017 22:05:55 +0000 Subject: Fixes --- src/core/lib/iomgr/ev_epollex_linux.cc | 67 ++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index 566986a774..fb94b8e513 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -54,6 +54,9 @@ // use-after-destruction) //#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1 +#define MAX_EPOLL_EVENTS 100 +#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5 + #ifndef NDEBUG grpc_tracer_flag grpc_trace_pollable_refcount = GRPC_TRACER_INITIALIZER(false, "pollable_refcount"); @@ -83,6 +86,10 @@ struct pollable { gpr_mu mu; grpc_pollset_worker *root_worker; + + int event_cursor; + int event_count; + struct epoll_event events[MAX_EPOLL_EVENTS]; }; static const char *pollable_type_string(pollable_type t) { @@ -174,9 +181,6 @@ struct grpc_pollset_worker { pwlink links[PWLINK_COUNT]; }; -#define MAX_EPOLL_EVENTS 100 -#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5 - struct grpc_pollset { gpr_mu mu; pollable *active_pollable; @@ -184,10 +188,6 @@ struct grpc_pollset { grpc_closure *shutdown_closure; grpc_pollset_worker *root_worker; int containing_pollset_set_count; - - int event_cursor; - int event_count; - struct epoll_event events[MAX_EPOLL_EVENTS]; }; /******************************************************************************* @@ -725,15 +725,15 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset_maybe_finish_shutdown(exec_ctx, pollset); } -static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, bool drain) { +static grpc_error *pollable_process_events(grpc_exec_ctx *exec_ctx, grpc_pollset*pollset, + pollable *pollable_obj, bool drain) { static const char *err_desc = "pollset_process_events"; grpc_error *error = GRPC_ERROR_NONE; for (int i = 0; (drain || i < MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL) && - pollset->event_cursor != pollset->event_count; + pollable_obj->event_cursor != pollable_obj->event_count; i++) { - int n = pollset->event_cursor++; - struct epoll_event *ev = &pollset->events[n]; + int n = pollable_obj->event_cursor++; + struct epoll_event *ev = &pollable_obj->events[n]; void *data_ptr = ev->data.ptr; if (1 & (intptr_t)data_ptr) { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -770,8 +770,6 @@ static grpc_error *pollset_process_events(grpc_exec_ctx *exec_ctx, static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { POLLABLE_UNREF(pollset->active_pollable, "pollset"); pollset->active_pollable = NULL; - GRPC_LOG_IF_ERROR("pollset_process_events", - pollset_process_events(exec_ctx, pollset, true)); } static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, @@ -790,7 +788,7 @@ static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, int r; do { GRPC_STATS_INC_SYSCALL_POLL(exec_ctx); - r = epoll_wait(p->epfd, pollset->events, MAX_EPOLL_EVENTS, timeout); + r = epoll_wait(p->epfd, p->events, MAX_EPOLL_EVENTS, timeout); } while (r < 0 && errno == EINTR); if (timeout != 0) { GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx); @@ -802,8 +800,8 @@ static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_log(GPR_DEBUG, "PS:%p poll %p got %d events", pollset, p, r); } - pollset->event_cursor = 0; - pollset->event_count = r; + p->event_cursor = 0; + p->event_count = r; return GRPC_ERROR_NONE; } @@ -852,7 +850,7 @@ static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl, grpc_millis deadline) { - bool do_poll = true; + bool do_poll = (pollset->shutdown_closure == nullptr); if (worker_hdl != NULL) *worker_hdl = worker; worker->initialized_cv = false; worker->kicked = false; @@ -899,23 +897,33 @@ static bool begin_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_unlock(&worker->pollable_obj->mu); return do_poll; - // && pollset->shutdown_closure == NULL && pollset->active_pollable == - // worker->pollable_obj; } static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_pollset_worker **worker_hdl) { + gpr_mu_lock(&pollset->mu); gpr_mu_lock(&worker->pollable_obj->mu); - if (worker_remove(&worker->pollable_obj->root_worker, worker, - PWLINK_POLLABLE) == WRR_NEW_ROOT) { - grpc_pollset_worker *new_root = worker->pollable_obj->root_worker; - GPR_ASSERT(new_root->initialized_cv); - gpr_cv_signal(&new_root->cv); + switch (worker_remove(&worker->pollable_obj->root_worker, worker, + PWLINK_POLLABLE)) { + case WRR_NEW_ROOT: { + // wakeup new poller + grpc_pollset_worker *new_root = worker->pollable_obj->root_worker; + GPR_ASSERT(new_root->initialized_cv); + gpr_cv_signal(&new_root->cv); + break; + } + case WRR_EMPTIED: + if (pollset->active_pollable != worker->pollable_obj) { + // pollable no longer being polled: flush events + pollable_process_events(exec_ctx, pollset, worker->pollable_obj, true); + } + break; + case WRR_REMOVED: + break; } gpr_mu_unlock(&worker->pollable_obj->mu); POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); - gpr_mu_lock(&pollset->mu); if (worker_remove(&pollset->root_worker, worker, PWLINK_POLLSET) == WRR_EMPTIED) { pollset_maybe_finish_shutdown(exec_ctx, pollset); @@ -957,12 +965,14 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (begin_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl, deadline)) { gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); - if (pollset->event_cursor == pollset->event_count) { + if (WORKER_PTR->pollable_obj->event_cursor == WORKER_PTR->pollable_obj->event_count) { append_error(&error, pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, deadline), err_desc); } - append_error(&error, pollset_process_events(exec_ctx, pollset, false), + append_error(&error, + pollable_process_events( + exec_ctx, pollset, WORKER_PTR->pollable_obj, false), err_desc); grpc_exec_ctx_flush(exec_ctx); gpr_tls_set(&g_current_thread_pollset, 0); @@ -973,6 +983,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, #ifdef GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP gpr_free(worker); #endif +#undef WORKER_PTR return error; } -- cgit v1.2.3 From 96e247042576decc655004e8413f670c082a4b1e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 17 Oct 2017 15:06:46 -0700 Subject: clang-format --- src/core/lib/iomgr/ev_epollex_linux.cc | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index fb94b8e513..c9e9fcae76 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -725,8 +725,9 @@ static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset_maybe_finish_shutdown(exec_ctx, pollset); } -static grpc_error *pollable_process_events(grpc_exec_ctx *exec_ctx, grpc_pollset*pollset, - pollable *pollable_obj, bool drain) { +static grpc_error *pollable_process_events(grpc_exec_ctx *exec_ctx, + grpc_pollset *pollset, + pollable *pollable_obj, bool drain) { static const char *err_desc = "pollset_process_events"; grpc_error *error = GRPC_ERROR_NONE; for (int i = 0; (drain || i < MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL) && @@ -905,22 +906,22 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_mu_lock(&pollset->mu); gpr_mu_lock(&worker->pollable_obj->mu); switch (worker_remove(&worker->pollable_obj->root_worker, worker, - PWLINK_POLLABLE)) { - case WRR_NEW_ROOT: { + PWLINK_POLLABLE)) { + case WRR_NEW_ROOT: { // wakeup new poller grpc_pollset_worker *new_root = worker->pollable_obj->root_worker; GPR_ASSERT(new_root->initialized_cv); gpr_cv_signal(&new_root->cv); break; } - case WRR_EMPTIED: - if (pollset->active_pollable != worker->pollable_obj) { - // pollable no longer being polled: flush events - pollable_process_events(exec_ctx, pollset, worker->pollable_obj, true); - } - break; - case WRR_REMOVED: - break; + case WRR_EMPTIED: + if (pollset->active_pollable != worker->pollable_obj) { + // pollable no longer being polled: flush events + pollable_process_events(exec_ctx, pollset, worker->pollable_obj, true); + } + break; + case WRR_REMOVED: + break; } gpr_mu_unlock(&worker->pollable_obj->mu); POLLABLE_UNREF(worker->pollable_obj, "pollset_worker"); @@ -965,14 +966,15 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (begin_worker(exec_ctx, pollset, WORKER_PTR, worker_hdl, deadline)) { gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset); gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); - if (WORKER_PTR->pollable_obj->event_cursor == WORKER_PTR->pollable_obj->event_count) { + if (WORKER_PTR->pollable_obj->event_cursor == + WORKER_PTR->pollable_obj->event_count) { append_error(&error, pollset_epoll(exec_ctx, pollset, WORKER_PTR->pollable_obj, deadline), err_desc); } append_error(&error, - pollable_process_events( - exec_ctx, pollset, WORKER_PTR->pollable_obj, false), + pollable_process_events(exec_ctx, pollset, + WORKER_PTR->pollable_obj, false), err_desc); grpc_exec_ctx_flush(exec_ctx); gpr_tls_set(&g_current_thread_pollset, 0); -- cgit v1.2.3 From d4a0eb281ce93c67689a2603eab88fbab53e30a9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 09:27:15 -0700 Subject: Flag protect epoll exclusive for now --- src/core/lib/iomgr/ev_epollex_linux.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index c9e9fcae76..feda517b49 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -1411,6 +1411,10 @@ static const grpc_event_engine_vtable vtable = { const grpc_event_engine_vtable *grpc_init_epollex_linux( bool explicitly_requested) { + if (!explicitly_requested) { + return NULL; + } + if (!grpc_has_wakeup_fd()) { return NULL; } -- cgit v1.2.3 From 5d9db0c26b7aa0eaa1b1a86b4945f14c44157240 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 09:43:55 -0700 Subject: Handle review feedback --- src/core/lib/iomgr/ev_epollex_linux.cc | 59 +++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index feda517b49..bee464cab1 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -70,6 +70,14 @@ typedef enum { PO_MULTI, PO_FD, PO_EMPTY } pollable_type; typedef struct pollable pollable; +/// A pollable is something that can be polled: it has an epoll set to poll on, +/// and a wakeup fd for kicks +/// There are three broad types: +/// - PO_EMPTY - the empty pollable, used before file descriptors are added to +/// a pollset +/// - PO_FD - a pollable containing only one FD - used to optimize single-fd +/// pollsets (which are common with synchronous api usage) +/// - PO_MULTI - a pollable containing many fds struct pollable { pollable_type type; // immutable gpr_refcount refs; @@ -111,6 +119,8 @@ static char *pollable_desc(pollable *p) { return out; } +/// Shared empty pollable - used by pollset to poll on until the first fd is +/// added static pollable *g_empty_pollable; static grpc_error *pollable_create(pollable_type type, pollable **p); @@ -173,7 +183,10 @@ typedef enum { PWLINK_POLLABLE = 0, PWLINK_POLLSET, PWLINK_COUNT } pwlinks; struct grpc_pollset_worker { bool kicked; bool initialized_cv; +#ifndef NDEBUG + // debug aid: which thread started this worker pid_t originator; +#endif gpr_cv cv; grpc_pollset *pollset; pollable *pollable_obj; @@ -239,11 +252,6 @@ static bool append_error(grpc_error **composite, grpc_error *error, * becomes a spurious read notification on a reused fd. */ -/* The alarm system needs to be able to wakeup 'some poller' sometimes - * (specifically when a new alarm needs to be triggered earlier than the next - * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a - * case occurs. */ - static grpc_fd *fd_freelist = NULL; static gpr_mu fd_freelist_mu; @@ -543,6 +551,7 @@ static void pollset_global_shutdown(void) { gpr_tls_destroy(&g_current_thread_worker); } +/* pollset->mu must be held while calling this function */ static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { if (GRPC_TRACER_ON(grpc_polling_trace)) { @@ -562,9 +571,8 @@ static void pollset_maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, /* pollset->mu must be held before calling this function, * pollset->active_pollable->mu & specific_worker->pollable_obj->mu must not be * held */ -static grpc_error *pollset_kick_one(grpc_exec_ctx *exec_ctx, - grpc_pollset *pollset, - grpc_pollset_worker *specific_worker) { +static grpc_error *kick_one_worker(grpc_exec_ctx *exec_ctx, + grpc_pollset_worker *specific_worker) { pollable *p = specific_worker->pollable_obj; grpc_core::mu_guard lock(&p->mu); GRPC_STATS_INC_POLLSET_KICK(exec_ctx); @@ -623,21 +631,22 @@ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_any_without_poller", pollset); } + GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER(exec_ctx); pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; } else { - return pollset_kick_one( - exec_ctx, pollset, - pollset->root_worker->links[PWLINK_POLLSET].next); + return kick_one_worker( + exec_ctx, pollset->root_worker->links[PWLINK_POLLSET].next); } } else { if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p kicked_any_but_awake", pollset); } + GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx); return GRPC_ERROR_NONE; } } else { - return pollset_kick_one(exec_ctx, pollset, specific_worker); + return kick_one_worker(exec_ctx, specific_worker); } } @@ -648,7 +657,7 @@ static grpc_error *pollset_kick_all(grpc_exec_ctx *exec_ctx, grpc_pollset_worker *w = pollset->root_worker; if (w != NULL) { do { - append_error(&error, pollset_kick_one(exec_ctx, pollset, w), err_desc); + append_error(&error, kick_one_worker(exec_ctx, w), err_desc); w = w->links[PWLINK_POLLSET].next; } while (w != pollset->root_worker); } @@ -690,10 +699,10 @@ static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { grpc_lfev_set_ready(exec_ctx, &fd->write_closure, "write"); } -static grpc_error *fd_become_pollable(grpc_fd *fd, pollable **p) { +static grpc_error *fd_get_or_become_pollable(grpc_fd *fd, pollable **p) { gpr_mu_lock(&fd->pollable_mu); grpc_error *error = GRPC_ERROR_NONE; - static const char *err_desc = "fd_become_pollable"; + static const char *err_desc = "fd_get_or_become_pollable"; if (fd->pollable_obj == NULL) { if (append_error(&error, pollable_create(PO_FD, &fd->pollable_obj), err_desc)) { @@ -773,13 +782,13 @@ static void pollset_destroy(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { pollset->active_pollable = NULL; } -static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, - pollable *p, grpc_millis deadline) { +static grpc_error *pollable_epoll(grpc_exec_ctx *exec_ctx, pollable *p, + grpc_millis deadline) { int timeout = poll_deadline_to_millis_timeout(exec_ctx, deadline); if (GRPC_TRACER_ON(grpc_polling_trace)) { char *desc = pollable_desc(p); - gpr_log(GPR_DEBUG, "PS:%p poll %p[%s] for %dms", pollset, p, desc, timeout); + gpr_log(GPR_DEBUG, "POLLABLE:%p[%s] poll for %dms", p, desc, timeout); gpr_free(desc); } @@ -798,7 +807,7 @@ static grpc_error *pollset_epoll(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait"); if (GRPC_TRACER_ON(grpc_polling_trace)) { - gpr_log(GPR_DEBUG, "PS:%p poll %p got %d events", pollset, p, r); + gpr_log(GPR_DEBUG, "POLLABLE:%p got %d events", p, r); } p->event_cursor = 0; @@ -934,9 +943,11 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, } } +#ifndef NDEBUG static long gettid(void) { return syscall(__NR_gettid); } +#endif -/* pollset->po.mu lock must be held by the caller before calling this. +/* pollset->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 */ @@ -951,7 +962,9 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker worker; #define WORKER_PTR (&worker) #endif +#ifndef NDEBUG WORKER_PTR->originator = gettid(); +#endif if (GRPC_TRACER_ON(grpc_polling_trace)) { gpr_log(GPR_DEBUG, "PS:%p work hdl=%p worker=%p now=%" PRIdPTR " deadline=%" PRIdPTR " kwp=%d pollable=%p", @@ -968,8 +981,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR); if (WORKER_PTR->pollable_obj->event_cursor == WORKER_PTR->pollable_obj->event_count) { - append_error(&error, pollset_epoll(exec_ctx, pollset, - WORKER_PTR->pollable_obj, deadline), + append_error(&error, pollable_epoll(exec_ctx, WORKER_PTR->pollable_obj, + deadline), err_desc); } append_error(&error, @@ -1000,7 +1013,7 @@ static grpc_error *pollset_transition_pollable_from_empty_to_fd_locked( } append_error(&error, pollset_kick_all(exec_ctx, pollset), err_desc); POLLABLE_UNREF(pollset->active_pollable, "pollset"); - append_error(&error, fd_become_pollable(fd, &pollset->active_pollable), + append_error(&error, fd_get_or_become_pollable(fd, &pollset->active_pollable), err_desc); return error; } -- cgit v1.2.3 From 7c8e59d0efc1b2502b3265d177df96e49c2fc4b7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 11:57:25 -0700 Subject: Add an essay --- src/core/lib/iomgr/ev_epollex_linux.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index bee464cab1..f151bff441 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -635,6 +635,21 @@ static grpc_error *pollset_kick(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, pollset->kicked_without_poller = true; return GRPC_ERROR_NONE; } else { + // We've been asked to kick a poller, but we haven't been told which one + // ... any will do + // We look at the pollset worker list because: + // 1. the pollable list may include workers from other pollers, so we'd + // need to do an O(N) search + // 2. we'd additionally need to take the pollable lock, which we've so + // far avoided + // Now, we would prefer to wake a poller in cv_wait, and not in + // epoll_wait (since the latter would imply the need to do an additional + // wakeup) + // We know that if a worker is at the root of a pollable, it's (likely) + // also the root of a pollset, and we know that if a worker is NOT at + // the root of a pollset, it's (likely) not at the root of a pollable, + // so we take our chances and choose the SECOND worker enqueued against + // the pollset as a worker that's likely to be in cv_wait return kick_one_worker( exec_ctx, pollset->root_worker->links[PWLINK_POLLSET].next); } -- cgit v1.2.3 From 8b761cfbe2330d18acc69196d19b1a3623e47463 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 12:02:21 -0700 Subject: Add comment --- src/core/ext/transport/chttp2/transport/flow_control.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 33542a31e4..7bcb3e8f37 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -150,6 +150,11 @@ class TransportFlowControl { // tell chttp2 exactly what it needs to do FlowControlAction MakeAction() { return UpdateAction(FlowControlAction()); } + // Call periodically (at a low-ish rate, 100ms - 10s makes sense) + // to perform more complex flow control calculations and return an action + // to let chttp2 change its parameters + FlowControlAction PeriodicUpdate(grpc_exec_ctx* exec_ctx); + void StreamSentData(int64_t size) { remote_window_ -= size; } grpc_error* ValidateRecvData(int64_t incoming_frame_size); @@ -199,8 +204,6 @@ class TransportFlowControl { BdpEstimator* bdp_estimator() { return &bdp_estimator_; } - FlowControlAction PeriodicUpdate(grpc_exec_ctx* exec_ctx); - void TestOnlyForceHugeWindow() { announced_window_ = 1024 * 1024 * 1024; remote_window_ = 1024 * 1024 * 1024; -- cgit v1.2.3 From d0ff8969a2bf2fe1928ed427932f1af8cf56c4b1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 12:03:03 -0700 Subject: Remove dead code --- src/core/ext/transport/chttp2/transport/internal.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index b2d2c1ad90..9e0796e820 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -681,16 +681,6 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, extern grpc_tracer_flag grpc_http_trace; extern grpc_tracer_flag grpc_flowctl_trace; -#ifndef NDEBUG -#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) \ - if (!(GRPC_TRACER_ON(grpc_flowctl_trace))) \ - ; \ - else \ - stmt -#else -#define GRPC_FLOW_CONTROL_IF_TRACING(stmt) -#endif - #define GRPC_CHTTP2_IF_TRACING(stmt) \ if (!(GRPC_TRACER_ON(grpc_http_trace))) \ ; \ -- cgit v1.2.3 From 96582b7f5ebd5729a438d084c344c9556ba6c6b4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 12:19:15 -0700 Subject: Reflow to remove bool --- .../transport/chttp2/transport/chttp2_transport.cc | 16 ++-- .../ext/transport/chttp2/transport/flow_control.cc | 92 +++++++++++----------- .../ext/transport/chttp2/transport/flow_control.h | 19 ++--- src/core/lib/transport/bdp_estimator.h | 11 +-- 4 files changed, 61 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 63ac02d102..02fc53122d 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -281,7 +281,6 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->endpoint_reading = 1; t->next_stream_id = is_client ? 1 : 2; t->is_client = is_client; - t->flow_control.Init(t); t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; t->is_first_frame = true; grpc_connectivity_state_init( @@ -389,6 +388,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->opt_target = GRPC_CHTTP2_OPTIMIZE_FOR_LATENCY; + bool enable_bdp = true; + if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { if (0 == strcmp(channel_args->args[i].key, @@ -449,8 +450,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, &channel_args->args[i], {0, 0, MAX_WRITE_BUFFER_SIZE}); } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { - t->flow_control->SetBdpProbe( - grpc_channel_arg_get_bool(&channel_args->args[i], true)); + enable_bdp = grpc_channel_arg_get_bool(&channel_args->args[i], true); } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) { const int value = grpc_channel_arg_get_integer( @@ -545,6 +545,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } + t->flow_control.Init(exec_ctx, t, enable_bdp); + /* No pings allowed before receiving a header or data frame. */ t->ping_state.pings_before_data_required = 0; t->ping_state.is_delayed_ping_timer_set = false; @@ -565,13 +567,13 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED; } - if (t->flow_control->bdp_probe()) { + if (enable_bdp) { GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping"); schedule_bdp_ping_locked(exec_ctx, t); - } - grpc_chttp2_act_on_flowctl_action( - exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, NULL); + grpc_chttp2_act_on_flowctl_action( + exec_ctx, t->flow_control->PeriodicUpdate(exec_ctx), t, NULL); + } grpc_chttp2_initiate_write(exec_ctx, t, GRPC_CHTTP2_INITIATE_WRITE_INITIAL_WRITE); diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 3b39eb2fdf..436ceedeb0 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -147,8 +147,21 @@ void FlowControlAction::Trace(grpc_chttp2_transport* t) const { gpr_free(mf_str); } -TransportFlowControl::TransportFlowControl(const grpc_chttp2_transport* t) - : t_(t), bdp_estimator_(t->peer_string) {} +TransportFlowControl::TransportFlowControl(grpc_exec_ctx* exec_ctx, + const grpc_chttp2_transport* t, + bool enable_bdp_probe) + : t_(t), + enable_bdp_probe_(enable_bdp_probe), + bdp_estimator_(t->peer_string), + last_pid_update_(grpc_exec_ctx_now(exec_ctx)), + pid_controller_(grpc_core::PidController::Args() + .set_gain_p(4) + .set_gain_i(8) + .set_gain_d(0) + .set_initial_control_value(TargetLogBdp()) + .set_min_control_value(-1) + .set_max_control_value(25) + .set_integral_range(10)) {} uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) { FlowControlTrace trace("t updt sent", this, nullptr); @@ -287,26 +300,19 @@ static double AdjustForMemoryPressure(grpc_resource_quota* quota, return target; } +double TransportFlowControl::TargetLogBdp() { + return AdjustForMemoryPressure( + grpc_resource_user_quota(grpc_endpoint_get_resource_user(t_->ep)), + 1 + log2(bdp_estimator_.EstimateBdp())); +} + double TransportFlowControl::SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value) { grpc_millis now = grpc_exec_ctx_now(exec_ctx); - if (!pid_controller_initialized_) { - last_pid_update_ = now; - pid_controller_initialized_ = true; - pid_controller_.Init(grpc_core::PidController::Args() - .set_gain_p(4) - .set_gain_i(8) - .set_gain_d(0) - .set_initial_control_value(value) - .set_min_control_value(-1) - .set_max_control_value(25) - .set_integral_range(10)); - return value; - } - double bdp_error = value - pid_controller_->last_control_value(); + double bdp_error = value - pid_controller_.last_control_value(); const double dt = (double)(now - last_pid_update_) * 1e-3; last_pid_update_ = now; - return pid_controller_->Update(bdp_error, dt); + return pid_controller_.Update(bdp_error, dt); } FlowControlAction::Urgency TransportFlowControl::DeltaUrgency( @@ -326,39 +332,29 @@ FlowControlAction TransportFlowControl::PeriodicUpdate( FlowControlAction action; if (enable_bdp_probe_) { // get bdp estimate and update initial_window accordingly. - int64_t estimate = -1; - if (bdp_estimator_.EstimateBdp(&estimate)) { - // target might change based on how much memory pressure we are under - // TODO(ncteisen): experiment with setting target to be huge under low - // memory pressure. - const double target = - pow(2, SmoothLogBdp(exec_ctx, - AdjustForMemoryPressure( - grpc_resource_user_quota( - grpc_endpoint_get_resource_user(t_->ep)), - 1 + log2((double)estimate)))); - - // Though initial window 'could' drop to 0, we keep the floor at 128 - target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX); - - action.set_send_initial_window_update( - DeltaUrgency(target_initial_window_size_, - GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE), - target_initial_window_size_); - } + // target might change based on how much memory pressure we are under + // TODO(ncteisen): experiment with setting target to be huge under low + // memory pressure. + const double target = pow(2, SmoothLogBdp(exec_ctx, TargetLogBdp())); + + // Though initial window 'could' drop to 0, we keep the floor at 128 + target_initial_window_size_ = (int32_t)GPR_CLAMP(target, 128, INT32_MAX); + + action.set_send_initial_window_update( + DeltaUrgency(target_initial_window_size_, + GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE), + target_initial_window_size_); // get bandwidth estimate and update max_frame accordingly. - double bw_dbl = -1; - if (bdp_estimator_.EstimateBandwidth(&bw_dbl)) { - // we target the max of BDP or bandwidth in microseconds. - int32_t frame_size = (int32_t)GPR_CLAMP( - GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000, - target_initial_window_size_), - 16384, 16777215); - action.set_send_max_frame_size_update( - DeltaUrgency(frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE), - frame_size); - } + double bw_dbl = bdp_estimator_.EstimateBandwidth(); + // we target the max of BDP or bandwidth in microseconds. + int32_t frame_size = (int32_t)GPR_CLAMP( + GPR_MAX((int32_t)GPR_CLAMP(bw_dbl, 0, INT_MAX) / 1000, + target_initial_window_size_), + 16384, 16777215); + action.set_send_max_frame_size_update( + DeltaUrgency(frame_size, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE), + frame_size); } return UpdateAction(action); } diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 7bcb3e8f37..d5107d467b 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -127,16 +127,9 @@ class FlowControlTrace { class TransportFlowControl { public: - TransportFlowControl(const grpc_chttp2_transport* t); - ~TransportFlowControl() { - if (pid_controller_initialized_) { - pid_controller_.Destroy(); - } - } - - // toggle bdp probing - // TODO(ctiller): make this safe to dynamically toggle - void SetBdpProbe(bool enable) { enable_bdp_probe_ = enable; } + TransportFlowControl(grpc_exec_ctx* exec_ctx, const grpc_chttp2_transport* t, + bool enable_bdp_probe); + ~TransportFlowControl() {} bool bdp_probe() const { return enable_bdp_probe_; } @@ -210,6 +203,7 @@ class TransportFlowControl { } private: + double TargetLogBdp(); double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value); FlowControlAction::Urgency DeltaUrgency(int32_t value, grpc_chttp2_setting_id setting_id); @@ -246,14 +240,13 @@ class TransportFlowControl { int32_t target_initial_window_size_ = kDefaultWindow; /** should we probe bdp? */ - bool enable_bdp_probe_ = true; + const bool enable_bdp_probe_; /* bdp estimation */ grpc_core::BdpEstimator bdp_estimator_; /* pid controller */ - bool pid_controller_initialized_ = false; - grpc_core::ManualConstructor pid_controller_; + grpc_core::PidController pid_controller_; grpc_millis last_pid_update_ = 0; }; diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h index 470c127f7f..750da39599 100644 --- a/src/core/lib/transport/bdp_estimator.h +++ b/src/core/lib/transport/bdp_estimator.h @@ -40,15 +40,8 @@ class BdpEstimator { explicit BdpEstimator(const char *name); ~BdpEstimator() {} - // Returns true if a reasonable estimate could be obtained - bool EstimateBdp(int64_t *estimate_out) const { - *estimate_out = estimate_; - return true; - } - bool EstimateBandwidth(double *bw_out) const { - *bw_out = bw_est_; - return true; - } + int64_t EstimateBdp() const { return estimate_; } + double EstimateBandwidth() const { return bw_est_; } void AddIncomingBytes(int64_t num_bytes) { accumulator_ += num_bytes; } -- cgit v1.2.3 From 828aed5ea45efd0bfbbecd683251cde437a1cbec Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 12:21:37 -0700 Subject: Fix compilation --- src/core/ext/transport/chttp2/transport/flow_control.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index 436ceedeb0..dd80036530 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -153,7 +153,6 @@ TransportFlowControl::TransportFlowControl(grpc_exec_ctx* exec_ctx, : t_(t), enable_bdp_probe_(enable_bdp_probe), bdp_estimator_(t->peer_string), - last_pid_update_(grpc_exec_ctx_now(exec_ctx)), pid_controller_(grpc_core::PidController::Args() .set_gain_p(4) .set_gain_i(8) @@ -161,7 +160,8 @@ TransportFlowControl::TransportFlowControl(grpc_exec_ctx* exec_ctx, .set_initial_control_value(TargetLogBdp()) .set_min_control_value(-1) .set_max_control_value(25) - .set_integral_range(10)) {} + .set_integral_range(10)), + last_pid_update_(grpc_exec_ctx_now(exec_ctx)) {} uint32_t TransportFlowControl::MaybeSendUpdate(bool writing_anyway) { FlowControlTrace trace("t updt sent", this, nullptr); -- cgit v1.2.3 From e29196b2a777e3ce3ab19e9a9c46ae7a9d90526e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 18 Oct 2017 19:52:33 +0000 Subject: Fix bad bug --- src/core/lib/iomgr/ev_epollex_linux.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index f151bff441..fa6d79cbfc 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -472,6 +472,8 @@ static grpc_error *pollable_create(pollable_type type, pollable **p) { (*p)->pollset_set = NULL; (*p)->next = (*p)->prev = *p; (*p)->root_worker = NULL; + (*p)->event_cursor = 0; + (*p)->event_count = 0; return GRPC_ERROR_NONE; } -- cgit v1.2.3