Merge branch 'cq-drop' into enable-epoll1

reviewable/pr11816/r1
Craig Tiller 8 years ago
commit ea7429f68f
  1. 8
      include/grpc++/grpc++.h
  2. 419
      src/core/lib/surface/completion_queue.c
  3. 3
      src/core/lib/surface/completion_queue.h
  4. 5
      src/core/lib/surface/server.c
  5. 5
      src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
  6. 12
      test/cpp/microbenchmarks/bm_fullstack_trickle.cc
  7. 14
      tools/distrib/pylint_code.sh
  8. 3
      tools/dockerfile/test/cxx_alpine_x64/Dockerfile
  9. 3
      tools/dockerfile/test/python_alpine_x64/Dockerfile
  10. 4
      tools/internal_ci/linux/grpc_build_artifacts.sh
  11. 39
      tools/internal_ci/linux/grpc_sanity.cfg
  12. 2
      tools/internal_ci/linux/grpc_sanity.sh
  13. 2
      tools/profiling/microbenchmarks/bm_json.py
  14. 7
      tools/run_tests/python_utils/jobset.py

@ -34,18 +34,18 @@
/// \mainpage gRPC C++ API /// \mainpage gRPC C++ API
/// ///
/// The gRPC C++ API mainly consists of the following classes: /// The gRPC C++ API mainly consists of the following classes:
// /// <br>
/// - grpc::Channel, which represents the connection to an endpoint. See [the /// - grpc::Channel, which represents the connection to an endpoint. See [the
/// gRPC Concepts page](http://www.grpc.io/docs/guides/concepts.html) for more /// gRPC Concepts page](http://www.grpc.io/docs/guides/concepts.html) for more
/// details. Channels are created by the factory function grpc::CreateChannel. /// details. Channels are created by the factory function grpc::CreateChannel.
// ///
/// - grpc::CompletionQueue, the producer-consumer queue used for all /// - grpc::CompletionQueue, the producer-consumer queue used for all
/// asynchronous communication with the gRPC runtime. /// asynchronous communication with the gRPC runtime.
// ///
/// - grpc::ClientContext and grpc::ServerContext, where optional configuration /// - grpc::ClientContext and grpc::ServerContext, where optional configuration
/// for an RPC can be set, such as setting custom metadata to be conveyed to the /// for an RPC can be set, such as setting custom metadata to be conveyed to the
/// peer, compression settings, authentication, etc. /// peer, compression settings, authentication, etc.
// ///
/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder. /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
/// ///
/// Streaming calls are handled with the streaming classes in /// Streaming calls are handled with the streaming classes in

@ -203,7 +203,10 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
typedef struct cq_vtable { typedef struct cq_vtable {
grpc_cq_completion_type cq_completion_type; grpc_cq_completion_type cq_completion_type;
size_t (*size)(); size_t data_size;
void (*init)(void *data);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq);
void (*destroy)(void *data);
void (*begin_op)(grpc_completion_queue *cq, void *tag); void (*begin_op)(grpc_completion_queue *cq, void *tag);
void (*end_op)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, void *tag, void (*end_op)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cq, void *tag,
grpc_error *error, grpc_error *error,
@ -232,25 +235,28 @@ typedef struct grpc_cq_event_queue {
gpr_atm num_queue_items; gpr_atm num_queue_items;
} grpc_cq_event_queue; } grpc_cq_event_queue;
/* TODO: sreek Refactor this based on the completion_type. Put completion-type typedef struct cq_next_data {
* specific data in a different structure (and co-allocate memory for it along /** Completed events for completion-queues of type GRPC_CQ_NEXT */
* with completion queue + pollset )*/ grpc_cq_event_queue queue;
typedef struct cq_data {
gpr_mu *mu; /** Counter of how many things have ever been queued on this completion queue
useful for avoiding locks to check the queue */
gpr_atm things_queued_ever;
/* Number of outstanding events (+1 if not shut down) */
gpr_atm pending_events;
int shutdown_called;
} cq_next_data;
typedef struct cq_pluck_data {
/** Completed events for completion-queues of type GRPC_CQ_PLUCK */ /** Completed events for completion-queues of type GRPC_CQ_PLUCK */
grpc_cq_completion completed_head; grpc_cq_completion completed_head;
grpc_cq_completion *completed_tail; grpc_cq_completion *completed_tail;
/** Completed events for completion-queues of type GRPC_CQ_NEXT */
grpc_cq_event_queue queue;
/** Number of pending events (+1 if we're not shutdown) */ /** Number of pending events (+1 if we're not shutdown) */
gpr_refcount pending_events; gpr_refcount pending_events;
/** Once owning_refs drops to zero, we will destroy the cq */
gpr_refcount owning_refs;
/** Counter of how many things have ever been queued on this completion queue /** Counter of how many things have ever been queued on this completion queue
useful for avoiding locks to check the queue */ useful for avoiding locks to check the queue */
gpr_atm things_queued_ever; gpr_atm things_queued_ever;
@ -259,34 +265,42 @@ typedef struct cq_data {
gpr_atm shutdown; gpr_atm shutdown;
int shutdown_called; int shutdown_called;
int is_server_cq;
int num_pluckers; int num_pluckers;
int num_polls;
plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS]; plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
grpc_closure pollset_shutdown_done; } cq_pluck_data;
/* Completion queue structure */
struct grpc_completion_queue {
/** Once owning_refs drops to zero, we will destroy the cq */
gpr_refcount owning_refs;
gpr_mu *mu;
const cq_vtable *vtable;
const cq_poller_vtable *poller_vtable;
#ifndef NDEBUG #ifndef NDEBUG
void **outstanding_tags; void **outstanding_tags;
size_t outstanding_tag_count; size_t outstanding_tag_count;
size_t outstanding_tag_capacity; size_t outstanding_tag_capacity;
#endif #endif
} cq_data;
/* Completion queue structure */ grpc_closure pollset_shutdown_done;
struct grpc_completion_queue { int num_polls;
cq_data data;
const cq_vtable *vtable;
const cq_poller_vtable *poller_vtable;
}; };
/* Forward declarations */ /* Forward declarations */
static void cq_finish_shutdown(grpc_exec_ctx *exec_ctx, static void cq_finish_shutdown_next(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq); grpc_completion_queue *cq);
static void cq_finish_shutdown_pluck(grpc_exec_ctx *exec_ctx,
static size_t cq_size(grpc_completion_queue *cq); grpc_completion_queue *cq);
static void cq_shutdown_next(grpc_exec_ctx *exec_ctx,
static void cq_begin_op(grpc_completion_queue *cq, void *tag); grpc_completion_queue *cq);
static void cq_shutdown_pluck(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq);
static void cq_begin_op_for_next(grpc_completion_queue *cq, void *tag);
static void cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag);
static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx, static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq, void *tag, grpc_completion_queue *cq, void *tag,
@ -310,26 +324,38 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag, static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
gpr_timespec deadline, void *reserved); gpr_timespec deadline, void *reserved);
static void cq_init_next(void *data);
static void cq_init_pluck(void *data);
static void cq_destroy_next(void *data);
static void cq_destroy_pluck(void *data);
/* Completion queue vtables based on the completion-type */ /* Completion queue vtables based on the completion-type */
static const cq_vtable g_cq_vtable[] = { static const cq_vtable g_cq_vtable[] = {
/* GRPC_CQ_NEXT */ /* GRPC_CQ_NEXT */
{.cq_completion_type = GRPC_CQ_NEXT, {.data_size = sizeof(cq_next_data),
.size = cq_size, .cq_completion_type = GRPC_CQ_NEXT,
.begin_op = cq_begin_op, .init = cq_init_next,
.shutdown = cq_shutdown_next,
.destroy = cq_destroy_next,
.begin_op = cq_begin_op_for_next,
.end_op = cq_end_op_for_next, .end_op = cq_end_op_for_next,
.next = cq_next, .next = cq_next,
.pluck = NULL}, .pluck = NULL},
/* GRPC_CQ_PLUCK */ /* GRPC_CQ_PLUCK */
{.cq_completion_type = GRPC_CQ_PLUCK, {.data_size = sizeof(cq_pluck_data),
.size = cq_size, .cq_completion_type = GRPC_CQ_PLUCK,
.begin_op = cq_begin_op, .init = cq_init_pluck,
.shutdown = cq_shutdown_pluck,
.destroy = cq_destroy_pluck,
.begin_op = cq_begin_op_for_pluck,
.end_op = cq_end_op_for_pluck, .end_op = cq_end_op_for_pluck,
.next = NULL, .next = NULL,
.pluck = cq_pluck}, .pluck = cq_pluck},
}; };
#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1)) #define DATA_FROM_CQ(cq) ((void *)(cq + 1))
#define CQ_FROM_POLLSET(ps) (((grpc_completion_queue *)ps) - 1) #define POLLSET_FROM_CQ(cq) \
((grpc_pollset *)(cq->vtable->data_size + (char *)DATA_FROM_CQ(cq)))
grpc_tracer_flag grpc_cq_pluck_trace = GRPC_TRACER_INITIALIZER(true); grpc_tracer_flag grpc_cq_pluck_trace = GRPC_TRACER_INITIALIZER(true);
grpc_tracer_flag grpc_cq_event_timeout_trace = GRPC_TRACER_INITIALIZER(true); grpc_tracer_flag grpc_cq_event_timeout_trace = GRPC_TRACER_INITIALIZER(true);
@ -381,12 +407,6 @@ static long cq_event_queue_num_items(grpc_cq_event_queue *q) {
return (long)gpr_atm_no_barrier_load(&q->num_queue_items); return (long)gpr_atm_no_barrier_load(&q->num_queue_items);
} }
static size_t cq_size(grpc_completion_queue *cq) {
/* Size of the completion queue and the size of the pollset whose memory is
allocated right after that of completion queue */
return sizeof(grpc_completion_queue) + cq->poller_vtable->size();
}
grpc_completion_queue *grpc_completion_queue_create_internal( grpc_completion_queue *grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_completion_type completion_type,
grpc_cq_polling_type polling_type) { grpc_cq_polling_type polling_type) {
@ -403,41 +423,56 @@ grpc_completion_queue *grpc_completion_queue_create_internal(
const cq_poller_vtable *poller_vtable = const cq_poller_vtable *poller_vtable =
&g_poller_vtable_by_poller_type[polling_type]; &g_poller_vtable_by_poller_type[polling_type];
cq = gpr_zalloc(sizeof(grpc_completion_queue) + poller_vtable->size()); cq = gpr_zalloc(sizeof(grpc_completion_queue) + vtable->data_size +
cq_data *cqd = &cq->data; poller_vtable->size());
cq->vtable = vtable; cq->vtable = vtable;
cq->poller_vtable = poller_vtable; cq->poller_vtable = poller_vtable;
poller_vtable->init(POLLSET_FROM_CQ(cq), &cq->data.mu); /* One for destroy(), one for pollset_shutdown */
gpr_ref_init(&cq->owning_refs, 2);
#ifndef NDEBUG poller_vtable->init(POLLSET_FROM_CQ(cq), &cq->mu);
cqd->outstanding_tags = NULL; vtable->init(DATA_FROM_CQ(cq));
cqd->outstanding_tag_capacity = 0;
#endif grpc_closure_init(&cq->pollset_shutdown_done, on_pollset_shutdown_done, cq,
grpc_schedule_on_exec_ctx);
GPR_TIMER_END("grpc_completion_queue_create_internal", 0);
return cq;
}
static void cq_init_next(void *ptr) {
cq_next_data *cqd = ptr;
/* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
cqd->shutdown_called = false;
gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0);
cq_event_queue_init(&cqd->queue);
}
static void cq_destroy_next(void *ptr) {
cq_next_data *cqd = ptr;
GPR_ASSERT(cq_event_queue_num_items(&cqd->queue) == 0);
cq_event_queue_destroy(&cqd->queue);
}
static void cq_init_pluck(void *ptr) {
cq_pluck_data *cqd = ptr;
/* Initial ref is dropped by grpc_completion_queue_shutdown */ /* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cqd->pending_events, 1); gpr_ref_init(&cqd->pending_events, 1);
/* One for destroy(), one for pollset_shutdown */
gpr_ref_init(&cqd->owning_refs, 2);
cqd->completed_tail = &cqd->completed_head; cqd->completed_tail = &cqd->completed_head;
cqd->completed_head.next = (uintptr_t)cqd->completed_tail; cqd->completed_head.next = (uintptr_t)cqd->completed_tail;
gpr_atm_no_barrier_store(&cqd->shutdown, 0); gpr_atm_no_barrier_store(&cqd->shutdown, 0);
cqd->shutdown_called = 0; cqd->shutdown_called = 0;
cqd->is_server_cq = 0;
cqd->num_pluckers = 0; cqd->num_pluckers = 0;
cqd->num_polls = 0;
gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0); gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0);
#ifndef NDEBUG }
cqd->outstanding_tag_count = 0;
#endif
cq_event_queue_init(&cqd->queue);
grpc_closure_init(&cqd->pollset_shutdown_done, on_pollset_shutdown_done, cq,
grpc_schedule_on_exec_ctx);
GPR_TIMER_END("grpc_completion_queue_create_internal", 0);
return cq; static void cq_destroy_pluck(void *ptr) {
cq_pluck_data *cqd = ptr;
GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head);
} }
grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cq) { grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cq) {
@ -446,23 +481,21 @@ grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cq) {
int grpc_get_cq_poll_num(grpc_completion_queue *cq) { int grpc_get_cq_poll_num(grpc_completion_queue *cq) {
int cur_num_polls; int cur_num_polls;
gpr_mu_lock(cq->data.mu); gpr_mu_lock(cq->mu);
cur_num_polls = cq->data.num_polls; cur_num_polls = cq->num_polls;
gpr_mu_unlock(cq->data.mu); gpr_mu_unlock(cq->mu);
return cur_num_polls; return cur_num_polls;
} }
#ifdef GRPC_CQ_REF_COUNT_DEBUG #ifdef GRPC_CQ_REF_COUNT_DEBUG
void grpc_cq_internal_ref(grpc_completion_queue *cq, const char *reason, void grpc_cq_internal_ref(grpc_completion_queue *cq, const char *reason,
const char *file, int line) { const char *file, int line) {
cq_data *cqd = &cq->data;
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cq, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %d -> %d %s", cq,
(int)cqd->owning_refs.count, (int)cqd->owning_refs.count + 1, reason); (int)cq->owning_refs.count, (int)cq->owning_refs.count + 1, reason);
#else #else
void grpc_cq_internal_ref(grpc_completion_queue *cq) { void grpc_cq_internal_ref(grpc_completion_queue *cq) {
cq_data *cqd = &cq->data;
#endif #endif
gpr_ref(&cqd->owning_refs); gpr_ref(&cq->owning_refs);
} }
static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg, static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
@ -480,61 +513,63 @@ void grpc_cq_internal_unref(grpc_completion_queue *cq, const char *reason,
#else #else
void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq) { grpc_completion_queue *cq) {
cq_data *cqd = &cq->data;
#endif #endif
if (gpr_unref(&cqd->owning_refs)) { if (gpr_unref(&cq->owning_refs)) {
GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head); cq->vtable->destroy(DATA_FROM_CQ(cq));
cq->poller_vtable->destroy(exec_ctx, POLLSET_FROM_CQ(cq)); cq->poller_vtable->destroy(exec_ctx, POLLSET_FROM_CQ(cq));
cq_event_queue_destroy(&cqd->queue);
#ifndef NDEBUG #ifndef NDEBUG
gpr_free(cqd->outstanding_tags); gpr_free(cq->outstanding_tags);
#endif #endif
gpr_free(cq); gpr_free(cq);
} }
} }
static void cq_begin_op(grpc_completion_queue *cq, void *tag) { static void cq_begin_op_for_next(grpc_completion_queue *cq, void *tag) {
cq_data *cqd = &cq->data; cq_next_data *cqd = DATA_FROM_CQ(cq);
#ifndef NDEBUG GPR_ASSERT(!cqd->shutdown_called);
gpr_mu_lock(cqd->mu); gpr_atm_no_barrier_fetch_add(&cqd->pending_events, 1);
}
static void cq_begin_op_for_pluck(grpc_completion_queue *cq, void *tag) {
cq_pluck_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(!cqd->shutdown_called); GPR_ASSERT(!cqd->shutdown_called);
if (cqd->outstanding_tag_count == cqd->outstanding_tag_capacity) {
cqd->outstanding_tag_capacity =
GPR_MAX(4, 2 * cqd->outstanding_tag_capacity);
cqd->outstanding_tags =
gpr_realloc(cqd->outstanding_tags, sizeof(*cqd->outstanding_tags) *
cqd->outstanding_tag_capacity);
}
cqd->outstanding_tags[cqd->outstanding_tag_count++] = tag;
gpr_mu_unlock(cqd->mu);
#endif
gpr_ref(&cqd->pending_events); gpr_ref(&cqd->pending_events);
} }
void grpc_cq_begin_op(grpc_completion_queue *cq, void *tag) { void grpc_cq_begin_op(grpc_completion_queue *cq, void *tag) {
#ifndef NDEBUG
gpr_mu_lock(cq->mu);
if (cq->outstanding_tag_count == cq->outstanding_tag_capacity) {
cq->outstanding_tag_capacity = GPR_MAX(4, 2 * cq->outstanding_tag_capacity);
cq->outstanding_tags =
gpr_realloc(cq->outstanding_tags, sizeof(*cq->outstanding_tags) *
cq->outstanding_tag_capacity);
}
cq->outstanding_tags[cq->outstanding_tag_count++] = tag;
gpr_mu_unlock(cq->mu);
#endif
cq->vtable->begin_op(cq, tag); cq->vtable->begin_op(cq, tag);
} }
#ifndef NDEBUG #ifndef NDEBUG
static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) { static void cq_check_tag(grpc_completion_queue *cq, void *tag, bool lock_cq) {
cq_data *cqd = &cq->data;
int found = 0; int found = 0;
if (lock_cq) { if (lock_cq) {
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
} }
for (int i = 0; i < (int)cqd->outstanding_tag_count; i++) { for (int i = 0; i < (int)cq->outstanding_tag_count; i++) {
if (cqd->outstanding_tags[i] == tag) { if (cq->outstanding_tags[i] == tag) {
cqd->outstanding_tag_count--; cq->outstanding_tag_count--;
GPR_SWAP(void *, cqd->outstanding_tags[i], GPR_SWAP(void *, cq->outstanding_tags[i],
cqd->outstanding_tags[cqd->outstanding_tag_count]); cq->outstanding_tags[cq->outstanding_tag_count]);
found = 1; found = 1;
break; break;
} }
} }
if (lock_cq) { if (lock_cq) {
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
} }
GPR_ASSERT(found); GPR_ASSERT(found);
@ -568,7 +603,7 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
} }
} }
cq_data *cqd = &cq->data; cq_next_data *cqd = DATA_FROM_CQ(cq);
int is_success = (error == GRPC_ERROR_NONE); int is_success = (error == GRPC_ERROR_NONE);
storage->tag = tag; storage->tag = tag;
@ -581,14 +616,16 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
/* Add the completion to the queue */ /* Add the completion to the queue */
bool is_first = cq_event_queue_push(&cqd->queue, storage); bool is_first = cq_event_queue_push(&cqd->queue, storage);
gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1); gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
bool shutdown = gpr_unref(&cqd->pending_events); bool will_definitely_shutdown =
gpr_atm_no_barrier_load(&cqd->pending_events) == 1;
if (!shutdown) { if (!will_definitely_shutdown) {
/* Only kick if this is the first item queued */ /* Only kick if this is the first item queued */
if (is_first) { if (is_first) {
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
grpc_error *kick_error = cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL); grpc_error *kick_error =
gpr_mu_unlock(cqd->mu); cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL);
gpr_mu_unlock(cq->mu);
if (kick_error != GRPC_ERROR_NONE) { if (kick_error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(kick_error); const char *msg = grpc_error_string(kick_error);
@ -596,9 +633,20 @@ static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_UNREF(kick_error); GRPC_ERROR_UNREF(kick_error);
} }
} }
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
GRPC_CQ_INTERNAL_REF(cq, "shutting_down");
gpr_mu_lock(cq->mu);
cq_finish_shutdown_next(exec_ctx, cq);
gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down");
}
} else { } else {
cq_finish_shutdown(exec_ctx, cq); GRPC_CQ_INTERNAL_REF(cq, "shutting_down");
gpr_mu_unlock(cqd->mu); gpr_atm_rel_store(&cqd->pending_events, 0);
gpr_mu_lock(cq->mu);
cq_finish_shutdown_next(exec_ctx, cq);
gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down");
} }
GPR_TIMER_END("cq_end_op_for_next", 0); GPR_TIMER_END("cq_end_op_for_next", 0);
@ -615,7 +663,7 @@ static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
void *done_arg, void *done_arg,
grpc_cq_completion *storage), grpc_cq_completion *storage),
void *done_arg, grpc_cq_completion *storage) { void *done_arg, grpc_cq_completion *storage) {
cq_data *cqd = &cq->data; cq_pluck_data *cqd = DATA_FROM_CQ(cq);
int is_success = (error == GRPC_ERROR_NONE); int is_success = (error == GRPC_ERROR_NONE);
GPR_TIMER_BEGIN("cq_end_op_for_pluck", 0); GPR_TIMER_BEGIN("cq_end_op_for_pluck", 0);
@ -639,7 +687,7 @@ static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
storage->done_arg = done_arg; storage->done_arg = done_arg;
storage->next = ((uintptr_t)&cqd->completed_head) | ((uintptr_t)(is_success)); storage->next = ((uintptr_t)&cqd->completed_head) | ((uintptr_t)(is_success));
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
cq_check_tag(cq, tag, false); /* Used in debug builds only */ cq_check_tag(cq, tag, false); /* Used in debug builds only */
/* Add to the list of completions */ /* Add to the list of completions */
@ -661,7 +709,7 @@ static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
grpc_error *kick_error = grpc_error *kick_error =
cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), pluck_worker); cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), pluck_worker);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
if (kick_error != GRPC_ERROR_NONE) { if (kick_error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(kick_error); const char *msg = grpc_error_string(kick_error);
@ -670,8 +718,8 @@ static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_UNREF(kick_error); GRPC_ERROR_UNREF(kick_error);
} }
} else { } else {
cq_finish_shutdown(exec_ctx, cq); cq_finish_shutdown_pluck(exec_ctx, cq);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
} }
GPR_TIMER_END("cq_end_op_for_pluck", 0); GPR_TIMER_END("cq_end_op_for_pluck", 0);
@ -699,7 +747,7 @@ typedef struct {
static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) { static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) {
cq_is_finished_arg *a = arg; cq_is_finished_arg *a = arg;
grpc_completion_queue *cq = a->cq; grpc_completion_queue *cq = a->cq;
cq_data *cqd = &cq->data; cq_next_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(a->stolen_completion == NULL); GPR_ASSERT(a->stolen_completion == NULL);
gpr_atm current_last_seen_things_queued_ever = gpr_atm current_last_seen_things_queued_ever =
@ -726,18 +774,16 @@ static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) {
static void dump_pending_tags(grpc_completion_queue *cq) { static void dump_pending_tags(grpc_completion_queue *cq) {
if (!GRPC_TRACER_ON(grpc_trace_pending_tags)) return; if (!GRPC_TRACER_ON(grpc_trace_pending_tags)) return;
cq_data *cqd = &cq->data;
gpr_strvec v; gpr_strvec v;
gpr_strvec_init(&v); gpr_strvec_init(&v);
gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:")); gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:"));
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
for (size_t i = 0; i < cqd->outstanding_tag_count; i++) { for (size_t i = 0; i < cq->outstanding_tag_count; i++) {
char *s; char *s;
gpr_asprintf(&s, " %p", cqd->outstanding_tags[i]); gpr_asprintf(&s, " %p", cq->outstanding_tags[i]);
gpr_strvec_add(&v, s); gpr_strvec_add(&v, s);
} }
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
char *out = gpr_strvec_flatten(&v, NULL); char *out = gpr_strvec_flatten(&v, NULL);
gpr_strvec_destroy(&v); gpr_strvec_destroy(&v);
gpr_log(GPR_DEBUG, "%s", out); gpr_log(GPR_DEBUG, "%s", out);
@ -751,7 +797,7 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
void *reserved) { void *reserved) {
grpc_event ret; grpc_event ret;
gpr_timespec now; gpr_timespec now;
cq_data *cqd = &cq->data; cq_next_data *cqd = DATA_FROM_CQ(cq);
GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@ -814,7 +860,7 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
} }
} }
if (gpr_atm_no_barrier_load(&cqd->shutdown)) { if (gpr_atm_no_barrier_load(&cqd->pending_events) == 0) {
/* Before returning, check if the queue has any items left over (since /* Before returning, check if the queue has any items left over (since
gpr_mpscq_pop() can sometimes return NULL even if the queue is not gpr_mpscq_pop() can sometimes return NULL even if the queue is not
empty. If so, keep retrying but do not return GRPC_QUEUE_SHUTDOWN */ empty. If so, keep retrying but do not return GRPC_QUEUE_SHUTDOWN */
@ -840,11 +886,11 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
} }
/* The main polling work happens in grpc_pollset_work */ /* The main polling work happens in grpc_pollset_work */
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
cqd->num_polls++; cq->num_polls++;
grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq), grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq),
NULL, now, iteration_deadline); NULL, now, iteration_deadline);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(err); const char *msg = grpc_error_string(err);
@ -865,10 +911,10 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
GPR_ASSERT(is_finished_arg.stolen_completion == NULL); GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
if (cq_event_queue_num_items(&cqd->queue) > 0 && if (cq_event_queue_num_items(&cqd->queue) > 0 &&
gpr_atm_no_barrier_load(&cqd->shutdown) == 0) { gpr_atm_no_barrier_load(&cqd->pending_events) > 0) {
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL); cq->poller_vtable->kick(POLLSET_FROM_CQ(cq), NULL);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
} }
GPR_TIMER_END("grpc_completion_queue_next", 0); GPR_TIMER_END("grpc_completion_queue_next", 0);
@ -876,6 +922,42 @@ static grpc_event cq_next(grpc_completion_queue *cq, gpr_timespec deadline,
return ret; return ret;
} }
/* Finishes the completion queue shutdown. This means that there are no more
completion events / tags expected from the completion queue
- Must be called under completion queue lock
- Must be called only once in completion queue's lifetime
- grpc_completion_queue_shutdown() MUST have been called before calling
this function */
static void cq_finish_shutdown_next(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq) {
cq_next_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(cqd->shutdown_called);
GPR_ASSERT(gpr_atm_no_barrier_load(&cqd->pending_events) == 0);
cq->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cq),
&cq->pollset_shutdown_done);
}
static void cq_shutdown_next(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq) {
cq_next_data *cqd = DATA_FROM_CQ(cq);
GRPC_CQ_INTERNAL_REF(cq, "shutting_down");
gpr_mu_lock(cq->mu);
if (cqd->shutdown_called) {
gpr_mu_unlock(cq->mu);
GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
return;
}
cqd->shutdown_called = 1;
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
cq_finish_shutdown_next(exec_ctx, cq);
}
gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(exec_ctx, cq, "shutting_down");
}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cq, grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
gpr_timespec deadline, void *reserved) { gpr_timespec deadline, void *reserved) {
return cq->vtable->next(cq, deadline, reserved); return cq->vtable->next(cq, deadline, reserved);
@ -883,7 +965,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
static int add_plucker(grpc_completion_queue *cq, void *tag, static int add_plucker(grpc_completion_queue *cq, void *tag,
grpc_pollset_worker **worker) { grpc_pollset_worker **worker) {
cq_data *cqd = &cq->data; cq_pluck_data *cqd = DATA_FROM_CQ(cq);
if (cqd->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { if (cqd->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
return 0; return 0;
} }
@ -895,7 +977,7 @@ static int add_plucker(grpc_completion_queue *cq, void *tag,
static void del_plucker(grpc_completion_queue *cq, void *tag, static void del_plucker(grpc_completion_queue *cq, void *tag,
grpc_pollset_worker **worker) { grpc_pollset_worker **worker) {
cq_data *cqd = &cq->data; cq_pluck_data *cqd = DATA_FROM_CQ(cq);
for (int i = 0; i < cqd->num_pluckers; i++) { for (int i = 0; i < cqd->num_pluckers; i++) {
if (cqd->pluckers[i].tag == tag && cqd->pluckers[i].worker == worker) { if (cqd->pluckers[i].tag == tag && cqd->pluckers[i].worker == worker) {
cqd->num_pluckers--; cqd->num_pluckers--;
@ -909,13 +991,13 @@ static void del_plucker(grpc_completion_queue *cq, void *tag,
static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) { static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) {
cq_is_finished_arg *a = arg; cq_is_finished_arg *a = arg;
grpc_completion_queue *cq = a->cq; grpc_completion_queue *cq = a->cq;
cq_data *cqd = &cq->data; cq_pluck_data *cqd = DATA_FROM_CQ(cq);
GPR_ASSERT(a->stolen_completion == NULL); GPR_ASSERT(a->stolen_completion == NULL);
gpr_atm current_last_seen_things_queued_ever = gpr_atm current_last_seen_things_queued_ever =
gpr_atm_no_barrier_load(&cqd->things_queued_ever); gpr_atm_no_barrier_load(&cqd->things_queued_ever);
if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
a->last_seen_things_queued_ever = a->last_seen_things_queued_ever =
gpr_atm_no_barrier_load(&cqd->things_queued_ever); gpr_atm_no_barrier_load(&cqd->things_queued_ever);
grpc_cq_completion *c; grpc_cq_completion *c;
@ -927,13 +1009,13 @@ static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) {
if (c == cqd->completed_tail) { if (c == cqd->completed_tail) {
cqd->completed_tail = prev; cqd->completed_tail = prev;
} }
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
a->stolen_completion = c; a->stolen_completion = c;
return true; return true;
} }
prev = c; prev = c;
} }
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
} }
return !a->first_loop && return !a->first_loop &&
gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
@ -946,7 +1028,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
grpc_cq_completion *prev; grpc_cq_completion *prev;
grpc_pollset_worker *worker = NULL; grpc_pollset_worker *worker = NULL;
gpr_timespec now; gpr_timespec now;
cq_data *cqd = &cq->data; cq_pluck_data *cqd = DATA_FROM_CQ(cq);
GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
@ -967,7 +1049,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
GRPC_CQ_INTERNAL_REF(cq, "pluck"); GRPC_CQ_INTERNAL_REF(cq, "pluck");
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
cq_is_finished_arg is_finished_arg = { cq_is_finished_arg is_finished_arg = {
.last_seen_things_queued_ever = .last_seen_things_queued_ever =
gpr_atm_no_barrier_load(&cqd->things_queued_ever), gpr_atm_no_barrier_load(&cqd->things_queued_ever),
@ -980,7 +1062,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg); GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg);
for (;;) { for (;;) {
if (is_finished_arg.stolen_completion != NULL) { if (is_finished_arg.stolen_completion != NULL) {
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
c = is_finished_arg.stolen_completion; c = is_finished_arg.stolen_completion;
is_finished_arg.stolen_completion = NULL; is_finished_arg.stolen_completion = NULL;
ret.type = GRPC_OP_COMPLETE; ret.type = GRPC_OP_COMPLETE;
@ -997,7 +1079,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
if (c == cqd->completed_tail) { if (c == cqd->completed_tail) {
cqd->completed_tail = prev; cqd->completed_tail = prev;
} }
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
ret.type = GRPC_OP_COMPLETE; ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u; ret.success = c->next & 1u;
ret.tag = c->tag; ret.tag = c->tag;
@ -1007,7 +1089,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
prev = c; prev = c;
} }
if (gpr_atm_no_barrier_load(&cqd->shutdown)) { if (gpr_atm_no_barrier_load(&cqd->shutdown)) {
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_SHUTDOWN; ret.type = GRPC_QUEUE_SHUTDOWN;
break; break;
@ -1017,7 +1099,7 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
"Too many outstanding grpc_completion_queue_pluck calls: maximum " "Too many outstanding grpc_completion_queue_pluck calls: maximum "
"is %d", "is %d",
GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
/* TODO(ctiller): should we use a different result here */ /* TODO(ctiller): should we use a different result here */
ret.type = GRPC_QUEUE_TIMEOUT; ret.type = GRPC_QUEUE_TIMEOUT;
@ -1027,19 +1109,19 @@ static grpc_event cq_pluck(grpc_completion_queue *cq, void *tag,
now = gpr_now(GPR_CLOCK_MONOTONIC); now = gpr_now(GPR_CLOCK_MONOTONIC);
if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) { if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
del_plucker(cq, tag, &worker); del_plucker(cq, tag, &worker);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT; ret.type = GRPC_QUEUE_TIMEOUT;
dump_pending_tags(cq); dump_pending_tags(cq);
break; break;
} }
cqd->num_polls++; cq->num_polls++;
grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq), grpc_error *err = cq->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cq),
&worker, now, deadline); &worker, now, deadline);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
del_plucker(cq, tag, &worker); del_plucker(cq, tag, &worker);
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
const char *msg = grpc_error_string(err); const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg); gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg);
@ -1068,43 +1150,42 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
return cq->vtable->pluck(cq, tag, deadline, reserved); return cq->vtable->pluck(cq, tag, deadline, reserved);
} }
/* Finishes the completion queue shutdown. This means that there are no more static void cq_finish_shutdown_pluck(grpc_exec_ctx *exec_ctx,
completion events / tags expected from the completion queue grpc_completion_queue *cq) {
- Must be called under completion queue lock cq_pluck_data *cqd = DATA_FROM_CQ(cq);
- Must be called only once in completion queue's lifetime
- grpc_completion_queue_shutdown() MUST have been called before calling
this function */
static void cq_finish_shutdown(grpc_exec_ctx *exec_ctx,
grpc_completion_queue *cq) {
cq_data *cqd = &cq->data;
GPR_ASSERT(cqd->shutdown_called); GPR_ASSERT(cqd->shutdown_called);
GPR_ASSERT(!gpr_atm_no_barrier_load(&cqd->shutdown)); GPR_ASSERT(!gpr_atm_no_barrier_load(&cqd->shutdown));
gpr_atm_no_barrier_store(&cqd->shutdown, 1); gpr_atm_no_barrier_store(&cqd->shutdown, 1);
cq->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cq), cq->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cq),
&cqd->pollset_shutdown_done); &cq->pollset_shutdown_done);
} }
/* Shutdown simply drops a ref that we reserved at creation time; if we drop static void cq_shutdown_pluck(grpc_exec_ctx *exec_ctx,
to zero here, then enter shutdown mode and wake up any waiters */ grpc_completion_queue *cq) {
void grpc_completion_queue_shutdown(grpc_completion_queue *cq) { cq_pluck_data *cqd = DATA_FROM_CQ(cq);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
GRPC_API_TRACE("grpc_completion_queue_shutdown(cq=%p)", 1, (cq));
cq_data *cqd = &cq->data;
gpr_mu_lock(cqd->mu); gpr_mu_lock(cq->mu);
if (cqd->shutdown_called) { if (cqd->shutdown_called) {
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
GPR_TIMER_END("grpc_completion_queue_shutdown", 0); GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
return; return;
} }
cqd->shutdown_called = 1; cqd->shutdown_called = 1;
if (gpr_unref(&cqd->pending_events)) { if (gpr_unref(&cqd->pending_events)) {
cq_finish_shutdown(&exec_ctx, cq); cq_finish_shutdown_pluck(exec_ctx, cq);
} }
gpr_mu_unlock(cqd->mu); gpr_mu_unlock(cq->mu);
}
/* Shutdown simply drops a ref that we reserved at creation time; if we drop
to zero here, then enter shutdown mode and wake up any waiters */
void grpc_completion_queue_shutdown(grpc_completion_queue *cq) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
GRPC_API_TRACE("grpc_completion_queue_shutdown(cq=%p)", 1, (cq));
cq->vtable->shutdown(&exec_ctx, cq);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
GPR_TIMER_END("grpc_completion_queue_shutdown", 0); GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
} }
@ -1114,12 +1195,6 @@ void grpc_completion_queue_destroy(grpc_completion_queue *cq) {
GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0); GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0);
grpc_completion_queue_shutdown(cq); grpc_completion_queue_shutdown(cq);
/* TODO (sreek): This should not ideally be here. Refactor it into the
* cq_vtable (perhaps have a create/destroy methods in the cq vtable) */
if (cq->vtable->cq_completion_type == GRPC_CQ_NEXT) {
GPR_ASSERT(cq_event_queue_num_items(&cq->data.queue) == 0);
}
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "destroy"); GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cq, "destroy");
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
@ -1130,18 +1205,6 @@ grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cq) {
return cq->poller_vtable->can_get_pollset ? POLLSET_FROM_CQ(cq) : NULL; return cq->poller_vtable->can_get_pollset ? POLLSET_FROM_CQ(cq) : NULL;
} }
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) {
return CQ_FROM_POLLSET(ps);
}
void grpc_cq_mark_server_cq(grpc_completion_queue *cq) {
cq->data.is_server_cq = 1;
}
bool grpc_cq_is_server_cq(grpc_completion_queue *cq) {
return cq->data.is_server_cq;
}
bool grpc_cq_can_listen(grpc_completion_queue *cq) { bool grpc_cq_can_listen(grpc_completion_queue *cq) {
return cq->poller_vtable->can_listen; return cq->poller_vtable->can_listen;
} }

@ -99,10 +99,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
void *done_arg, grpc_cq_completion *storage); void *done_arg, grpc_cq_completion *storage);
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps);
void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
bool grpc_cq_is_server_cq(grpc_completion_queue *cc);
bool grpc_cq_can_listen(grpc_completion_queue *cc); bool grpc_cq_can_listen(grpc_completion_queue *cc);
grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc); grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc);

@ -964,8 +964,6 @@ static void register_completion_queue(grpc_server *server,
if (server->cqs[i] == cq) return; if (server->cqs[i] == cq) return;
} }
grpc_cq_mark_server_cq(cq);
GRPC_CQ_INTERNAL_REF(cq, "server"); GRPC_CQ_INTERNAL_REF(cq, "server");
n = server->cq_count++; n = server->cq_count++;
server->cqs = gpr_realloc(server->cqs, server->cqs = gpr_realloc(server->cqs,
@ -1129,9 +1127,8 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
chand->channel = channel; chand->channel = channel;
size_t cq_idx; size_t cq_idx;
grpc_completion_queue *accepting_cq = grpc_cq_from_pollset(accepting_pollset);
for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) { for (cq_idx = 0; cq_idx < s->cq_count; cq_idx++) {
if (s->cqs[cq_idx] == accepting_cq) break; if (grpc_cq_pollset(s->cqs[cq_idx]) == accepting_pollset) break;
} }
if (cq_idx == s->cq_count) { if (cq_idx == s->cq_count) {
/* completion queue not found: pick a random one to publish new calls to */ /* completion queue not found: pick a random one to publish new calls to */

@ -28,8 +28,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Reference implementation for reflection in gRPC Python.""" """Reference implementation for reflection in gRPC Python."""
import threading
import grpc import grpc
from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pb2
from google.protobuf import descriptor_pool from google.protobuf import descriptor_pool
@ -120,6 +118,7 @@ class ReflectionServicer(reflection_pb2_grpc.ServerReflectionServicer):
])) ]))
def ServerReflectionInfo(self, request_iterator, context): def ServerReflectionInfo(self, request_iterator, context):
# pylint: disable=unused-argument
for request in request_iterator: for request in request_iterator:
if request.HasField('file_by_filename'): if request.HasField('file_by_filename'):
yield self._file_by_filename(request.file_by_filename) yield self._file_by_filename(request.file_by_filename)
@ -152,4 +151,4 @@ def enable_server_reflection(service_names, server, pool=None):
pool: DescriptorPool object to use (descriptor_pool.Default() if None). pool: DescriptorPool object to use (descriptor_pool.Default() if None).
""" """
reflection_pb2_grpc.add_ServerReflectionServicer_to_server( reflection_pb2_grpc.add_ServerReflectionServicer_to_server(
ReflectionServicer(service_names, pool), server) ReflectionServicer(service_names, pool=pool), server)

@ -419,18 +419,18 @@ static void BM_PumpUnbalancedUnary_Trickle(benchmark::State& state) {
} }
static void UnaryTrickleArgs(benchmark::internal::Benchmark* b) { static void UnaryTrickleArgs(benchmark::internal::Benchmark* b) {
// A selection of interesting numbers
const int cli_1024k = 1024 * 1024; const int cli_1024k = 1024 * 1024;
const int cli_32M = 32 * 1024 * 1024; const int cli_32M = 32 * 1024 * 1024;
const int svr_256k = 256 * 1024; const int svr_256k = 256 * 1024;
const int svr_4M = 4 * 1024 * 1024; const int svr_4M = 4 * 1024 * 1024;
const int svr_64M = 64 * 1024 * 1024; const int svr_64M = 64 * 1024 * 1024;
for (int bw = 64; bw <= 128 * 1024 * 1024; bw *= 16) { for (int bw = 64; bw <= 128 * 1024 * 1024; bw *= 16) {
b->Args({bw, cli_1024k, svr_256k}); for (auto svr : {svr_256k, svr_4M, svr_64M}) {
b->Args({bw, cli_1024k, svr_4M}); for (auto cli : {cli_1024k, cli_32M}) {
b->Args({bw, cli_1024k, svr_64M}); b->Args({cli, svr, bw});
b->Args({bw, cli_32M, svr_256k}); }
b->Args({bw, cli_32M, svr_4M}); }
b->Args({bw, cli_32M, svr_64M});
} }
} }
BENCHMARK(BM_PumpUnbalancedUnary_Trickle)->Apply(UnaryTrickleArgs); BENCHMARK(BM_PumpUnbalancedUnary_Trickle)->Apply(UnaryTrickleArgs);

@ -31,18 +31,22 @@
set -ex set -ex
# change to root directory # change to root directory
cd $(dirname $0)/../.. cd "$(dirname "$0")/../.."
DIRS=src/python/grpcio/grpc DIRS=(
'src/python/grpcio/grpc'
'src/python/grpcio_reflection/grpc_reflection'
'src/python/grpcio_health_checking/grpc_health'
)
VIRTUALENV=python_pylint_venv VIRTUALENV=python_pylint_venv
virtualenv $VIRTUALENV virtualenv $VIRTUALENV
PYTHON=`realpath $VIRTUALENV/bin/python` PYTHON=$(realpath $VIRTUALENV/bin/python)
$PYTHON -m pip install pylint==1.6.5 $PYTHON -m pip install pylint==1.6.5
for dir in $DIRS; do for dir in "${DIRS[@]}"; do
$PYTHON -m pylint --rcfile=.pylintrc -rn $dir || exit $? $PYTHON -m pylint --rcfile=.pylintrc -rn "$dir" || exit $?
done done
exit 0 exit 0

@ -55,6 +55,9 @@ RUN pip install pip --upgrade
RUN pip install virtualenv RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
# Google Cloud platform API libraries
RUN pip install --upgrade google-api-python-client
# Prepare ccache # Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++ RUN ln -s /usr/bin/ccache /usr/local/bin/g++

@ -55,6 +55,9 @@ RUN pip install pip --upgrade
RUN pip install virtualenv RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
# Google Cloud platform API libraries
RUN pip install --upgrade google-api-python-client
# Prepare ccache # Prepare ccache
RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
RUN ln -s /usr/bin/ccache /usr/local/bin/g++ RUN ln -s /usr/bin/ccache /usr/local/bin/g++

@ -35,4 +35,8 @@ cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc source tools/internal_ci/helper_scripts/prepare_build_linux_rc
# TODO(jtattermusch): install ruby on the internal_ci worker
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable --ruby
tools/run_tests/task_runner.py -f artifact linux tools/run_tests/task_runner.py -f artifact linux

@ -0,0 +1,39 @@
# Copyright 2017, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/linux/grpc_sanity.sh"
timeout_mins: 20
action {
define_artifacts {
regex: "**/*sponge_log.xml"
}
}

@ -35,4 +35,4 @@ cd $(dirname $0)/../../..
source tools/internal_ci/helper_scripts/prepare_build_linux_rc source tools/internal_ci/helper_scripts/prepare_build_linux_rc
tools/run_tests/run_tests.py -l sanity -c opt -t -x sponge_log.xml --use_docker --report_suite_name sanity_linux_opt tools/run_tests/run_tests_matrix.py -f basictests linux sanity opt --inner_jobs 16 -j 1 --internal_ci

@ -56,7 +56,7 @@ _BM_SPECS = {
}, },
'BM_PumpUnbalancedUnary_Trickle': { 'BM_PumpUnbalancedUnary_Trickle': {
'tpl': [], 'tpl': [],
'dyn': ['request_size', 'bandwidth_kilobits'], 'dyn': ['cli_req_size', 'svr_req_size', 'bandwidth_kilobits'],
}, },
'BM_ErrorStringOnNewError': { 'BM_ErrorStringOnNewError': {
'tpl': ['fixture'], 'tpl': ['fixture'],

@ -276,8 +276,13 @@ class Job(object):
env = sanitized_environment(env) env = sanitized_environment(env)
self._start = time.time() self._start = time.time()
cmdline = self._spec.cmdline cmdline = self._spec.cmdline
if measure_cpu_costs: # The Unix time command is finicky when used with MSBuild, so we don't use it
# with jobs that run MSBuild.
global measure_cpu_costs
if measure_cpu_costs and not 'vsprojects\\build' in cmdline[0]:
cmdline = ['time', '-p'] + cmdline cmdline = ['time', '-p'] + cmdline
else:
measure_cpu_costs = False
try_start = lambda: subprocess.Popen(args=cmdline, try_start = lambda: subprocess.Popen(args=cmdline,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
stdout=self._tempfile, stdout=self._tempfile,

Loading…
Cancel
Save