/* Cleaning up a list with pending alarms. */ void destruction_test(void) { grpc_alarm alarms[5]; grpc_alarm_list_init(gpr_time_0); memset(cb_called, 0, sizeof(cb_called)); grpc_alarm_init(&alarms[0], gpr_time_from_millis(100), cb, (void *)(gpr_intptr)0, gpr_time_0); grpc_alarm_init(&alarms[1], gpr_time_from_millis(3), cb, (void *)(gpr_intptr)1, gpr_time_0); grpc_alarm_init(&alarms[2], gpr_time_from_millis(100), cb, (void *)(gpr_intptr)2, gpr_time_0); grpc_alarm_init(&alarms[3], gpr_time_from_millis(3), cb, (void *)(gpr_intptr)3, gpr_time_0); grpc_alarm_init(&alarms[4], gpr_time_from_millis(1), cb, (void *)(gpr_intptr)4, gpr_time_0); GPR_ASSERT(1 == grpc_alarm_check(NULL, gpr_time_from_millis(2), NULL)); GPR_ASSERT(1 == cb_called[4][1]); grpc_alarm_cancel(&alarms[0]); grpc_alarm_cancel(&alarms[3]); GPR_ASSERT(1 == cb_called[0][0]); GPR_ASSERT(1 == cb_called[3][0]); grpc_alarm_list_shutdown(); GPR_ASSERT(1 == cb_called[1][0]); GPR_ASSERT(1 == cb_called[2][0]); }
/* Cleaning up a list with pending alarms. */ void destruction_test(void) { grpc_alarm alarms[5]; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_alarm_list_init(gpr_time_0(GPR_CLOCK_REALTIME)); memset(cb_called, 0, sizeof(cb_called)); grpc_alarm_init(&exec_ctx, &alarms[0], tfm(100), cb, (void *)(gpr_intptr)0, gpr_time_0(GPR_CLOCK_REALTIME)); grpc_alarm_init(&exec_ctx, &alarms[1], tfm(3), cb, (void *)(gpr_intptr)1, gpr_time_0(GPR_CLOCK_REALTIME)); grpc_alarm_init(&exec_ctx, &alarms[2], tfm(100), cb, (void *)(gpr_intptr)2, gpr_time_0(GPR_CLOCK_REALTIME)); grpc_alarm_init(&exec_ctx, &alarms[3], tfm(3), cb, (void *)(gpr_intptr)3, gpr_time_0(GPR_CLOCK_REALTIME)); grpc_alarm_init(&exec_ctx, &alarms[4], tfm(1), cb, (void *)(gpr_intptr)4, gpr_time_0(GPR_CLOCK_REALTIME)); GPR_ASSERT(1 == grpc_alarm_check(&exec_ctx, tfm(2), NULL)); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(1 == cb_called[4][1]); grpc_alarm_cancel(&exec_ctx, &alarms[0]); grpc_alarm_cancel(&exec_ctx, &alarms[3]); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(1 == cb_called[0][0]); GPR_ASSERT(1 == cb_called[3][0]); grpc_alarm_list_shutdown(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(1 == cb_called[1][0]); GPR_ASSERT(1 == cb_called[2][0]); }
/* cancel handshaking: cancel all requests, and shutdown (the caller promises not to initiate again) */ static void setup_cancel(grpc_transport_setup *sp) { grpc_client_setup *s = (grpc_client_setup *)sp; int cancel_alarm = 0; gpr_mu_lock(&s->mu); s->cancelled = 1; while (s->in_cb) { gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future); } GPR_ASSERT(s->refs > 0); /* effectively cancels the current request (if any) */ s->active_request = NULL; if (s->in_alarm) { cancel_alarm = 1; } if (--s->refs == 0) { gpr_mu_unlock(&s->mu); destroy_setup(s); } else { gpr_mu_unlock(&s->mu); } if (cancel_alarm) { grpc_alarm_cancel(&s->backoff_alarm); } }
static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0); lock(call); call->receiving = 0; if (success) { for (i = 0; success && i < call->recv_ops.nops; i++) { grpc_stream_op *op = &call->recv_ops.ops[i]; switch (op->type) { case GRPC_NO_OP: break; case GRPC_OP_METADATA: recv_metadata(call, &op->data.metadata); break; case GRPC_OP_BEGIN_MESSAGE: success = begin_message(call, op->data.begin_message); break; case GRPC_OP_SLICE: success = add_slice_to_message(call, op->data.slice); break; } } if (!success) { grpc_stream_ops_unref_owned_objects(&call->recv_ops.ops[i], call->recv_ops.nops - i); } if (call->recv_state == GRPC_STREAM_RECV_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_READ_CLOSED); call->read_state = READ_STATE_READ_CLOSED; } if (call->recv_state == GRPC_STREAM_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; if (call->have_alarm) { grpc_alarm_cancel(&call->alarm); call->have_alarm = 0; } } finish_read_ops(call); } else { finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, 0); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, 0); } call->recv_ops.nops = 0; unlock(call); GRPC_CALL_INTERNAL_UNREF(call, "receiving", 0); GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0); }
void grpc_call_destroy(grpc_call *c) { int cancel; lock(c); if (c->have_alarm) { grpc_alarm_cancel(&c->alarm); c->have_alarm = 0; } cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c); grpc_call_internal_unref(c, 1); }
void grpc_call_destroy(grpc_call *c) { int cancel; lock(c); if (c->have_alarm) { grpc_alarm_cancel(&c->alarm); c->have_alarm = 0; } cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c); GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1); }
static void on_connect(void *acp, int success) { async_connect *ac = acp; SOCKET sock = ac->socket->socket; grpc_endpoint *ep = NULL; grpc_winsocket_callback_info *info = &ac->socket->write_info; void(*cb)(void *arg, grpc_endpoint *tcp) = ac->cb; void *cb_arg = ac->cb_arg; grpc_alarm_cancel(&ac->alarm); if (success) { DWORD transfered_bytes = 0; DWORD flags; BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped, &transfered_bytes, FALSE, &flags); GPR_ASSERT(transfered_bytes == 0); if (!wsa_success) { char *utf8_message = gpr_format_message(WSAGetLastError()); gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message); gpr_free(utf8_message); goto finish; } else { ep = grpc_tcp_create(ac->socket); goto finish; } } else { gpr_log(GPR_ERROR, "on_connect is shutting down"); goto finish; } abort(); finish: gpr_mu_lock(&ac->mu); if (!ep) { grpc_winsocket_orphan(ac->socket); } async_connect_cleanup(ac); cb(cb_arg, ep); }
static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) { async_connect *ac = acp; int so_error = 0; socklen_t so_error_size; int err; int done; grpc_endpoint **ep = ac->ep; grpc_closure *closure = ac->closure; grpc_fd *fd; if (grpc_tcp_trace) { gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d", ac->addr_str, success); } gpr_mu_lock(&ac->mu); GPR_ASSERT(ac->fd); fd = ac->fd; ac->fd = NULL; gpr_mu_unlock(&ac->mu); grpc_alarm_cancel(exec_ctx, &ac->alarm); gpr_mu_lock(&ac->mu); if (success) { do { so_error_size = sizeof(so_error); err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); } while (err < 0 && errno == EINTR); if (err < 0) { gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s", ac->addr_str, strerror(errno)); goto finish; } else if (so_error != 0) { if (so_error == ENOBUFS) { /* We will get one of these errors if we have run out of memory in the kernel for the data structures allocated when you connect a socket. If this happens it is very likely that if we wait a little bit then try again the connection will work (since other programs or this program will close their network connections and free up memory). This does _not_ indicate that there is anything wrong with the server we are connecting to, this is a local problem. If you are looking at this code, then chances are that your program or another program on the same computer opened too many network connections. The "easy" fix: don't do that! */ gpr_log(GPR_ERROR, "kernel out of buffers"); gpr_mu_unlock(&ac->mu); grpc_fd_notify_on_write(exec_ctx, fd, &ac->write_closure); return; } else { switch (so_error) { case ECONNREFUSED: gpr_log( GPR_ERROR, "failed to connect to '%s': socket error: connection refused", ac->addr_str); break; default: gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d", ac->addr_str, so_error); break; } goto finish; } } else { grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str); fd = NULL; goto finish; } } else { gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred", ac->addr_str); goto finish; } GPR_UNREACHABLE_CODE(return ); finish: if (fd != NULL) { grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd); grpc_fd_orphan(exec_ctx, fd, NULL, "tcp_client_orphan"); fd = NULL; } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac->addr_str); gpr_free(ac); } grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL); }
static void on_writable(void *acp, int success) { async_connect *ac = acp; int so_error = 0; socklen_t so_error_size; int err; int fd = ac->fd->fd; int done; grpc_endpoint *ep = NULL; void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb; void *cb_arg = ac->cb_arg; grpc_alarm_cancel(&ac->alarm); if (success) { do { so_error_size = sizeof(so_error); err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size); } while (err < 0 && errno == EINTR); if (err < 0) { gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno)); goto finish; } else if (so_error != 0) { if (so_error == ENOBUFS) { /* We will get one of these errors if we have run out of memory in the kernel for the data structures allocated when you connect a socket. If this happens it is very likely that if we wait a little bit then try again the connection will work (since other programs or this program will close their network connections and free up memory). This does _not_ indicate that there is anything wrong with the server we are connecting to, this is a local problem. If you are looking at this code, then chances are that your program or another program on the same computer opened too many network connections. The "easy" fix: don't do that! */ gpr_log(GPR_ERROR, "kernel out of buffers"); grpc_fd_notify_on_write(ac->fd, &ac->write_closure); return; } else { switch (so_error) { case ECONNREFUSED: gpr_log(GPR_ERROR, "socket error: connection refused"); break; default: gpr_log(GPR_ERROR, "socket error: %d", so_error); break; } goto finish; } } else { ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE); goto finish; } } else { gpr_log(GPR_ERROR, "on_writable failed during connect"); goto finish; } abort(); finish: gpr_mu_lock(&ac->mu); if (!ep) { grpc_fd_orphan(ac->fd, NULL, NULL); } done = (--ac->refs == 0); gpr_mu_unlock(&ac->mu); if (done) { gpr_mu_destroy(&ac->mu); gpr_free(ac); } cb(cb_arg, ep); }
void grpc_alarm_destroy(grpc_alarm *alarm) { grpc_alarm_cancel(alarm); GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm"); gpr_free(alarm); }
void grpc_alarm_destroy(grpc_alarm *alarm, void *reserved) { grpc_alarm_cancel(alarm, reserved); GRPC_ALARM_UNREF(alarm, "alarm_destroy"); }
/* Test grpc_alarm add and cancel. */ static void test_grpc_alarm(void) { grpc_alarm alarm; grpc_alarm alarm_to_cancel; /* Timeout on the alarm cond. var, so make big enough to absorb time deviations. Otherwise, operations after wait will not be properly ordered */ gpr_timespec alarm_deadline; gpr_timespec followup_deadline; alarm_arg arg; alarm_arg arg2; void *fdone; grpc_iomgr_init(); arg.counter = 0; arg.success = SUCCESS_NOT_SET; arg.done_success_ctr = 0; arg.done_cancel_ctr = 0; arg.done = 0; gpr_mu_init(&arg.mu); gpr_cv_init(&arg.cv); gpr_event_init(&arg.fcb_arg); grpc_alarm_init(&alarm, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100), alarm_cb, &arg, gpr_now()); alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1); gpr_mu_lock(&arg.mu); while (arg.done == 0) { if (gpr_cv_wait(&arg.cv, &arg.mu, alarm_deadline)) { gpr_log(GPR_ERROR, "alarm deadline exceeded"); break; } } gpr_mu_unlock(&arg.mu); followup_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5); fdone = gpr_event_wait(&arg.fcb_arg, followup_deadline); if (arg.counter != 1) { gpr_log(GPR_ERROR, "Alarm callback not called"); GPR_ASSERT(0); } else if (arg.done_success_ctr != 1) { gpr_log(GPR_ERROR, "Alarm done callback not called with success"); GPR_ASSERT(0); } else if (arg.done_cancel_ctr != 0) { gpr_log(GPR_ERROR, "Alarm done callback called with cancel"); GPR_ASSERT(0); } else if (arg.success == SUCCESS_NOT_SET) { gpr_log(GPR_ERROR, "Alarm callback without status"); GPR_ASSERT(0); } else { gpr_log(GPR_INFO, "Alarm callback called successfully"); } if (fdone != (void *)&arg.fcb_arg) { gpr_log(GPR_ERROR, "Followup callback #1 not invoked properly %p %p", fdone, &arg.fcb_arg); GPR_ASSERT(0); } gpr_cv_destroy(&arg.cv); gpr_mu_destroy(&arg.mu); arg2.counter = 0; arg2.success = SUCCESS_NOT_SET; arg2.done_success_ctr = 0; arg2.done_cancel_ctr = 0; arg2.done = 0; gpr_mu_init(&arg2.mu); gpr_cv_init(&arg2.cv); gpr_event_init(&arg2.fcb_arg); grpc_alarm_init(&alarm_to_cancel, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100), alarm_cb, &arg2, gpr_now()); grpc_alarm_cancel(&alarm_to_cancel); alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1); gpr_mu_lock(&arg2.mu); while (arg2.done == 0) { gpr_cv_wait(&arg2.cv, &arg2.mu, alarm_deadline); } gpr_mu_unlock(&arg2.mu); gpr_log(GPR_INFO, "alarm done = %d", arg2.done); followup_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5); fdone = gpr_event_wait(&arg2.fcb_arg, followup_deadline); if (arg2.counter != arg2.done_success_ctr) { gpr_log(GPR_ERROR, "Alarm callback called but didn't lead to done success"); GPR_ASSERT(0); } else if (arg2.done_success_ctr && arg2.done_cancel_ctr) { gpr_log(GPR_ERROR, "Alarm done callback called with success and cancel"); GPR_ASSERT(0); } else if (arg2.done_cancel_ctr + arg2.done_success_ctr != 1) { gpr_log(GPR_ERROR, "Alarm done callback called incorrect number of times"); GPR_ASSERT(0); } else if (arg2.success == SUCCESS_NOT_SET) { gpr_log(GPR_ERROR, "Alarm callback without status"); GPR_ASSERT(0); } else if (arg2.done_success_ctr) { gpr_log(GPR_INFO, "Alarm callback executed before cancel"); gpr_log(GPR_INFO, "Current value of triggered is %d\n", alarm_to_cancel.triggered); } else if (arg2.done_cancel_ctr) { gpr_log(GPR_INFO, "Alarm callback canceled"); gpr_log(GPR_INFO, "Current value of triggered is %d\n", alarm_to_cancel.triggered); } else { gpr_log(GPR_ERROR, "Alarm cancel test should not be here"); GPR_ASSERT(0); } if (fdone != (void *)&arg2.fcb_arg) { gpr_log(GPR_ERROR, "Followup callback #2 not invoked properly %p %p", fdone, &arg2.fcb_arg); GPR_ASSERT(0); } gpr_cv_destroy(&arg2.cv); gpr_mu_destroy(&arg2.mu); grpc_iomgr_shutdown(); }