|
|
|
@ -106,6 +106,8 @@ struct grpc_pollset_worker { |
|
|
|
|
gpr_cv cv; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#define MAX_NEIGHBOURHOODS 1024 |
|
|
|
|
|
|
|
|
|
typedef struct pollset_neighbourhood { |
|
|
|
|
gpr_mu mu; |
|
|
|
|
grpc_pollset *active_root; |
|
|
|
@ -121,6 +123,7 @@ struct grpc_pollset { |
|
|
|
|
bool shutting_down; /* Is the pollset shutting down ? */ |
|
|
|
|
bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */ |
|
|
|
|
grpc_closure *shutdown_closure; /* Called after after shutdown is complete */ |
|
|
|
|
int begin_refs; |
|
|
|
|
|
|
|
|
|
grpc_pollset *next; |
|
|
|
|
grpc_pollset *prev; |
|
|
|
@ -312,7 +315,6 @@ GPR_TLS_DECL(g_current_thread_pollset); |
|
|
|
|
GPR_TLS_DECL(g_current_thread_worker); |
|
|
|
|
static gpr_atm g_active_poller; |
|
|
|
|
static pollset_neighbourhood *g_neighbourhoods; |
|
|
|
|
static bool *g_neighbour_scan_state; |
|
|
|
|
static size_t g_num_neighbourhoods; |
|
|
|
|
|
|
|
|
|
/* Return true if first in list */ |
|
|
|
@ -352,6 +354,10 @@ static worker_remove_result worker_remove(grpc_pollset *pollset, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static size_t choose_neighbourhood(void) { |
|
|
|
|
return (size_t)gpr_cpu_current_cpu() % g_num_neighbourhoods; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_error *pollset_global_init(void) { |
|
|
|
|
gpr_tls_init(&g_current_thread_pollset); |
|
|
|
|
gpr_tls_init(&g_current_thread_worker); |
|
|
|
@ -364,11 +370,9 @@ static grpc_error *pollset_global_init(void) { |
|
|
|
|
if (epoll_ctl(g_epfd, EPOLL_CTL_ADD, global_wakeup_fd.read_fd, &ev) != 0) { |
|
|
|
|
return GRPC_OS_ERROR(errno, "epoll_ctl"); |
|
|
|
|
} |
|
|
|
|
g_num_neighbourhoods = GPR_MAX(1, gpr_cpu_num_cores()); |
|
|
|
|
g_num_neighbourhoods = GPR_CLAMP(gpr_cpu_num_cores(), 1, MAX_NEIGHBOURHOODS); |
|
|
|
|
g_neighbourhoods = |
|
|
|
|
gpr_zalloc(sizeof(*g_neighbourhoods) * g_num_neighbourhoods); |
|
|
|
|
g_neighbour_scan_state = |
|
|
|
|
gpr_malloc(sizeof(*g_neighbour_scan_state) * g_num_neighbourhoods); |
|
|
|
|
for (size_t i = 0; i < g_num_neighbourhoods; i++) { |
|
|
|
|
gpr_mu_init(&g_neighbourhoods[i].mu); |
|
|
|
|
} |
|
|
|
@ -383,26 +387,27 @@ static void pollset_global_shutdown(void) { |
|
|
|
|
gpr_mu_destroy(&g_neighbourhoods[i].mu); |
|
|
|
|
} |
|
|
|
|
gpr_free(g_neighbourhoods); |
|
|
|
|
gpr_free(g_neighbour_scan_state); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) { |
|
|
|
|
gpr_mu_init(&pollset->mu); |
|
|
|
|
*mu = &pollset->mu; |
|
|
|
|
pollset->neighbourhood = &g_neighbourhoods[gpr_cpu_current_cpu()]; |
|
|
|
|
pollset->neighbourhood = &g_neighbourhoods[choose_neighbourhood()]; |
|
|
|
|
pollset->seen_inactive = true; |
|
|
|
|
pollset->next = pollset->prev = pollset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void pollset_destroy(grpc_pollset *pollset) { |
|
|
|
|
gpr_mu_lock(&pollset->neighbourhood->mu); |
|
|
|
|
pollset->prev->next = pollset->next; |
|
|
|
|
pollset->next->prev = pollset->prev; |
|
|
|
|
if (pollset == pollset->neighbourhood->active_root) { |
|
|
|
|
pollset->neighbourhood->active_root = |
|
|
|
|
pollset->next == pollset ? NULL : pollset->next; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&pollset->neighbourhood->mu); |
|
|
|
|
if (!pollset->seen_inactive) { |
|
|
|
|
gpr_mu_lock(&pollset->neighbourhood->mu); |
|
|
|
|
pollset->prev->next = pollset->next; |
|
|
|
|
pollset->next->prev = pollset->prev; |
|
|
|
|
if (pollset == pollset->neighbourhood->active_root) { |
|
|
|
|
pollset->neighbourhood->active_root = |
|
|
|
|
pollset->next == pollset ? NULL : pollset->next; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&pollset->neighbourhood->mu); |
|
|
|
|
} |
|
|
|
|
gpr_mu_destroy(&pollset->mu); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -428,7 +433,8 @@ static grpc_error *pollset_kick_all(grpc_pollset *pollset) { |
|
|
|
|
|
|
|
|
|
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->begin_refs == 0) { |
|
|
|
|
grpc_closure_sched(exec_ctx, pollset->shutdown_closure, GRPC_ERROR_NONE); |
|
|
|
|
pollset->shutdown_closure = NULL; |
|
|
|
|
} |
|
|
|
@ -532,14 +538,16 @@ static bool begin_worker(grpc_pollset *pollset, grpc_pollset_worker *worker, |
|
|
|
|
if (worker_hdl != NULL) *worker_hdl = worker; |
|
|
|
|
worker->initialized_cv = false; |
|
|
|
|
worker->kick_state = UNKICKED; |
|
|
|
|
pollset->begin_refs++; |
|
|
|
|
|
|
|
|
|
if (pollset->seen_inactive) { |
|
|
|
|
// pollset has been observed to be inactive, we need to move back to the
|
|
|
|
|
// active list
|
|
|
|
|
pollset_neighbourhood *neighbourhood = pollset->neighbourhood = &g_neighbourhoods[gpr_cpu_current_cpu()]; |
|
|
|
|
pollset_neighbourhood *neighbourhood = pollset->neighbourhood = |
|
|
|
|
&g_neighbourhoods[choose_neighbourhood()]; |
|
|
|
|
gpr_mu_unlock(&pollset->mu); |
|
|
|
|
// pollset unlocked: state may change (even worker->kick_state)
|
|
|
|
|
retry_lock_neighbourhood: |
|
|
|
|
// pollset unlocked: state may change (even worker->kick_state)
|
|
|
|
|
retry_lock_neighbourhood: |
|
|
|
|
gpr_mu_lock(&neighbourhood->mu); |
|
|
|
|
gpr_mu_lock(&pollset->mu); |
|
|
|
|
if (pollset->seen_inactive) { |
|
|
|
@ -564,16 +572,18 @@ retry_lock_neighbourhood: |
|
|
|
|
gpr_mu_unlock(&neighbourhood->mu); |
|
|
|
|
} |
|
|
|
|
worker_insert(pollset, worker); |
|
|
|
|
pollset->begin_refs--; |
|
|
|
|
if (worker->kick_state == UNKICKED) { |
|
|
|
|
GPR_ASSERT(gpr_atm_no_barrier_load(&g_active_poller) != (gpr_atm)worker); |
|
|
|
|
worker->initialized_cv = true; |
|
|
|
|
gpr_cv_init(&worker->cv); |
|
|
|
|
do { |
|
|
|
|
while (worker->kick_state == UNKICKED && |
|
|
|
|
pollset->shutdown_closure == NULL) { |
|
|
|
|
if (gpr_cv_wait(&worker->cv, &pollset->mu, deadline) && |
|
|
|
|
worker->kick_state == UNKICKED) { |
|
|
|
|
worker->kick_state = KICKED; |
|
|
|
|
} |
|
|
|
|
} while (worker->kick_state == UNKICKED); |
|
|
|
|
} |
|
|
|
|
*now = gpr_now(now->clock_type); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -594,17 +604,24 @@ static bool check_neighbourhood_for_available_poller( |
|
|
|
|
grpc_pollset_worker *inspect_worker = inspect->root_worker; |
|
|
|
|
if (inspect_worker != NULL) { |
|
|
|
|
do { |
|
|
|
|
if (inspect_worker->kick_state == UNKICKED) { |
|
|
|
|
if (gpr_atm_no_barrier_cas(&g_active_poller, 0, |
|
|
|
|
(gpr_atm)inspect_worker)) { |
|
|
|
|
inspect_worker->kick_state = DESIGNATED_POLLER; |
|
|
|
|
if (inspect_worker->initialized_cv) { |
|
|
|
|
gpr_cv_signal(&inspect_worker->cv); |
|
|
|
|
switch (inspect_worker->kick_state) { |
|
|
|
|
case UNKICKED: |
|
|
|
|
if (gpr_atm_no_barrier_cas(&g_active_poller, 0, |
|
|
|
|
(gpr_atm)inspect_worker)) { |
|
|
|
|
inspect_worker->kick_state = DESIGNATED_POLLER; |
|
|
|
|
if (inspect_worker->initialized_cv) { |
|
|
|
|
gpr_cv_signal(&inspect_worker->cv); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// even if we didn't win the cas, there's a worker, we can stop
|
|
|
|
|
found_worker = true; |
|
|
|
|
break; |
|
|
|
|
// even if we didn't win the cas, there's a worker, we can stop
|
|
|
|
|
found_worker = true; |
|
|
|
|
break; |
|
|
|
|
case KICKED: |
|
|
|
|
break; |
|
|
|
|
case DESIGNATED_POLLER: |
|
|
|
|
found_worker = true; // ok, so someone else found the worker, but
|
|
|
|
|
// we'll accept that
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
inspect_worker = inspect_worker->next; |
|
|
|
|
} while (inspect_worker != inspect->root_worker); |
|
|
|
@ -649,6 +666,7 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, |
|
|
|
|
size_t poller_neighbourhood_idx = |
|
|
|
|
(size_t)(pollset->neighbourhood - g_neighbourhoods); |
|
|
|
|
bool found_worker = false; |
|
|
|
|
bool scan_state[MAX_NEIGHBOURHOODS]; |
|
|
|
|
for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) { |
|
|
|
|
pollset_neighbourhood *neighbourhood = |
|
|
|
|
&g_neighbourhoods[(poller_neighbourhood_idx + i) % |
|
|
|
@ -657,19 +675,18 @@ static void end_worker(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, |
|
|
|
|
found_worker = |
|
|
|
|
check_neighbourhood_for_available_poller(neighbourhood); |
|
|
|
|
gpr_mu_unlock(&neighbourhood->mu); |
|
|
|
|
g_neighbour_scan_state[i] = true; |
|
|
|
|
scan_state[i] = true; |
|
|
|
|
} else { |
|
|
|
|
g_neighbour_scan_state[i] = false; |
|
|
|
|
scan_state[i] = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (size_t i = 0; !found_worker && i < g_num_neighbourhoods; i++) { |
|
|
|
|
if (g_neighbour_scan_state[i]) continue; |
|
|
|
|
if (scan_state[i]) continue; |
|
|
|
|
pollset_neighbourhood *neighbourhood = |
|
|
|
|
&g_neighbourhoods[(poller_neighbourhood_idx + i) % |
|
|
|
|
g_num_neighbourhoods]; |
|
|
|
|
gpr_mu_lock(&neighbourhood->mu); |
|
|
|
|
found_worker = |
|
|
|
|
check_neighbourhood_for_available_poller(neighbourhood); |
|
|
|
|
found_worker = check_neighbourhood_for_available_poller(neighbourhood); |
|
|
|
|
gpr_mu_unlock(&neighbourhood->mu); |
|
|
|
|
} |
|
|
|
|
grpc_exec_ctx_flush(exec_ctx); |
|
|
|
|