static void producer_thread(void *arg) { test_thread_options *opt = arg; int i; gpr_log(GPR_INFO, "producer %d started", opt->id); gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1); GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time())); gpr_log(GPR_INFO, "producer %d phase 1", opt->id); for (i = 0; i < TEST_THREAD_EVENTS; i++) { grpc_cq_begin_op(opt->cc, NULL, GRPC_WRITE_ACCEPTED); } gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id); gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr) 1); GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time())); gpr_log(GPR_INFO, "producer %d phase 2", opt->id); for (i = 0; i < TEST_THREAD_EVENTS; i++) { grpc_cq_end_write_accepted(opt->cc, (void *)(gpr_intptr) 1, NULL, NULL, NULL, GRPC_OP_OK); opt->events_triggered++; } gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id); gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1); }
static void consumer_thread(void *arg) { test_thread_options *opt = arg; grpc_event *ev; gpr_log(GPR_INFO, "consumer %d started", opt->id); gpr_event_set(&opt->on_started, (void *)(gpr_intptr) 1); GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time())); gpr_log(GPR_INFO, "consumer %d phase 1", opt->id); gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id); gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr) 1); GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time())); gpr_log(GPR_INFO, "consumer %d phase 2", opt->id); for (;;) { ev = grpc_completion_queue_next(opt->cc, ten_seconds_time()); GPR_ASSERT(ev); switch (ev->type) { case GRPC_WRITE_ACCEPTED: GPR_ASSERT(ev->data.write_accepted == GRPC_OP_OK); opt->events_triggered++; grpc_event_finish(ev); break; case GRPC_QUEUE_SHUTDOWN: gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id); gpr_event_set(&opt->on_finished, (void *)(gpr_intptr) 1); grpc_event_finish(ev); return; default: gpr_log(GPR_ERROR, "Invalid event received: %d", ev->type); abort(); } } }
static void producer_thread(void *arg) { test_thread_options *opt = arg; int i; gpr_log(GPR_INFO, "producer %d started", opt->id); gpr_event_set(&opt->on_started, (void *)(gpr_intptr)1); GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time())); gpr_log(GPR_INFO, "producer %d phase 1", opt->id); for (i = 0; i < TEST_THREAD_EVENTS; i++) { grpc_cq_begin_op(opt->cc); } gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id); gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr)1); GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time())); gpr_log(GPR_INFO, "producer %d phase 2", opt->id); for (i = 0; i < TEST_THREAD_EVENTS; i++) { grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, 1, free_completion, NULL, gpr_malloc(sizeof(grpc_cq_completion))); opt->events_triggered++; } gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id); gpr_event_set(&opt->on_finished, (void *)(gpr_intptr)1); }
static void consumer_thread(void *arg) { test_thread_options *opt = arg; grpc_event ev; gpr_log(GPR_INFO, "consumer %d started", opt->id); gpr_event_set(&opt->on_started, (void *)(gpr_intptr)1); GPR_ASSERT(gpr_event_wait(opt->phase1, ten_seconds_time())); gpr_log(GPR_INFO, "consumer %d phase 1", opt->id); gpr_log(GPR_INFO, "consumer %d phase 1 done", opt->id); gpr_event_set(&opt->on_phase1_done, (void *)(gpr_intptr)1); GPR_ASSERT(gpr_event_wait(opt->phase2, ten_seconds_time())); gpr_log(GPR_INFO, "consumer %d phase 2", opt->id); for (;;) { ev = grpc_completion_queue_next(opt->cc, ten_seconds_time(), NULL); switch (ev.type) { case GRPC_OP_COMPLETE: GPR_ASSERT(ev.success); opt->events_triggered++; break; case GRPC_QUEUE_SHUTDOWN: gpr_log(GPR_INFO, "consumer %d phase 2 done", opt->id); gpr_event_set(&opt->on_finished, (void *)(gpr_intptr)1); return; case GRPC_QUEUE_TIMEOUT: gpr_log(GPR_ERROR, "Invalid timeout received"); abort(); } } }
void test_times_out(void) { struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); int svr_fd; #define NUM_CLIENT_CONNECTS 10 int client_fd[NUM_CLIENT_CONNECTS]; int i; int r; gpr_event ev; gpr_timespec connect_deadline; gpr_event_init(&ev); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; /* create a dummy server */ svr_fd = socket(AF_INET, SOCK_STREAM, 0); GPR_ASSERT(svr_fd >= 0); GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len)); GPR_ASSERT(0 == listen(svr_fd, 1)); /* Get its address */ GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0); /* tie up the listen buffer, which is somewhat arbitrarily sized. */ for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) { client_fd[i] = socket(AF_INET, SOCK_STREAM, 0); grpc_set_socket_nonblocking(client_fd[i], 1); do { r = connect(client_fd[i], (struct sockaddr *)&addr, addr_len); } while (r == -1 && errno == EINTR); GPR_ASSERT(r < 0); GPR_ASSERT(errno == EWOULDBLOCK || errno == EINPROGRESS); } /* connect to dummy server address */ connect_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1); grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len, connect_deadline); /* Make sure the event doesn't trigger early */ GPR_ASSERT(!gpr_event_wait(&ev, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(500))); /* Now wait until it should have triggered */ sleep(1); /* wait for the connection callback to finish */ GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); close(svr_fd); for (i = 0; i < NUM_CLIENT_CONNECTS; ++i) { close(client_fd[i]); } }
static void test_thread(void *args) { thd_args *a = args; gpr_event_wait(a->start, gpr_inf_future(GPR_CLOCK_REALTIME)); for (size_t i = 1; i <= THREAD_ITERATIONS; i++) { gpr_mpscq_push(a->q, &new_node(i, &a->ctr)->node); } }
void test_succeeds(void) { struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); int svr_fd; int r; gpr_event ev; gpr_event_init(&ev); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; /* create a dummy server */ svr_fd = socket(AF_INET, SOCK_STREAM, 0); GPR_ASSERT(svr_fd >= 0); GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr *)&addr, addr_len)); GPR_ASSERT(0 == listen(svr_fd, 1)); /* connect to it */ GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0); grpc_tcp_client_connect(must_succeed, &ev, (struct sockaddr *)&addr, addr_len, gpr_inf_future); /* await the connection */ do { addr_len = sizeof(addr); r = accept(svr_fd, (struct sockaddr *)&addr, &addr_len); } while (r == -1 && errno == EINTR); GPR_ASSERT(r >= 0); close(r); /* wait for the connection callback to finish */ GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); }
static void run_test(const char *response_payload, size_t response_payload_length, grpc_status_code expected_status, const char *expected_detail) { test_tcp_server test_server; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_event ev; grpc_init(); gpr_event_init(&ev); server_port = grpc_pick_unused_port_or_die(); test_tcp_server_init(&test_server, on_connect, &test_server); test_tcp_server_start(&test_server, server_port); state.response_payload = response_payload; state.response_payload_length = response_payload_length; /* poll server until sending out the response */ poll_server_until_read_done(&test_server, &ev); start_rpc(server_port, expected_status, expected_detail); gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME)); /* clean up */ grpc_endpoint_shutdown(&exec_ctx, state.tcp); grpc_endpoint_destroy(&exec_ctx, state.tcp); grpc_exec_ctx_finish(&exec_ctx); cleanup_rpc(); test_tcp_server_destroy(&test_server); grpc_shutdown(); }
static void shutdown_during_write_test(grpc_endpoint_test_config config, size_t slice_size) { /* test that shutdown with a pending write creates no leaks */ gpr_timespec deadline; size_t size; size_t nblocks; int current_data = 1; shutdown_during_write_test_state read_st; shutdown_during_write_test_state write_st; gpr_slice *slices; grpc_endpoint_test_fixture f = begin_test(config, __FUNCTION__, slice_size); gpr_log(GPR_INFO, "testing shutdown during a write"); read_st.ep = f.client_ep; write_st.ep = f.server_ep; gpr_event_init(&read_st.ev); gpr_event_init(&write_st.ev); grpc_endpoint_notify_on_read( read_st.ep, shutdown_during_write_test_read_handler, &read_st); for (size = 1;; size *= 2) { slices = allocate_blocks(size, 1, &nblocks, ¤t_data); switch (grpc_endpoint_write(write_st.ep, slices, nblocks, shutdown_during_write_test_write_handler, &write_st)) { case GRPC_ENDPOINT_WRITE_DONE: break; case GRPC_ENDPOINT_WRITE_ERROR: gpr_log(GPR_ERROR, "error writing"); abort(); case GRPC_ENDPOINT_WRITE_PENDING: grpc_endpoint_shutdown(write_st.ep); deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10); GPR_ASSERT(gpr_event_wait(&write_st.ev, deadline)); grpc_endpoint_destroy(write_st.ep); GPR_ASSERT(gpr_event_wait(&read_st.ev, deadline)); gpr_free(slices); end_test(config); return; } gpr_free(slices); } gpr_log(GPR_ERROR, "should never reach here"); abort(); }
void grpc_iocp_shutdown(void) { BOOL success; gpr_event_set(&g_shutdown_iocp, (void *)1); grpc_iocp_kick(); gpr_event_wait(&g_iocp_done, gpr_inf_future(GPR_CLOCK_REALTIME)); success = CloseHandle(g_iocp); GPR_ASSERT(success); }
void grpc_iomgr_shutdown(void) { grpc_iomgr_object *obj; grpc_iomgr_closure *closure; gpr_timespec shutdown_deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(10)); gpr_mu_lock(&g_mu); g_shutdown = 1; while (g_cbs_head || g_root_object.next != &g_root_object) { size_t nobjs = count_objects(); gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", nobjs, g_cbs_head ? " and executing final callbacks" : ""); if (g_cbs_head) { do { closure = g_cbs_head; g_cbs_head = closure->next; if (!g_cbs_head) g_cbs_tail = NULL; gpr_mu_unlock(&g_mu); closure->cb(closure->cb_arg, 0); gpr_mu_lock(&g_mu); } while (g_cbs_head); continue; } if (nobjs > 0) { int timeout = 0; gpr_timespec short_deadline = gpr_time_add(gpr_now(), gpr_time_from_millis(100)); while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) { if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) { timeout = 1; break; } } if (timeout) { gpr_log(GPR_DEBUG, "Failed to free %d iomgr objects before shutdown deadline: " "memory leaks are likely", count_objects()); for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) { gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s", obj->name); } break; } } } gpr_mu_unlock(&g_mu); grpc_kick_poller(); gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future); grpc_iomgr_platform_shutdown(); grpc_alarm_list_shutdown(); gpr_mu_destroy(&g_mu); gpr_cv_destroy(&g_rcv); }
static void test_initial_string(test_tcp_server *server, int secure) { gpr_event ev; gpr_event_init(&ev); grpc_test_set_initial_connect_string_function(set_magic_initial_string); poll_server_until_read_done(server, &ev); start_rpc(secure, server_port); gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME)); match_initial_magic_string(&state.incoming_buffer); cleanup_rpc(); }
void grpc_iocp_shutdown(void) { BOOL success; gpr_event_set(&g_shutdown_iocp, (void *)1); success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR) &g_iocp_kick_token, &g_iocp_custom_overlap); GPR_ASSERT(success); gpr_event_wait(&g_iocp_done, gpr_inf_future); success = CloseHandle(g_iocp); GPR_ASSERT(success); }
static void test_unparseable_hostports(void) { const char* const kCases[] = { "[", "[::1", "[::1]bad", "[1.2.3.4]", "[localhost]", "[localhost]:1", }; unsigned i; for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) { gpr_event ev; gpr_event_init(&ev); grpc_resolve_address(kCases[i], "1", must_fail, &ev); GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); } }
static void test_invalid_ip_addresses(void) { const char* const kCases[] = { "293.283.1238.3:1", "[2001:db8::11111]:1", }; unsigned i; for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) { gpr_event ev; gpr_event_init(&ev); grpc_resolve_address(kCases[i], NULL, must_fail, &ev); GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); } }
static void test_ipv6_without_port(void) { const char* const kCases[] = { "2001:db8::1", "2001:db8::1.2.3.4", "[2001:db8::1]", }; unsigned i; for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) { gpr_event ev; gpr_event_init(&ev); grpc_resolve_address(kCases[i], "80", must_succeed, &ev); GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); } }
// interleave waiting for an event with a timer check static bool wait_loop(int deadline_seconds, gpr_event *ev) { while (deadline_seconds) { gpr_log(GPR_DEBUG, "Test: waiting for %d more seconds", deadline_seconds); if (gpr_event_wait(ev, grpc_timeout_seconds_to_deadline(1))) return true; deadline_seconds--; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_timer_check(&exec_ctx, gpr_now(GPR_CLOCK_MONOTONIC), NULL); grpc_exec_ctx_finish(&exec_ctx); } return false; }
static void test_initial_string_with_redirect(test_tcp_server *server, int secure) { gpr_event ev; gpr_event_init(&ev); int another_port = grpc_pick_unused_port_or_die(); grpc_test_set_initial_connect_string_function( reset_addr_and_set_magic_string); poll_server_until_read_done(server, &ev); start_rpc(secure, another_port); gpr_event_wait(&ev, gpr_inf_future(GPR_CLOCK_REALTIME)); match_initial_magic_string(&state.incoming_buffer); cleanup_rpc(); }
void gpr_cancellable_cancel(gpr_cancellable *c) { if (!gpr_cancellable_is_cancelled(c)) { int failures; int backoff = 1; do { struct gpr_cancellable_list_ *l; struct gpr_cancellable_list_ *nl; gpr_mu *omu = 0; /* one-element cache of a processed gpr_mu */ gpr_cv *ocv = 0; /* one-element cache of a processd gpr_cv */ gpr_mu_lock(&c->mu); gpr_atm_rel_store(&c->cancelled, 1); failures = 0; for (l = c->waiters.next; l != &c->waiters; l = nl) { nl = l->next; if (omu != l->mu) { omu = l->mu; if (gpr_mu_trylock(l->mu)) { gpr_mu_unlock(l->mu); l->next->prev = l->prev; /* remove *l from list */ l->prev->next = l->next; /* allow unconditional dequeue in gpr_cv_cancellable_wait() */ l->next = l; l->prev = l; ocv = 0; /* force broadcast */ } else { failures++; } } if (ocv != l->cv) { ocv = l->cv; gpr_cv_broadcast(l->cv); } } gpr_mu_unlock(&c->mu); if (failures != 0) { if (backoff < 10) { volatile int i; for (i = 0; i != (1 << backoff); i++) { } backoff++; } else { gpr_event ev; gpr_event_init(&ev); gpr_event_wait( &ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000, GPR_TIMESPAN))); } } } while (failures != 0); } }
void grpc_iomgr_shutdown(void) { delayed_callback *cb; gpr_timespec shutdown_deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(10)); gpr_mu_lock(&g_mu); g_shutdown = 1; while (g_cbs_head || g_refs) { gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed%s", g_refs, g_cbs_head ? " and executing final callbacks" : ""); while (g_cbs_head) { cb = g_cbs_head; g_cbs_head = cb->next; if (!g_cbs_head) g_cbs_tail = NULL; gpr_mu_unlock(&g_mu); cb->cb(cb->cb_arg, 0); gpr_free(cb); gpr_mu_lock(&g_mu); } if (g_refs) { int timeout = 0; gpr_timespec short_deadline = gpr_time_add(gpr_now(), gpr_time_from_millis(100)); while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) { if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) { timeout = 1; break; } } if (timeout) { gpr_log(GPR_DEBUG, "Failed to free %d iomgr objects before shutdown deadline: " "memory leaks are likely", g_refs); break; } } } gpr_mu_unlock(&g_mu); grpc_kick_poller(); gpr_event_wait(&g_background_callback_executor_done, gpr_inf_future); grpc_iomgr_platform_shutdown(); grpc_alarm_list_shutdown(); gpr_mu_destroy(&g_mu); gpr_cv_destroy(&g_cv); gpr_cv_destroy(&g_rcv); }
void args_finish(grpc_exec_ctx *exec_ctx, args_struct *args) { GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline())); grpc_resolved_addresses_destroy(args->addrs); grpc_pollset_set_del_pollset(exec_ctx, args->pollset_set, args->pollset); grpc_pollset_set_destroy(exec_ctx, args->pollset_set); grpc_closure do_nothing_cb; GRPC_CLOSURE_INIT(&do_nothing_cb, do_nothing, NULL, grpc_schedule_on_exec_ctx); grpc_pollset_shutdown(exec_ctx, args->pollset, &do_nothing_cb); // exec_ctx needs to be flushed before calling grpc_pollset_destroy() grpc_exec_ctx_flush(exec_ctx); grpc_pollset_destroy(exec_ctx, args->pollset); gpr_free(args->pollset); }
static void test_get(int use_ssl) { grpc_httpcli_request req; gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_get", use_ssl); gpr_event_init(&g_done); memset(&req, 0, sizeof(req)); req.host = "www.google.com"; req.path = "/"; req.use_ssl = use_ssl; grpc_httpcli_get(&req, n_seconds_time(15), on_finish, (void *)42); GPR_ASSERT(gpr_event_wait(&g_done, n_seconds_time(20))); }
/* Wait a millisecond and increment counter on each iteration, using an event for timing; then mark thread as done. */ static void inc_with_1ms_delay_event(void *v /*=m*/) { struct test *m = v; gpr_int64 i; for (i = 0; i != m->iterations; i++) { gpr_timespec deadline; deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000, GPR_TIMESPAN)); GPR_ASSERT(gpr_event_wait(&m->event, deadline) == NULL); gpr_mu_lock(&m->mu); m->counter++; gpr_mu_unlock(&m->mu); } mark_thread_done(m); }
/* Wait until m->event is set to (void *)1, then decrement m->refcount m->stats_counter m->iterations times, and ensure that the last decrement caused the counter to reach zero, then mark thread as done. */ static void refcheck(void *v /*=m*/) { struct test *m = v; gpr_int64 n = m->iterations * m->threads; gpr_int64 i; GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) == (void *)1); GPR_ASSERT(gpr_event_get(&m->event) == (void *)1); for (i = 1; i != n; i++) { GPR_ASSERT(!gpr_unref(&m->refcount)); m->counter++; } GPR_ASSERT(gpr_unref(&m->refcount)); m->counter++; mark_thread_done(m); }
void test_fails(void) { struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); gpr_event ev; gpr_event_init(&ev); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; /* connect to a broken address */ grpc_tcp_client_connect(must_fail, &ev, (struct sockaddr *)&addr, addr_len, gpr_inf_future); /* wait for the connection callback to finish */ GPR_ASSERT(gpr_event_wait(&ev, test_deadline())); }
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); } }
void grpc_run_bad_client_test(const char *name, const char *client_payload, size_t client_payload_length, grpc_bad_client_server_side_validator validator) { grpc_endpoint_pair sfd; thd_args a; gpr_thd_id id; gpr_slice slice = gpr_slice_from_copied_buffer(client_payload, client_payload_length); /* Add a debug log */ gpr_log(GPR_INFO, "TEST: %s", name); /* Init grpc */ grpc_init(); /* Create endpoints */ sfd = grpc_iomgr_create_endpoint_pair(65536); /* Create server, completion events */ a.server = grpc_server_create_from_filters(NULL, 0, NULL); a.cq = grpc_completion_queue_create(); gpr_event_init(&a.done_thd); gpr_event_init(&a.done_write); a.validator = validator; grpc_server_register_completion_queue(a.server, a.cq); grpc_server_start(a.server); grpc_create_chttp2_transport(server_setup_transport, &a, NULL, sfd.server, NULL, 0, grpc_mdctx_create(), 0); /* Bind everything into the same pollset */ grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq)); grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq)); /* Check a ground truth */ GPR_ASSERT(grpc_server_has_open_connections(a.server)); /* Start validator */ gpr_thd_new(&id, thd_func, &a, NULL); /* Write data */ switch (grpc_endpoint_write(sfd.client, &slice, 1, done_write, &a)) { case GRPC_ENDPOINT_WRITE_DONE: done_write(&a, 1); break; case GRPC_ENDPOINT_WRITE_PENDING: break; case GRPC_ENDPOINT_WRITE_ERROR: done_write(&a, 0); break; } /* Await completion */ GPR_ASSERT( gpr_event_wait(&a.done_write, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))); GPR_ASSERT(gpr_event_wait(&a.done_thd, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5))); /* Shutdown */ grpc_endpoint_destroy(sfd.client); grpc_server_destroy(a.server); grpc_completion_queue_destroy(a.cq); grpc_shutdown(); }
static void test_threading(int producers, int consumers) { test_thread_options *options = gpr_malloc((producers + consumers) * sizeof(test_thread_options)); gpr_event phase1 = GPR_EVENT_INIT; gpr_event phase2 = GPR_EVENT_INIT; grpc_completion_queue *cc = grpc_completion_queue_create(NULL); int i; int total_consumed = 0; static int optid = 101; gpr_log(GPR_INFO, "%s: %d producers, %d consumers", "test_threading", producers, consumers); /* start all threads: they will wait for phase1 */ for (i = 0; i < producers + consumers; i++) { gpr_thd_id id; gpr_event_init(&options[i].on_started); gpr_event_init(&options[i].on_phase1_done); gpr_event_init(&options[i].on_finished); options[i].phase1 = &phase1; options[i].phase2 = &phase2; options[i].events_triggered = 0; options[i].cc = cc; options[i].id = optid++; GPR_ASSERT(gpr_thd_new(&id, i < producers ? producer_thread : consumer_thread, options + i, NULL)); gpr_event_wait(&options[i].on_started, ten_seconds_time()); } /* start phase1: producers will pre-declare all operations they will complete */ gpr_log(GPR_INFO, "start phase 1"); gpr_event_set(&phase1, (void *)(gpr_intptr)1); gpr_log(GPR_INFO, "wait phase 1"); for (i = 0; i < producers + consumers; i++) { GPR_ASSERT(gpr_event_wait(&options[i].on_phase1_done, ten_seconds_time())); } gpr_log(GPR_INFO, "done phase 1"); /* start phase2: operations will complete, and consumers will consume them */ gpr_log(GPR_INFO, "start phase 2"); gpr_event_set(&phase2, (void *)(gpr_intptr)1); /* in parallel, we shutdown the completion channel - all events should still be consumed */ grpc_completion_queue_shutdown(cc); /* join all threads */ gpr_log(GPR_INFO, "wait phase 2"); for (i = 0; i < producers + consumers; i++) { GPR_ASSERT(gpr_event_wait(&options[i].on_finished, ten_seconds_time())); } gpr_log(GPR_INFO, "done phase 2"); /* destroy the completion channel */ grpc_completion_queue_destroy(cc); /* verify that everything was produced and consumed */ for (i = 0; i < producers + consumers; i++) { if (i < producers) { GPR_ASSERT(options[i].events_triggered == TEST_THREAD_EVENTS); } else { total_consumed += options[i].events_triggered; } } GPR_ASSERT(total_consumed == producers * TEST_THREAD_EVENTS); gpr_free(options); }
int run_concurrent_connectivity_test() { struct server_thread_args args; memset(&args, 0, sizeof(args)); grpc_init(); gpr_thd_id threads[NUM_THREADS]; gpr_thd_id server; char *localhost = gpr_strdup("localhost:54321"); gpr_thd_options options = gpr_thd_options_default(); gpr_thd_options_set_joinable(&options); /* First round, no server */ gpr_log(GPR_DEBUG, "Wave 1"); for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_new(&threads[i], create_loop_destroy, localhost, &options); } for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_join(threads[i]); } gpr_free(localhost); /* Second round, actual grpc server */ gpr_log(GPR_DEBUG, "Wave 2"); int port = grpc_pick_unused_port_or_die(); gpr_asprintf(&args.addr, "localhost:%d", port); args.server = grpc_server_create(NULL, NULL); grpc_server_add_insecure_http2_port(args.server, args.addr); args.cq = grpc_completion_queue_create_for_next(NULL); grpc_server_register_completion_queue(args.server, args.cq, NULL); grpc_server_start(args.server); gpr_thd_new(&server, server_thread, &args, &options); for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_new(&threads[i], create_loop_destroy, args.addr, &options); } for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_join(threads[i]); } grpc_server_shutdown_and_notify(args.server, args.cq, tag(0xd1e)); gpr_thd_join(server); grpc_server_destroy(args.server); grpc_completion_queue_destroy(args.cq); gpr_free(args.addr); /* Third round, bogus tcp server */ gpr_log(GPR_DEBUG, "Wave 3"); args.pollset = gpr_zalloc(grpc_pollset_size()); grpc_pollset_init(args.pollset, &args.mu); gpr_event_init(&args.ready); gpr_thd_new(&server, bad_server_thread, &args, &options); gpr_event_wait(&args.ready, gpr_inf_future(GPR_CLOCK_MONOTONIC)); for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_new(&threads[i], create_loop_destroy, args.addr, &options); } for (size_t i = 0; i < NUM_THREADS; ++i) { gpr_thd_join(threads[i]); } gpr_atm_rel_store(&args.stop, 1); gpr_thd_join(server); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_pollset_shutdown(&exec_ctx, args.pollset, GRPC_CLOSURE_CREATE(done_pollset_shutdown, args.pollset, grpc_schedule_on_exec_ctx)); grpc_exec_ctx_finish(&exec_ctx); grpc_shutdown(); return 0; }
static void test_connectivity(grpc_end2end_test_config config) { grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL); grpc_connectivity_state state; cq_verifier *cqv = cq_verifier_create(f.cq); child_events ce; gpr_thd_options thdopt = gpr_thd_options_default(); gpr_thd_id thdid; config.init_client(&f, NULL); ce.channel = f.client; ce.cq = f.cq; gpr_event_init(&ce.started); gpr_thd_options_set_joinable(&thdopt); GPR_ASSERT(gpr_thd_new(&thdid, child_thread, &ce, &thdopt)); gpr_event_wait(&ce.started, gpr_inf_future(GPR_CLOCK_MONOTONIC)); /* channels should start life in IDLE, and stay there */ GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 0) == GRPC_CHANNEL_IDLE); gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 0) == GRPC_CHANNEL_IDLE); /* start watching for a change */ gpr_log(GPR_DEBUG, "watching"); grpc_channel_watch_connectivity_state( f.client, GRPC_CHANNEL_IDLE, gpr_now(GPR_CLOCK_MONOTONIC), f.cq, tag(1)); /* eventually the child thread completion should trigger */ gpr_thd_join(thdid); /* check that we're still in idle, and start connecting */ GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) == GRPC_CHANNEL_IDLE); /* start watching for a change */ grpc_channel_watch_connectivity_state(f.client, GRPC_CHANNEL_IDLE, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(2)); /* and now the watch should trigger */ cq_expect_completion(cqv, tag(2), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE || state == GRPC_CHANNEL_CONNECTING); /* quickly followed by a transition to TRANSIENT_FAILURE */ grpc_channel_watch_connectivity_state(f.client, GRPC_CHANNEL_CONNECTING, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(3)); cq_expect_completion(cqv, tag(3), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE || state == GRPC_CHANNEL_CONNECTING); gpr_log(GPR_DEBUG, "*** STARTING SERVER ***"); /* now let's bring up a server to connect to */ config.init_server(&f, NULL); gpr_log(GPR_DEBUG, "*** STARTED SERVER ***"); /* we'll go through some set of transitions (some might be missed), until READY is reached */ while (state != GRPC_CHANNEL_READY) { grpc_channel_watch_connectivity_state( f.client, state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(4)); cq_expect_completion(cqv, tag(4), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); GPR_ASSERT(state == GRPC_CHANNEL_READY || state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_TRANSIENT_FAILURE); } /* bring down the server again */ /* we should go immediately to TRANSIENT_FAILURE */ gpr_log(GPR_DEBUG, "*** SHUTTING DOWN SERVER ***"); grpc_channel_watch_connectivity_state(f.client, GRPC_CHANNEL_READY, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(5)); grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead)); cq_expect_completion(cqv, tag(5), 1); cq_expect_completion(cqv, tag(0xdead), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE || state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_IDLE); /* cleanup server */ grpc_server_destroy(f.server); gpr_log(GPR_DEBUG, "*** SHUTDOWN SERVER ***"); grpc_channel_destroy(f.client); grpc_completion_queue_shutdown(f.cq); grpc_completion_queue_destroy(f.cq); config.tear_down_data(&f); cq_verifier_destroy(cqv); }