static grpc_cq_completion *cq_event_queue_pop(grpc_cq_event_queue *q) { grpc_cq_completion *c = NULL; if (gpr_spinlock_trylock(&q->queue_lock)) { c = (grpc_cq_completion *)gpr_mpscq_pop(&q->queue); gpr_spinlock_unlock(&q->queue_lock); } if (c) { gpr_atm_no_barrier_fetch_add(&q->num_queue_items, -1); } return c; }
static void test_serial(void) { gpr_log(GPR_DEBUG, "test_serial"); gpr_mpscq q; gpr_mpscq_init(&q); for (size_t i = 0; i < 10000000; i++) { gpr_mpscq_push(&q, &new_node(i, NULL)->node); } for (size_t i = 0; i < 10000000; i++) { test_node *n = (test_node *)gpr_mpscq_pop(&q); GPR_ASSERT(n); GPR_ASSERT(n->i == i); gpr_free(n); } }
static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("workqueue.on_readable", 0); grpc_workqueue *workqueue = arg; if (error != GRPC_ERROR_NONE) { /* HACK: let wakeup_fd code know that we stole the fd */ workqueue->wakeup_fd.read_fd = 0; grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); GPR_ASSERT(gpr_atm_no_barrier_load(&workqueue->state) == 0); gpr_free(workqueue); } else { error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); gpr_mpscq_node *n = gpr_mpscq_pop(&workqueue->queue); if (error == GRPC_ERROR_NONE) { grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, &workqueue->read_closure); } else { /* recurse to get error handling */ on_readable(exec_ctx, arg, error); } if (n == NULL) { /* try again - queue in an inconsistant state */ wakeup(exec_ctx, workqueue); } else { switch (gpr_atm_full_fetch_add(&workqueue->state, -2)) { case 3: // had one count, one unorphaned --> done, unorphaned break; case 2: // had one count, one orphaned --> done, orphaned workqueue_destroy(exec_ctx, workqueue); break; case 1: case 0: // these values are illegal - representing an already done or // deleted workqueue GPR_UNREACHABLE_CODE(break); default: // schedule a wakeup since there's more to do wakeup(exec_ctx, workqueue); } grpc_closure *cl = (grpc_closure *)n; grpc_error *clerr = cl->error; cl->cb(exec_ctx, cl->cb_arg, clerr); GRPC_ERROR_UNREF(clerr); } } GPR_TIMER_END("workqueue.on_readable", 0); }
static void pull_thread(void *arg) { pull_args *pa = arg; gpr_event_wait(pa->start, gpr_inf_future(GPR_CLOCK_REALTIME)); for (;;) { gpr_mu_lock(&pa->mu); if (pa->num_done == pa->num_thds) { gpr_mu_unlock(&pa->mu); return; } gpr_mpscq_node *n; while ((n = gpr_mpscq_pop(pa->q)) == NULL) { pa->spins++; } test_node *tn = (test_node *)n; GPR_ASSERT(*tn->ctr == tn->i - 1); *tn->ctr = tn->i; if (tn->i == THREAD_ITERATIONS) pa->num_done++; gpr_free(tn); gpr_mu_unlock(&pa->mu); } }
static void test_mt(void) { gpr_log(GPR_DEBUG, "test_mt"); gpr_event start; gpr_event_init(&start); gpr_thd_id thds[100]; thd_args ta[GPR_ARRAY_SIZE(thds)]; gpr_mpscq q; gpr_mpscq_init(&q); for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_options options = gpr_thd_options_default(); gpr_thd_options_set_joinable(&options); ta[i].ctr = 0; ta[i].q = &q; ta[i].start = &start; GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options)); } size_t num_done = 0; size_t spins = 0; gpr_event_set(&start, (void *)1); while (num_done != GPR_ARRAY_SIZE(thds)) { gpr_mpscq_node *n; while ((n = gpr_mpscq_pop(&q)) == NULL) { spins++; } test_node *tn = (test_node *)n; GPR_ASSERT(*tn->ctr == tn->i - 1); *tn->ctr = tn->i; if (tn->i == THREAD_ITERATIONS) num_done++; gpr_free(tn); } gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins); for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_join(thds[i]); } gpr_mpscq_destroy(&q); }