Make sure dedicated pollsets have polling islands. Simplies a lot of

code. Fix init/shutdown
pull/10970/head
Sree Kuchibhotla 8 years ago
parent d4fc32eacd
commit a03edfd285
  1. 135
      src/core/lib/iomgr/ev_epoll_thread_pool_linux.c

@ -221,7 +221,8 @@ struct grpc_pollset *g_pollsets = NULL;
gpr_thd_id *g_poller_threads = NULL; gpr_thd_id *g_poller_threads = NULL;
static void add_fd_to_global_pollset(grpc_fd *fd); static void add_fd_to_global_pollset(grpc_fd *fd);
static void init_dedicated_pollsets(); static bool init_dedicated_pollsets();
static void shutdown_dedicated_pollsets();
static void poller_thread_loop(void *arg); static void poller_thread_loop(void *arg);
static void start_dedicated_poller_threads(); static void start_dedicated_poller_threads();
static void shutdown_dedicated_poller_threads(); static void shutdown_dedicated_poller_threads();
@ -258,7 +259,7 @@ static grpc_wakeup_fd polling_island_wakeup_fd;
static __thread polling_island *g_current_thread_polling_island; static __thread polling_island *g_current_thread_polling_island;
/* Forward declaration */ /* Forward declaration */
static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi); static void polling_island_delete(polling_island *pi);
static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error); grpc_error *error);
@ -337,7 +338,7 @@ static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) {
guaranteed that no one else holds a reference to the polling island (and guaranteed that no one else holds a reference to the polling island (and
that there is no racing pi_add_ref() call either).*/ that there is no racing pi_add_ref() call either).*/
if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) { if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
polling_island_delete(exec_ctx, pi); polling_island_delete(pi);
} }
} }
@ -442,8 +443,7 @@ static void polling_island_remove_fd_locked(polling_island *pi, grpc_fd *fd,
} }
/* Might return NULL in case of an error */ /* Might return NULL in case of an error */
static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, static polling_island *polling_island_create(grpc_fd *initial_fd,
grpc_fd *initial_fd,
grpc_error **error) { grpc_error **error) {
polling_island *pi = NULL; polling_island *pi = NULL;
const char *err_desc = "polling_island_create"; const char *err_desc = "polling_island_create";
@ -486,13 +486,13 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx,
done: done:
if (*error != GRPC_ERROR_NONE) { if (*error != GRPC_ERROR_NONE) {
polling_island_delete(exec_ctx, pi); polling_island_delete(pi);
pi = NULL; pi = NULL;
} }
return pi; return pi;
} }
static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) { static void polling_island_delete(polling_island *pi) {
GPR_ASSERT(pi->fd_cnt == 0); GPR_ASSERT(pi->fd_cnt == 0);
if (pi->epoll_fd >= 0) { if (pi->epoll_fd >= 0) {
@ -807,9 +807,7 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure); grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure);
} }
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
return NULL;
}
/******************************************************************************* /*******************************************************************************
* Pollset Definitions * Pollset Definitions
@ -1042,7 +1040,7 @@ static void pollset_do_epoll_pwait(grpc_exec_ctx *exec_ctx, int epoll_fd,
struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
int ep_rv; int ep_rv;
char *err_msg; char *err_msg;
const char *err_desc = "pollset_work_and_unlock"; const char *err_desc = "pollset_do_epoll_pwait";
int timeout_ms = -1; int timeout_ms = -1;
@ -1095,27 +1093,29 @@ static void pollset_do_epoll_pwait(grpc_exec_ctx *exec_ctx, int epoll_fd,
} }
} }
static void pollset_add_polling_island(grpc_pollset *ps, grpc_error **error) {
GPR_ASSERT(ps->pi == NULL);
ps->pi = polling_island_create(NULL, error);
if (ps->pi) {
PI_ADD_REF(ps->pi, "ps");
GRPC_POLLING_TRACE(
"pollset_add_polling_island: pollset: %p created new pi: %p",
(void *)ps, (void *)ps->pi);
}
}
/* Note: Make sure the pollset has a polling island (i.e pollset->pi != NULL)
* before calling this */
static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset, grpc_error **error) { grpc_pollset *pollset, grpc_error **error) {
GPR_ASSERT(pollset->pi);
int epoll_fd = -1; int epoll_fd = -1;
polling_island *pi = NULL; polling_island *pi = NULL;
GPR_TIMER_BEGIN("pollset_work_and_unlock", 0); GPR_TIMER_BEGIN("pollset_work_and_unlock", 0);
/* Since epoll_fd is immutable, it is safe to read it without a lock on the /* Since epoll_fd is immutable, it is safe to read it without a lock on the
polling island. */ polling island. */
if (pollset->pi == NULL) {
pollset->pi = polling_island_create(exec_ctx, NULL, error);
if (pollset->pi == NULL) {
GPR_TIMER_END("pollset_work_and_unlock", 0);
return; /* Fatal error. Cannot continue */
}
PI_ADD_REF(pollset->pi, "ps");
GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p",
(void *)pollset, (void *)pollset->pi);
}
pi = pollset->pi; pi = pollset->pi;
epoll_fd = pi->epoll_fd; epoll_fd = pi->epoll_fd;
@ -1212,17 +1212,19 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *ps, static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *ps,
grpc_fd *fd) { grpc_fd *fd) {
/* fd MUST have a NULL polling island and pollset MUST have a non-NULL polling
* island*/
GPR_ASSERT(fd->pi == NULL);
GPR_ASSERT(ps->pi);
GPR_TIMER_BEGIN("pollset_add_fd", 0); GPR_TIMER_BEGIN("pollset_add_fd", 0);
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
polling_island *pi_new = NULL; polling_island *pi = NULL;
gpr_mu_lock(&ps->mu); gpr_mu_lock(&ps->mu);
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
/* fd MUST have a NULL polling island */
GPR_ASSERT(fd->pi == NULL);
/* Early out if we are trying to add an 'fd' to a 'pollset' but the fd is /* Early out if we are trying to add an 'fd' to a 'pollset' but the fd is
* already orphaned */ * already orphaned */
if (fd->orphaned) { if (fd->orphaned) {
@ -1231,39 +1233,16 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *ps,
return; return;
} }
pi_new = ps->pi; pi = ps->pi;
if (pi_new == NULL) { gpr_mu_lock(&pi->mu);
/* Unlock before creating a new polling island: the polling island will polling_island_add_fds_locked(pi, &fd, 1, true, &error);
create a workqueue which creates a file descriptor, and holding an fd gpr_mu_unlock(&pi->mu);
lock here can eventually cause a loop to appear to TSAN (making it
unhappy). We don't think it's a real loop (there's an epoch point
where that loop possibility disappears), but the advantages of
keeping TSAN happy outweigh any performance advantage we might have
by keeping the lock held. */
gpr_mu_unlock(&fd->mu);
pi_new = polling_island_create(exec_ctx, fd, &error);
gpr_mu_lock(&fd->mu);
GRPC_POLLING_TRACE( PI_ADD_REF(pi, "fd");
"pollset_add_fd: Created new polling island: %p (ps: %p, fd: %d", fd->pi = pi;
(void *)pi_new, (void *)ps, fd->fd);
} else {
gpr_mu_lock(&pi_new->mu);
polling_island_add_fds_locked(pi_new, &fd, 1, true, &error);
gpr_mu_unlock(&pi_new->mu);
GRPC_POLLING_TRACE("pollset_add_fd: ps->pi = %p. Add fd: %d", GRPC_POLLING_TRACE("pollset_add_fd: ps->pi = %p. Add fd: %d", (void *)pi,
(void *)pi_new, fd->fd); fd->fd);
}
PI_ADD_REF(pi_new, "fd");
fd->pi = pi_new;
GPR_ASSERT((ps->pi == NULL) || (ps->pi == pi_new));
if (ps->pi == NULL) {
PI_ADD_REF(pi_new, "pollset");
ps->pi = pi_new;
}
gpr_mu_unlock(&ps->mu); gpr_mu_unlock(&ps->mu);
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
@ -1328,6 +1307,7 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
static void shutdown_engine(void) { static void shutdown_engine(void) {
shutdown_dedicated_poller_threads(); shutdown_dedicated_poller_threads();
shutdown_dedicated_pollsets();
fd_global_shutdown(); fd_global_shutdown();
pollset_global_shutdown(); pollset_global_shutdown();
polling_island_global_shutdown(); polling_island_global_shutdown();
@ -1381,16 +1361,38 @@ static void add_fd_to_global_pollset(grpc_fd *fd) {
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }
static void init_dedicated_pollsets() { static bool init_dedicated_pollsets() {
gpr_mu *temp_mu; gpr_mu *temp_mu;
grpc_error *error = GRPC_ERROR_NONE;
bool is_success = true;
g_num_pollsets = (size_t)gpr_cpu_num_cores(); g_num_pollsets = (size_t)gpr_cpu_num_cores();
g_pollsets = (grpc_pollset *)malloc(g_num_pollsets * sizeof(grpc_pollset)); g_pollsets = (grpc_pollset *)malloc(g_num_pollsets * sizeof(grpc_pollset));
for (size_t i = 0; i < g_num_pollsets; i++) { for (size_t i = 0; i < g_num_pollsets; i++) {
pollset_init(&g_pollsets[i], &temp_mu); pollset_init(&g_pollsets[i], &temp_mu);
pollset_add_polling_island(&g_pollsets[i], &error);
if (g_pollsets[i].pi == NULL) {
is_success = false;
break;
}
}
if (is_success) {
gpr_log(GPR_INFO, "Created %ld dedicated pollsets", g_num_pollsets);
} else {
shutdown_dedicated_pollsets();
} }
gpr_log(GPR_INFO, "Created %ld pollsets", g_num_pollsets); GRPC_LOG_IF_ERROR("init_dedicated_pollsets", error);
return is_success;
}
static void shutdown_dedicated_pollsets() {
if (g_pollsets) {
gpr_free(g_pollsets);
g_pollsets = NULL;
}
} }
static void poller_thread_loop(void *arg) { static void poller_thread_loop(void *arg) {
@ -1405,6 +1407,7 @@ static void poller_thread_loop(void *arg) {
} }
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
GRPC_LOG_IF_ERROR("poller_thread_loop", error);
} }
/* g_pollsets MUST be initialized before calling this */ /* g_pollsets MUST be initialized before calling this */
@ -1425,6 +1428,7 @@ static void start_dedicated_poller_threads() {
static void shutdown_dedicated_poller_threads() { static void shutdown_dedicated_poller_threads() {
GPR_ASSERT(g_poller_threads); GPR_ASSERT(g_poller_threads);
GPR_ASSERT(g_pollsets);
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
gpr_log(GPR_INFO, "Shutting down pollers"); gpr_log(GPR_INFO, "Shutting down pollers");
@ -1432,7 +1436,6 @@ static void shutdown_dedicated_poller_threads() {
for (size_t i = 0; i < g_num_pollsets; i++) { for (size_t i = 0; i < g_num_pollsets; i++) {
gpr_mu_lock(&g_pollsets[i].mu); gpr_mu_lock(&g_pollsets[i].mu);
polling_island *pi = g_pollsets[i].pi; polling_island *pi = g_pollsets[i].pi;
GPR_ASSERT(pi);
gpr_mu_lock(&pi->mu); gpr_mu_lock(&pi->mu);
polling_island_add_wakeup_fd_locked(pi, &polling_island_wakeup_fd, &error); polling_island_add_wakeup_fd_locked(pi, &polling_island_wakeup_fd, &error);
gpr_mu_unlock(&pi->mu); gpr_mu_unlock(&pi->mu);
@ -1441,6 +1444,10 @@ static void shutdown_dedicated_poller_threads() {
for (size_t i = 0; i < g_num_pollsets; i++) { for (size_t i = 0; i < g_num_pollsets; i++) {
gpr_thd_join(g_poller_threads[i]); gpr_thd_join(g_poller_threads[i]);
} }
GRPC_LOG_IF_ERROR("shutdown_dedicated_poller_threads", error);
gpr_free(g_poller_threads);
g_poller_threads = NULL;
} }
/****************************************************************************/ /****************************************************************************/
@ -1469,7 +1476,9 @@ const grpc_event_engine_vtable *grpc_init_epoll_thread_pool_linux(void) {
return NULL; return NULL;
} }
init_dedicated_pollsets(); if (!init_dedicated_pollsets()) {
return NULL;
}
fd_global_init(); fd_global_init();

Loading…
Cancel
Save