From 65582323ad6b934b4cbb3a4632bb4c985acc1bdc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 21 Apr 2015 09:24:41 -0700 Subject: [PATCH 01/58] Initial interface change --- src/core/transport/stream_op.h | 11 +----- src/core/transport/transport.h | 68 +++++++++------------------------- 2 files changed, 19 insertions(+), 60 deletions(-) diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index 20146b9af21..c3901bf6088 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -55,9 +55,7 @@ typedef enum grpc_stream_op_code { GRPC_OP_BEGIN_MESSAGE, /* Add a slice of data to the current message/metadata element/status. Must not overflow the forward declared length. */ - GRPC_OP_SLICE, - /* Call some function once this operation has passed flow control. */ - GRPC_OP_FLOW_CTL_CB + GRPC_OP_SLICE } grpc_stream_op_code; /* Arguments for GRPC_OP_BEGIN */ @@ -68,12 +66,6 @@ typedef struct grpc_begin_message { gpr_uint32 flags; } grpc_begin_message; -/* Arguments for GRPC_OP_FLOW_CTL_CB */ -typedef struct grpc_flow_ctl_cb { - void (*cb)(void *arg, grpc_op_error error); - void *arg; -} grpc_flow_ctl_cb; - typedef struct grpc_linked_mdelem { grpc_mdelem *md; struct grpc_linked_mdelem *next; @@ -129,7 +121,6 @@ typedef struct grpc_stream_op { grpc_begin_message begin_message; grpc_metadata_batch metadata; gpr_slice slice; - grpc_flow_ctl_cb flow_ctl_cb; } data; } grpc_stream_op; diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index ce8c17c3228..6dd0fdaf468 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -62,24 +62,6 @@ typedef enum grpc_stream_state { /* Callbacks made from the transport to the upper layers of grpc. */ struct grpc_transport_callbacks { - /* Allocate a buffer to receive data into. - It's safe to call grpc_slice_new() to do this, but performance minded - proxies may want to carefully place data into optimal locations for - transports. - This function must return a valid, non-empty slice. - - Arguments: - user_data - the transport user data set at transport creation time - transport - the grpc_transport instance making this call - stream - the grpc_stream instance the buffer will be used for, or - NULL if this is not known - size_hint - how big of a buffer would the transport optimally like? - the actual returned buffer can be smaller or larger than - size_hint as the implementation finds convenient */ - struct gpr_slice (*alloc_recv_buffer)(void *user_data, - grpc_transport *transport, - grpc_stream *stream, size_t size_hint); - /* Initialize a new stream on behalf of the transport. Must result in a call to grpc_transport_init_stream(transport, ..., request) in the same call @@ -96,31 +78,6 @@ struct grpc_transport_callbacks { void (*accept_stream)(void *user_data, grpc_transport *transport, const void *server_data); - /* Process a set of stream ops that have been received by the transport. - Called by network threads, so must be careful not to block on network - activity. - - If final_state == GRPC_STREAM_CLOSED, the upper layers should arrange to - call grpc_transport_destroy_stream. - - Ownership of any objects contained in ops is transferred to the callee. - - Arguments: - user_data - the transport user data set at transport creation time - transport - the grpc_transport instance making this call - stream - the stream this data was received for - ops - stream operations that are part of this batch - ops_count - the number of stream operations in this batch - final_state - the state of the stream as of the final operation in this - batch */ - void (*recv_batch)(void *user_data, grpc_transport *transport, - grpc_stream *stream, grpc_stream_op *ops, size_t ops_count, - grpc_stream_state final_state); - - /* The transport received a goaway */ - void (*goaway)(void *user_data, grpc_transport *transport, - grpc_status_code status, gpr_slice debug); - /* The transport has been closed */ void (*closed)(void *user_data, grpc_transport *transport); }; @@ -169,6 +126,21 @@ void grpc_transport_destroy_stream(grpc_transport *transport, void grpc_transport_set_allow_window_updates(grpc_transport *transport, grpc_stream *stream, int allow); +/* Transport op: a set of operations to perform on a transport */ +typedef struct grpc_transport_op { + grpc_stream_op_buffer *send_ops; + int is_last_send; + void (*on_done_send)(void *user_data, int success); + void *send_user_data; + + grpc_stream_op_buffer *recv_ops; + grpc_stream_state *recv_state; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; + + grpc_pollset *bind_pollset; +} grpc_transport_op; + /* Send a batch of operations on a transport Takes ownership of any objects contained in ops. @@ -177,13 +149,9 @@ void grpc_transport_set_allow_window_updates(grpc_transport *transport, transport - the transport on which to initiate the stream stream - the stream on which to send the operations. This must be non-NULL and previously initialized by the same transport. - ops - an array of operations to apply to the stream - can be NULL - if ops_count == 0. - ops_count - the number of elements in ops - is_last - is this the last batch of operations to be sent out */ -void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream, - grpc_stream_op *ops, size_t ops_count, - int is_last); + op - a grpc_transport_op specifying the op to perform */ +void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream, + grpc_transport_op *op); /* Send a ping on a transport From 83f88d90b9c61c94994ed00d03a6fa469359d559 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 21 Apr 2015 16:02:05 -0700 Subject: [PATCH 02/58] stuff --- BUILD | 8 +- Makefile | 15 +- build.json | 6 +- src/core/channel/census_filter.c | 70 ++--- src/core/channel/channel_stack.c | 44 +-- src/core/channel/channel_stack.h | 77 +----- src/core/channel/child_channel.c | 18 +- src/core/channel/client_channel.c | 93 +++---- src/core/channel/connected_channel.c | 261 +----------------- src/core/channel/http_client_filter.c | 72 +++-- src/core/channel/http_filter.c | 137 --------- src/core/channel/http_filter.h | 43 --- src/core/channel/http_server_filter.c | 116 ++++---- src/core/channel/noop_filter.c | 13 +- src/core/surface/call.c | 178 ++++++------ src/core/surface/call.h | 1 - src/core/transport/chttp2_transport.c | 4 +- src/core/transport/stream_op.h | 28 +- src/core/transport/transport.h | 21 +- src/core/transport/transport_op_string.c | 141 ++++++++++ vsprojects/vs2010/grpc.vcxproj | 7 +- vsprojects/vs2010/grpc.vcxproj.filters | 12 +- vsprojects/vs2010/grpc_unsecure.vcxproj | 7 +- .../vs2010/grpc_unsecure.vcxproj.filters | 12 +- vsprojects/vs2013/grpc.vcxproj | 7 +- vsprojects/vs2013/grpc.vcxproj.filters | 12 +- vsprojects/vs2013/grpc_unsecure.vcxproj | 7 +- .../vs2013/grpc_unsecure.vcxproj.filters | 12 +- 28 files changed, 490 insertions(+), 932 deletions(-) delete mode 100644 src/core/channel/http_filter.c delete mode 100644 src/core/channel/http_filter.h create mode 100644 src/core/transport/transport_op_string.c diff --git a/BUILD b/BUILD index a4649d5024e..97a85555115 100644 --- a/BUILD +++ b/BUILD @@ -145,7 +145,6 @@ cc_library( "src/core/channel/client_setup.h", "src/core/channel/connected_channel.h", "src/core/channel/http_client_filter.h", - "src/core/channel/http_filter.h", "src/core/channel/http_server_filter.h", "src/core/channel/noop_filter.h", "src/core/compression/algorithm.h", @@ -245,7 +244,6 @@ cc_library( "src/core/tsi/fake_transport_security.c", "src/core/tsi/ssl_transport_security.c", "src/core/tsi/transport_security.c", - "src/core/channel/call_op_string.c", "src/core/channel/census_filter.c", "src/core/channel/channel_args.c", "src/core/channel/channel_stack.c", @@ -254,7 +252,6 @@ cc_library( "src/core/channel/client_setup.c", "src/core/channel/connected_channel.c", "src/core/channel/http_client_filter.c", - "src/core/channel/http_filter.c", "src/core/channel/http_server_filter.c", "src/core/channel/noop_filter.c", "src/core/compression/algorithm.c", @@ -342,6 +339,7 @@ cc_library( "src/core/transport/metadata.c", "src/core/transport/stream_op.c", "src/core/transport/transport.c", + "src/core/transport/transport_op_string.c", ], hdrs = [ "include/grpc/grpc_security.h", @@ -373,7 +371,6 @@ cc_library( "src/core/channel/client_setup.h", "src/core/channel/connected_channel.h", "src/core/channel/http_client_filter.h", - "src/core/channel/http_filter.h", "src/core/channel/http_server_filter.h", "src/core/channel/noop_filter.h", "src/core/compression/algorithm.h", @@ -454,7 +451,6 @@ cc_library( "src/core/transport/transport.h", "src/core/transport/transport_impl.h", "src/core/surface/init_unsecure.c", - "src/core/channel/call_op_string.c", "src/core/channel/census_filter.c", "src/core/channel/channel_args.c", "src/core/channel/channel_stack.c", @@ -463,7 +459,6 @@ cc_library( "src/core/channel/client_setup.c", "src/core/channel/connected_channel.c", "src/core/channel/http_client_filter.c", - "src/core/channel/http_filter.c", "src/core/channel/http_server_filter.c", "src/core/channel/noop_filter.c", "src/core/compression/algorithm.c", @@ -551,6 +546,7 @@ cc_library( "src/core/transport/metadata.c", "src/core/transport/stream_op.c", "src/core/transport/transport.c", + "src/core/transport/transport_op_string.c", ], hdrs = [ "include/grpc/byte_buffer.h", diff --git a/Makefile b/Makefile index 218d68f733e..b09a63fef0c 100644 --- a/Makefile +++ b/Makefile @@ -2603,7 +2603,6 @@ LIBGRPC_SRC = \ src/core/tsi/fake_transport_security.c \ src/core/tsi/ssl_transport_security.c \ src/core/tsi/transport_security.c \ - src/core/channel/call_op_string.c \ src/core/channel/census_filter.c \ src/core/channel/channel_args.c \ src/core/channel/channel_stack.c \ @@ -2612,7 +2611,6 @@ LIBGRPC_SRC = \ src/core/channel/client_setup.c \ src/core/channel/connected_channel.c \ src/core/channel/http_client_filter.c \ - src/core/channel/http_filter.c \ src/core/channel/http_server_filter.c \ src/core/channel/noop_filter.c \ src/core/compression/algorithm.c \ @@ -2700,6 +2698,7 @@ LIBGRPC_SRC = \ src/core/transport/metadata.c \ src/core/transport/stream_op.c \ src/core/transport/transport.c \ + src/core/transport/transport_op_string.c \ PUBLIC_HEADERS_C += \ include/grpc/grpc_security.h \ @@ -2750,7 +2749,6 @@ src/core/surface/secure_channel_create.c: $(OPENSSL_DEP) src/core/tsi/fake_transport_security.c: $(OPENSSL_DEP) src/core/tsi/ssl_transport_security.c: $(OPENSSL_DEP) src/core/tsi/transport_security.c: $(OPENSSL_DEP) -src/core/channel/call_op_string.c: $(OPENSSL_DEP) src/core/channel/census_filter.c: $(OPENSSL_DEP) src/core/channel/channel_args.c: $(OPENSSL_DEP) src/core/channel/channel_stack.c: $(OPENSSL_DEP) @@ -2759,7 +2757,6 @@ src/core/channel/client_channel.c: $(OPENSSL_DEP) src/core/channel/client_setup.c: $(OPENSSL_DEP) src/core/channel/connected_channel.c: $(OPENSSL_DEP) src/core/channel/http_client_filter.c: $(OPENSSL_DEP) -src/core/channel/http_filter.c: $(OPENSSL_DEP) src/core/channel/http_server_filter.c: $(OPENSSL_DEP) src/core/channel/noop_filter.c: $(OPENSSL_DEP) src/core/compression/algorithm.c: $(OPENSSL_DEP) @@ -2847,6 +2844,7 @@ src/core/transport/chttp2_transport.c: $(OPENSSL_DEP) src/core/transport/metadata.c: $(OPENSSL_DEP) src/core/transport/stream_op.c: $(OPENSSL_DEP) src/core/transport/transport.c: $(OPENSSL_DEP) +src/core/transport/transport_op_string.c: $(OPENSSL_DEP) endif $(LIBDIR)/$(CONFIG)/libgrpc.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_OBJS) @@ -2913,7 +2911,6 @@ $(OBJDIR)/$(CONFIG)/src/core/surface/secure_channel_create.o: $(OBJDIR)/$(CONFIG)/src/core/tsi/fake_transport_security.o: $(OBJDIR)/$(CONFIG)/src/core/tsi/ssl_transport_security.o: $(OBJDIR)/$(CONFIG)/src/core/tsi/transport_security.o: -$(OBJDIR)/$(CONFIG)/src/core/channel/call_op_string.o: $(OBJDIR)/$(CONFIG)/src/core/channel/census_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/channel_args.o: $(OBJDIR)/$(CONFIG)/src/core/channel/channel_stack.o: @@ -2922,7 +2919,6 @@ $(OBJDIR)/$(CONFIG)/src/core/channel/client_channel.o: $(OBJDIR)/$(CONFIG)/src/core/channel/client_setup.o: $(OBJDIR)/$(CONFIG)/src/core/channel/connected_channel.o: $(OBJDIR)/$(CONFIG)/src/core/channel/http_client_filter.o: -$(OBJDIR)/$(CONFIG)/src/core/channel/http_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/http_server_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/noop_filter.o: $(OBJDIR)/$(CONFIG)/src/core/compression/algorithm.o: @@ -3010,6 +3006,7 @@ $(OBJDIR)/$(CONFIG)/src/core/transport/chttp2_transport.o: $(OBJDIR)/$(CONFIG)/src/core/transport/metadata.o: $(OBJDIR)/$(CONFIG)/src/core/transport/stream_op.o: $(OBJDIR)/$(CONFIG)/src/core/transport/transport.o: +$(OBJDIR)/$(CONFIG)/src/core/transport/transport_op_string.o: LIBGRPC_TEST_UTIL_SRC = \ @@ -3090,7 +3087,6 @@ $(OBJDIR)/$(CONFIG)/test/core/util/slice_splitter.o: LIBGRPC_UNSECURE_SRC = \ src/core/surface/init_unsecure.c \ - src/core/channel/call_op_string.c \ src/core/channel/census_filter.c \ src/core/channel/channel_args.c \ src/core/channel/channel_stack.c \ @@ -3099,7 +3095,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/channel/client_setup.c \ src/core/channel/connected_channel.c \ src/core/channel/http_client_filter.c \ - src/core/channel/http_filter.c \ src/core/channel/http_server_filter.c \ src/core/channel/noop_filter.c \ src/core/compression/algorithm.c \ @@ -3187,6 +3182,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/transport/metadata.c \ src/core/transport/stream_op.c \ src/core/transport/transport.c \ + src/core/transport/transport_op_string.c \ PUBLIC_HEADERS_C += \ include/grpc/byte_buffer.h \ @@ -3231,7 +3227,6 @@ ifneq ($(NO_DEPS),true) endif $(OBJDIR)/$(CONFIG)/src/core/surface/init_unsecure.o: -$(OBJDIR)/$(CONFIG)/src/core/channel/call_op_string.o: $(OBJDIR)/$(CONFIG)/src/core/channel/census_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/channel_args.o: $(OBJDIR)/$(CONFIG)/src/core/channel/channel_stack.o: @@ -3240,7 +3235,6 @@ $(OBJDIR)/$(CONFIG)/src/core/channel/client_channel.o: $(OBJDIR)/$(CONFIG)/src/core/channel/client_setup.o: $(OBJDIR)/$(CONFIG)/src/core/channel/connected_channel.o: $(OBJDIR)/$(CONFIG)/src/core/channel/http_client_filter.o: -$(OBJDIR)/$(CONFIG)/src/core/channel/http_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/http_server_filter.o: $(OBJDIR)/$(CONFIG)/src/core/channel/noop_filter.o: $(OBJDIR)/$(CONFIG)/src/core/compression/algorithm.o: @@ -3328,6 +3322,7 @@ $(OBJDIR)/$(CONFIG)/src/core/transport/chttp2_transport.o: $(OBJDIR)/$(CONFIG)/src/core/transport/metadata.o: $(OBJDIR)/$(CONFIG)/src/core/transport/stream_op.o: $(OBJDIR)/$(CONFIG)/src/core/transport/transport.o: +$(OBJDIR)/$(CONFIG)/src/core/transport/transport_op_string.o: LIBGRPC++_SRC = \ diff --git a/build.json b/build.json index 89cf8de3a62..43a81ecb7cb 100644 --- a/build.json +++ b/build.json @@ -96,7 +96,6 @@ "src/core/channel/client_setup.h", "src/core/channel/connected_channel.h", "src/core/channel/http_client_filter.h", - "src/core/channel/http_filter.h", "src/core/channel/http_server_filter.h", "src/core/channel/noop_filter.h", "src/core/compression/algorithm.h", @@ -178,7 +177,6 @@ "src/core/transport/transport_impl.h" ], "src": [ - "src/core/channel/call_op_string.c", "src/core/channel/census_filter.c", "src/core/channel/channel_args.c", "src/core/channel/channel_stack.c", @@ -187,7 +185,6 @@ "src/core/channel/client_setup.c", "src/core/channel/connected_channel.c", "src/core/channel/http_client_filter.c", - "src/core/channel/http_filter.c", "src/core/channel/http_server_filter.c", "src/core/channel/noop_filter.c", "src/core/compression/algorithm.c", @@ -274,7 +271,8 @@ "src/core/transport/chttp2_transport.c", "src/core/transport/metadata.c", "src/core/transport/stream_op.c", - "src/core/transport/transport.c" + "src/core/transport/transport.c", + "src/core/transport/transport_op_string.c" ] } ], diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c index 9c0c20af221..3e0fc39fc9a 100644 --- a/src/core/channel/census_filter.c +++ b/src/core/channel/census_filter.c @@ -49,6 +49,11 @@ typedef struct call_data { census_op_id op_id; census_rpc_stats stats; gpr_timespec start_ts; + + /* recv callback */ + grpc_stream_op_buffer *recv_ops; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; } call_data; typedef struct channel_data { @@ -60,55 +65,58 @@ static void init_rpc_stats(census_rpc_stats* stats) { stats->cnt = 1; } -static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld, +static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb, call_data* calld, channel_data* chand) { grpc_linked_mdelem* m; - for (m = op->data.metadata.list.head; m != NULL; m = m->next) { - if (m->md->key == chand->path_str) { - gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); - census_add_method_tag( - calld->op_id, (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + size_t i; + for (i = 0; i < sopb->nops; i++) { + grpc_stream_op * op = &sopb->ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + for (m = op->data.metadata.list.head; m != NULL; m = m->next) { + if (m->md->key == chand->path_str) { + gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + census_add_method_tag( + calld->op_id, (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + } } } } -static void client_call_op(grpc_call_element* elem, - grpc_call_element* from_elem, grpc_call_op* op) { +static void client_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; GPR_ASSERT(calld != NULL); GPR_ASSERT(chand != NULL); GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); - switch (op->type) { - case GRPC_SEND_METADATA: - extract_and_annotate_method_tag(op, calld, chand); - break; - case GRPC_RECV_FINISH: - /* Should we stop timing the rpc here? */ - break; - default: - break; + if (op->send_ops) { + extract_and_annotate_method_tag(op->send_ops, calld, chand); } - /* Always pass control up or down the stack depending on op->dir */ grpc_call_next_op(elem, op); } -static void server_call_op(grpc_call_element* elem, - grpc_call_element* from_elem, grpc_call_op* op) { +static void server_on_done_recv(void *ptr, int success) { + grpc_call_element *elem = ptr; + call_data* calld = elem->call_data; + channel_data* chand = elem->channel_data; + if (success) { + extract_and_annotate_method_tag(calld->recv_ops, calld, chand); + } + calld->on_done_recv(calld->recv_user_data, success); +} + +static void server_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; GPR_ASSERT(calld != NULL); GPR_ASSERT(chand != NULL); GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); - switch (op->type) { - case GRPC_RECV_METADATA: - extract_and_annotate_method_tag(op, calld, chand); - break; - case GRPC_SEND_FINISH: - /* Should we stop timing the rpc here? */ - break; - default: - break; + if (op->recv_ops) { + /* substitute our callback for the op callback */ + calld->recv_ops = op->recv_ops; + calld->on_done_recv = op->on_done_recv; + calld->recv_user_data = op->recv_user_data; + op->on_done_recv = server_on_done_recv; + op->recv_user_data = elem; } /* Always pass control up or down the stack depending on op->dir */ grpc_call_next_op(elem, op); @@ -180,11 +188,11 @@ static void destroy_channel_elem(grpc_channel_element* elem) { } const grpc_channel_filter grpc_client_census_filter = { - client_call_op, channel_op, sizeof(call_data), client_init_call_elem, + client_start_transport_op, channel_op, sizeof(call_data), client_init_call_elem, client_destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "census-client"}; const grpc_channel_filter grpc_server_census_filter = { - server_call_op, channel_op, sizeof(call_data), server_init_call_elem, + server_start_transport_op, channel_op, sizeof(call_data), server_init_call_elem, server_destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "census-server"}; diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index 3a3a3a75b70..c121e270056 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -35,6 +35,7 @@ #include #include +#include int grpc_trace_channel = 0; @@ -181,12 +182,9 @@ void grpc_call_stack_destroy(grpc_call_stack *stack) { } } -void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) { - grpc_call_element *next_elem = elem + op->dir; - if (op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA) { - grpc_metadata_batch_assert_ok(&op->data.metadata); - } - next_elem->filter->call_op(next_elem, elem, op); +void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op) { + grpc_call_element *next_elem = elem + 1; + next_elem->filter->start_transport_op(next_elem, op); } void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) { @@ -205,39 +203,15 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { sizeof(grpc_call_stack))); } -static void do_nothing(void *user_data, grpc_op_error error) {} - void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { - grpc_call_op cancel_op; - cancel_op.type = GRPC_CANCEL_OP; - cancel_op.dir = GRPC_CALL_DOWN; - cancel_op.done_cb = do_nothing; - cancel_op.user_data = NULL; - cancel_op.flags = 0; - cancel_op.bind_pollset = NULL; - grpc_call_next_op(cur_elem, &cancel_op); -} - -void grpc_call_element_send_finish(grpc_call_element *cur_elem) { - grpc_call_op finish_op; - finish_op.type = GRPC_SEND_FINISH; - finish_op.dir = GRPC_CALL_DOWN; - finish_op.done_cb = do_nothing; - finish_op.user_data = NULL; - finish_op.flags = 0; - finish_op.bind_pollset = NULL; - grpc_call_next_op(cur_elem, &finish_op); + grpc_transport_op op; + memset(&op, 0, sizeof(op)); + op.cancel_with_status = GRPC_STATUS_CANCELLED; + grpc_call_next_op(cur_elem, &op); } void grpc_call_element_recv_status(grpc_call_element *cur_elem, grpc_status_code status, const char *message) { - grpc_call_op op; - op.type = GRPC_RECV_SYNTHETIC_STATUS; - op.dir = GRPC_CALL_UP; - op.done_cb = do_nothing; - op.user_data = NULL; - op.data.synthetic_status.status = status; - op.data.synthetic_status.message = message; - grpc_call_next_op(cur_elem, &op); + abort(); } diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index addc92b2727..75897ff6516 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -51,78 +51,11 @@ typedef struct grpc_channel_element grpc_channel_element; typedef struct grpc_call_element grpc_call_element; -/* Call operations - things that can be sent and received. - - Threading: - SEND, RECV, and CANCEL ops can be active on a call at the same time, but - only one SEND, one RECV, and one CANCEL can be active at a time. - - If state is shared between send/receive/cancel operations, it is up to - filters to provide their own protection around that. */ -typedef enum { - /* send metadata to the channels peer */ - GRPC_SEND_METADATA, - /* send a message to the channels peer */ - GRPC_SEND_MESSAGE, - /* send a pre-formatted message to the channels peer */ - GRPC_SEND_PREFORMATTED_MESSAGE, - /* send half-close to the channels peer */ - GRPC_SEND_FINISH, - /* request that more data be allowed through flow control */ - GRPC_REQUEST_DATA, - /* metadata was received from the channels peer */ - GRPC_RECV_METADATA, - /* a message was received from the channels peer */ - GRPC_RECV_MESSAGE, - /* half-close was received from the channels peer */ - GRPC_RECV_HALF_CLOSE, - /* full close was received from the channels peer */ - GRPC_RECV_FINISH, - /* a status has been sythesized locally */ - GRPC_RECV_SYNTHETIC_STATUS, - /* the call has been abnormally terminated */ - GRPC_CANCEL_OP -} grpc_call_op_type; - /* The direction of the call. The values of the enums (1, -1) matter here - they are used to increment or decrement a pointer to find the next element to call */ typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir; -/* A single filterable operation to be performed on a call */ -typedef struct { - /* The type of operation we're performing */ - grpc_call_op_type type; - /* The directionality of this call - does the operation begin at the bottom - of the stack and flow up, or does the operation start at the top of the - stack and flow down through the filters. */ - grpc_call_dir dir; - - /* Flags associated with this call: see GRPC_WRITE_* in grpc.h */ - gpr_uint32 flags; - - /* Argument data, matching up with grpc_call_op_type names */ - union { - grpc_byte_buffer *message; - grpc_metadata_batch metadata; - struct { - grpc_status_code status; - const char *message; - } synthetic_status; - } data; - - grpc_pollset *bind_pollset; - - /* Must be called when processing of this call-op is complete. - Signature chosen to match transport flow control callbacks */ - void (*done_cb)(void *user_data, grpc_op_error error); - /* User data to be passed into done_cb */ - void *user_data; -} grpc_call_op; - -/* returns a string representation of op, that can be destroyed with gpr_free */ -char *grpc_call_op_string(grpc_call_op *op); - typedef enum { /* send a goaway message to remote channels indicating that we are going to disconnect in the future */ @@ -170,8 +103,7 @@ typedef struct { typedef struct { /* Called to eg. send/receive data on a call. See grpc_call_next_op on how to call the next element in the stack */ - void (*call_op)(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op); + void (*start_transport_op)(grpc_call_element *elem, grpc_transport_op *op); /* Called to handle channel level operations - e.g. new calls, or transport closure. See grpc_channel_next_op on how to call the next element in the stack */ @@ -272,8 +204,8 @@ void grpc_call_stack_init(grpc_channel_stack *channel_stack, /* Destroy a call stack */ void grpc_call_stack_destroy(grpc_call_stack *stack); -/* Call the next operation (depending on call directionality) in a call stack */ -void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op); +/* Call the next operation in a call stack */ +void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op); /* Call the next operation (depending on call directionality) in a channel stack */ void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op); @@ -285,10 +217,9 @@ grpc_channel_stack *grpc_channel_stack_from_top_element( grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem); void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_call_op *op); + grpc_call_element *elem, grpc_transport_op *op); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); -void grpc_call_element_send_finish(grpc_call_element *cur_elem); void grpc_call_element_recv_status(grpc_call_element *cur_elem, grpc_status_code status, const char *message); diff --git a/src/core/channel/child_channel.c b/src/core/channel/child_channel.c index 2cb03829c79..244417384a7 100644 --- a/src/core/channel/child_channel.c +++ b/src/core/channel/child_channel.c @@ -61,22 +61,11 @@ typedef struct { } lb_channel_data; typedef struct { - grpc_call_element *back; grpc_child_channel *channel; } lb_call_data; -static void lb_call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { - lb_call_data *calld = elem->call_data; - - switch (op->dir) { - case GRPC_CALL_UP: - calld->back->filter->call_op(calld->back, elem, op); - break; - case GRPC_CALL_DOWN: - grpc_call_next_op(elem, op); - break; - } +static void lb_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + grpc_call_next_op(elem, op); } /* Currently we assume all channel operations should just be pushed up. */ @@ -165,7 +154,7 @@ static void lb_destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_child_channel_top_filter = { - lb_call_op, lb_channel_op, sizeof(lb_call_data), + lb_start_transport_op, lb_channel_op, sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem, "child-channel", }; @@ -282,7 +271,6 @@ grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, lbelem = LINK_BACK_ELEM_FROM_CALL(stk); lbchand = lbelem->channel_data; lbcalld = lbelem->call_data; - lbcalld->back = parent; lbcalld->channel = channel; gpr_mu_lock(&lbchand->mu); diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index bc481e59ca5..6ad50cb9448 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -82,7 +82,7 @@ struct call_data { /* owning element */ grpc_call_element *elem; - gpr_uint8 got_first_send; + gpr_uint8 got_first_op; call_state state; gpr_timespec deadline; @@ -91,7 +91,7 @@ struct call_data { /* our child call stack */ grpc_child_call *child_call; } active; - grpc_call_op waiting_op; + grpc_transport_op waiting_op; } s; }; @@ -110,9 +110,7 @@ static int prepare_activate(grpc_call_element *elem, return 1; } -static void do_nothing(void *ignored, grpc_op_error error) {} - -static void complete_activate(grpc_call_element *elem, grpc_call_op *op) { +static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; grpc_call_element *child_elem = grpc_child_call_get_top_element(calld->s.active.child_call); @@ -121,17 +119,16 @@ static void complete_activate(grpc_call_element *elem, grpc_call_op *op) { /* continue the start call down the stack, this nees to happen after metadata are flushed*/ - child_elem->filter->call_op(child_elem, elem, op); + child_elem->filter->start_transport_op(child_elem, op); } -static void start_rpc(grpc_call_element *elem, grpc_call_op *op) { +static void start_rpc(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; gpr_mu_lock(&chand->mu); if (calld->state == CALL_CANCELLED) { gpr_mu_unlock(&chand->mu); - grpc_metadata_batch_destroy(&op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_ERROR); + grpc_transport_op_finish_with_failure(op); return; } GPR_ASSERT(calld->state == CALL_CREATED); @@ -187,19 +184,10 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) { } static void send_up_cancelled_ops(grpc_call_element *elem) { - grpc_call_op finish_op; - /* send up a synthesized status */ - grpc_call_element_recv_status(elem, GRPC_STATUS_CANCELLED, "Cancelled"); - /* send up a finish */ - finish_op.type = GRPC_RECV_FINISH; - finish_op.dir = GRPC_CALL_UP; - finish_op.flags = 0; - finish_op.done_cb = do_nothing; - finish_op.user_data = NULL; - grpc_call_next_op(elem, &finish_op); + abort(); } -static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) { +static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_call_element *child_elem; @@ -209,15 +197,13 @@ static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) { case CALL_ACTIVE: child_elem = grpc_child_call_get_top_element(calld->s.active.child_call); gpr_mu_unlock(&chand->mu); - child_elem->filter->call_op(child_elem, elem, op); + child_elem->filter->start_transport_op(child_elem, op); return; /* early out */ case CALL_WAITING: - grpc_metadata_batch_destroy(&calld->s.waiting_op.data.metadata); remove_waiting_child(chand, calld); calld->state = CALL_CANCELLED; gpr_mu_unlock(&chand->mu); send_up_cancelled_ops(elem); - calld->s.waiting_op.done_cb(calld->s.waiting_op.user_data, GRPC_OP_ERROR); return; /* early out */ case CALL_CREATED: calld->state = CALL_CANCELLED; @@ -232,40 +218,27 @@ static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) { abort(); } -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void cc_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { call_data *calld = elem->call_data; GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - switch (op->type) { - case GRPC_SEND_METADATA: - if (!calld->got_first_send) { - /* filter out the start event to find which child to send on */ - calld->got_first_send = 1; - start_rpc(elem, op); - } else { - grpc_call_next_op(elem, op); - } - break; - case GRPC_CANCEL_OP: - cancel_rpc(elem, op); - break; - case GRPC_SEND_MESSAGE: - case GRPC_SEND_FINISH: - case GRPC_REQUEST_DATA: - if (calld->state == CALL_ACTIVE) { - grpc_call_element *child_elem = - grpc_child_call_get_top_element(calld->s.active.child_call); - child_elem->filter->call_op(child_elem, elem, op); - } else { - op->done_cb(op->user_data, GRPC_OP_ERROR); - } - break; - default: - GPR_ASSERT(op->dir == GRPC_CALL_UP); - grpc_call_next_op(elem, op); - break; + if (op->cancel_with_status != GRPC_STATUS_OK) { + GPR_ASSERT(op->send_ops == NULL); + GPR_ASSERT(op->recv_ops == NULL); + + cancel_rpc(elem, op); + return; + } + + if (!calld->got_first_op) { + calld->got_first_op = 1; + start_rpc(elem, op); + } else { + grpc_call_element *child_elem = + grpc_child_call_get_top_element(calld->s.active.child_call); + child_elem->filter->start_transport_op(child_elem, op); } } @@ -359,7 +332,7 @@ static void init_call_elem(grpc_call_element *elem, calld->elem = elem; calld->state = CALL_CREATED; calld->deadline = gpr_inf_future; - calld->got_first_send = 0; + calld->got_first_op = 0; } /* Destructor for call_data */ @@ -372,9 +345,7 @@ static void destroy_call_elem(grpc_call_element *elem) { if (calld->state == CALL_ACTIVE) { grpc_child_call_destroy(calld->s.active.child_call); } - if (calld->state == CALL_WAITING) { - grpc_metadata_batch_destroy(&calld->s.waiting_op.data.metadata); - } + GPR_ASSERT(calld->state != CALL_WAITING); } /* Constructor for channel_data */ @@ -417,7 +388,7 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_client_channel_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "client-channel", }; @@ -436,7 +407,7 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete( call_data **waiting_children; size_t waiting_child_count; size_t i; - grpc_call_op *call_ops; + grpc_transport_op *call_ops; /* build the child filter stack */ child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters); @@ -472,13 +443,13 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete( chand->waiting_child_count = 0; chand->waiting_child_capacity = 0; - call_ops = gpr_malloc(sizeof(grpc_call_op) * waiting_child_count); + call_ops = gpr_malloc(sizeof(*call_ops) * waiting_child_count); for (i = 0; i < waiting_child_count; i++) { call_ops[i] = waiting_children[i]->s.waiting_op; if (!prepare_activate(waiting_children[i]->elem, chand->active_child)) { waiting_children[i] = NULL; - call_ops[i].done_cb(call_ops[i].user_data, GRPC_OP_ERROR); + grpc_transport_op_finish_with_failure(&call_ops[i]); } } diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 711274bfe1b..d0b834a10a1 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -50,19 +50,10 @@ typedef struct connected_channel_channel_data { grpc_transport *transport; - gpr_uint32 max_message_length; } channel_data; typedef struct connected_channel_call_data { - grpc_call_element *elem; - grpc_stream_op_buffer outgoing_sopb; - - gpr_uint32 max_message_length; - gpr_uint32 incoming_message_length; - gpr_uint8 reading_message; - gpr_uint8 got_read_close; - gpr_slice_buffer incoming_message; - gpr_uint32 outgoing_buffer_length_estimate; + void *unused; } call_data; /* We perform a small hack to locate transport data alongside the connected @@ -72,6 +63,7 @@ typedef struct connected_channel_call_data { #define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \ (((call_data *)(transport_stream)) - 1) +#if 0 /* Copy the contents of a byte buffer into stream ops */ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, grpc_stream_op_buffer *sopb) { @@ -87,76 +79,17 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, break; } } - -/* Flush queued stream operations onto the transport */ -static void end_bufferable_op(grpc_call_op *op, channel_data *chand, - call_data *calld, int is_last) { - size_t nops; - - if (op->flags & GRPC_WRITE_BUFFER_HINT) { - if (calld->outgoing_buffer_length_estimate < MAX_BUFFER_LENGTH) { - op->done_cb(op->user_data, GRPC_OP_OK); - return; - } - } - - calld->outgoing_buffer_length_estimate = 0; - grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, op->user_data); - - nops = calld->outgoing_sopb.nops; - calld->outgoing_sopb.nops = 0; - grpc_transport_send_batch(chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld), - calld->outgoing_sopb.ops, nops, is_last); -} +#endif /* Intercept a call operation and either push it directly up or translate it into transport stream operations */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void con_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - if (op->bind_pollset) { - grpc_transport_add_to_pollset(chand->transport, op->bind_pollset); - } - - switch (op->type) { - case GRPC_SEND_METADATA: - grpc_sopb_add_metadata(&calld->outgoing_sopb, op->data.metadata); - end_bufferable_op(op, chand, calld, 0); - break; - case GRPC_SEND_MESSAGE: - grpc_sopb_add_begin_message(&calld->outgoing_sopb, - grpc_byte_buffer_length(op->data.message), - op->flags); - /* fall-through */ - case GRPC_SEND_PREFORMATTED_MESSAGE: - copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb); - calld->outgoing_buffer_length_estimate += - (5 + grpc_byte_buffer_length(op->data.message)); - end_bufferable_op(op, chand, calld, 0); - break; - case GRPC_SEND_FINISH: - end_bufferable_op(op, chand, calld, 1); - break; - case GRPC_REQUEST_DATA: - /* re-arm window updates if they were disarmed by finish_message */ - grpc_transport_set_allow_window_updates( - chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 1); - break; - case GRPC_CANCEL_OP: - grpc_transport_abort_stream(chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld), - GRPC_STATUS_CANCELLED); - break; - default: - GPR_ASSERT(op->dir == GRPC_CALL_UP); - grpc_call_next_op(elem, op); - break; - } + grpc_transport_perform_op(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); } /* Currently we assume all channel operations should just be pushed up. */ @@ -188,14 +121,6 @@ static void init_call_elem(grpc_call_element *elem, int r; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); - calld->elem = elem; - grpc_sopb_init(&calld->outgoing_sopb); - - calld->reading_message = 0; - calld->got_read_close = 0; - calld->outgoing_buffer_length_estimate = 0; - calld->max_message_length = chand->max_message_length; - gpr_slice_buffer_init(&calld->incoming_message); r = grpc_transport_init_stream(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), server_transport_data); @@ -207,8 +132,6 @@ static void destroy_call_elem(grpc_call_element *elem) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); - grpc_sopb_destroy(&calld->outgoing_sopb); - gpr_slice_buffer_destroy(&calld->incoming_message); grpc_transport_destroy_stream(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld)); } @@ -218,12 +141,12 @@ static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { channel_data *cd = (channel_data *)elem->channel_data; - size_t i; GPR_ASSERT(!is_first); GPR_ASSERT(is_last); GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); cd->transport = NULL; +#if 0 cd->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; if (args) { for (i = 0; i < args->num_args; i++) { @@ -240,6 +163,7 @@ static void init_channel_elem(grpc_channel_element *elem, } } } +#endif } /* Destructor for channel_data */ @@ -250,15 +174,10 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_connected_channel_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + con_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "connected", }; -static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport, - grpc_stream *stream, size_t size_hint) { - return gpr_slice_malloc(size_hint); -} - /* Transport callback to accept a new stream... calls up to handle it */ static void accept_stream(void *user_data, grpc_transport *transport, const void *transport_server_data) { @@ -276,168 +195,6 @@ static void accept_stream(void *user_data, grpc_transport *transport, channel_op(elem, NULL, &op); } -static void recv_error(channel_data *chand, call_data *calld, int line, - const char *message) { - gpr_log_message(__FILE__, line, GPR_LOG_SEVERITY_ERROR, message); - - if (chand->transport) { - grpc_transport_abort_stream(chand->transport, - TRANSPORT_STREAM_FROM_CALL_DATA(calld), - GRPC_STATUS_INVALID_ARGUMENT); - } -} - -static void do_nothing(void *calldata, grpc_op_error error) {} - -static void finish_message(channel_data *chand, call_data *calld) { - grpc_call_element *elem = calld->elem; - grpc_call_op call_op; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - /* if we got all the bytes for this message, call up the stack */ - call_op.type = GRPC_RECV_MESSAGE; - call_op.done_cb = do_nothing; - /* TODO(ctiller): this could be a lot faster if coded directly */ - call_op.data.message = grpc_byte_buffer_create(calld->incoming_message.slices, - calld->incoming_message.count); - gpr_slice_buffer_reset_and_unref(&calld->incoming_message); - - /* disable window updates until we get a request more from above */ - grpc_transport_set_allow_window_updates( - chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 0); - - GPR_ASSERT(calld->incoming_message.count == 0); - calld->reading_message = 0; - grpc_call_next_op(elem, &call_op); -} - -static void got_metadata(grpc_call_element *elem, - grpc_metadata_batch metadata) { - grpc_call_op op; - op.type = GRPC_RECV_METADATA; - op.dir = GRPC_CALL_UP; - op.flags = 0; - op.data.metadata = metadata; - op.done_cb = do_nothing; - op.user_data = NULL; - - grpc_call_next_op(elem, &op); -} - -/* Handle incoming stream ops from the transport, translating them into - call_ops to pass up the call stack */ -static void recv_batch(void *user_data, grpc_transport *transport, - grpc_stream *stream, grpc_stream_op *ops, - size_t ops_count, grpc_stream_state final_state) { - call_data *calld = CALL_DATA_FROM_TRANSPORT_STREAM(stream); - grpc_call_element *elem = calld->elem; - channel_data *chand = elem->channel_data; - grpc_stream_op *stream_op; - grpc_call_op call_op; - size_t i; - gpr_uint32 length; - - GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); - - for (i = 0; i < ops_count; i++) { - stream_op = ops + i; - switch (stream_op->type) { - case GRPC_OP_FLOW_CTL_CB: - stream_op->data.flow_ctl_cb.cb(stream_op->data.flow_ctl_cb.arg, 1); - break; - case GRPC_NO_OP: - break; - case GRPC_OP_METADATA: - got_metadata(elem, stream_op->data.metadata); - break; - case GRPC_OP_BEGIN_MESSAGE: - /* can't begin a message when we're still reading a message */ - if (calld->reading_message) { - char *message = NULL; - gpr_asprintf(&message, - "Message terminated early; read %d bytes, expected %d", - (int)calld->incoming_message.length, - (int)calld->incoming_message_length); - recv_error(chand, calld, __LINE__, message); - gpr_free(message); - return; - } - /* stash away parameters, and prepare for incoming slices */ - length = stream_op->data.begin_message.length; - if (length > calld->max_message_length) { - char *message = NULL; - gpr_asprintf( - &message, - "Maximum message length of %d exceeded by a message of length %d", - calld->max_message_length, length); - recv_error(chand, calld, __LINE__, message); - gpr_free(message); - } else if (length > 0) { - calld->reading_message = 1; - calld->incoming_message_length = length; - } else { - finish_message(chand, calld); - } - break; - case GRPC_OP_SLICE: - if (GPR_SLICE_LENGTH(stream_op->data.slice) == 0) { - gpr_slice_unref(stream_op->data.slice); - break; - } - /* we have to be reading a message to know what to do here */ - if (!calld->reading_message) { - recv_error(chand, calld, __LINE__, - "Received payload data while not reading a message"); - return; - } - /* append the slice to the incoming buffer */ - gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice); - if (calld->incoming_message.length > calld->incoming_message_length) { - /* if we got too many bytes, complain */ - char *message = NULL; - gpr_asprintf(&message, - "Receiving message overflow; read %d bytes, expected %d", - (int)calld->incoming_message.length, - (int)calld->incoming_message_length); - recv_error(chand, calld, __LINE__, message); - gpr_free(message); - return; - } else if (calld->incoming_message.length == - calld->incoming_message_length) { - finish_message(chand, calld); - } - } - } - /* if the stream closed, then call up the stack to let it know */ - if (!calld->got_read_close && (final_state == GRPC_STREAM_RECV_CLOSED || - final_state == GRPC_STREAM_CLOSED)) { - calld->got_read_close = 1; - if (calld->reading_message) { - char *message = NULL; - gpr_asprintf(&message, - "Last message truncated; read %d bytes, expected %d", - (int)calld->incoming_message.length, - (int)calld->incoming_message_length); - recv_error(chand, calld, __LINE__, message); - gpr_free(message); - } - call_op.type = GRPC_RECV_HALF_CLOSE; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - call_op.done_cb = do_nothing; - call_op.user_data = NULL; - grpc_call_next_op(elem, &call_op); - } - if (final_state == GRPC_STREAM_CLOSED) { - call_op.type = GRPC_RECV_FINISH; - call_op.dir = GRPC_CALL_UP; - call_op.flags = 0; - call_op.done_cb = do_nothing; - call_op.user_data = NULL; - grpc_call_next_op(elem, &call_op); - } -} - static void transport_goaway(void *user_data, grpc_transport *transport, grpc_status_code status, gpr_slice debug) { /* transport got goaway ==> call up and handle it */ @@ -470,7 +227,7 @@ static void transport_closed(void *user_data, grpc_transport *transport) { } const grpc_transport_callbacks connected_channel_transport_callbacks = { - alloc_recv_buffer, accept_stream, recv_batch, + accept_stream, transport_goaway, transport_closed, }; diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index bc014b15fff..fb2ce4d34ad 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -39,6 +39,12 @@ typedef struct call_data { grpc_linked_mdelem scheme; grpc_linked_mdelem te_trailers; grpc_linked_mdelem content_type; + int sent_initial_metadata; + + int got_initial_metadata; + grpc_stream_op_buffer *recv_ops; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; } call_data; typedef struct channel_data { @@ -64,22 +70,39 @@ static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) { return md; } -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void hc_on_recv(void *user_data, int success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (success) { + size_t i; + size_t nops = calld->recv_ops->nops; + grpc_stream_op *ops = calld->recv_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->got_initial_metadata = 1; + grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem); + } + } + calld->on_done_recv(calld->recv_user_data, success); +} + +static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; + size_t i; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - switch (op->type) { - case GRPC_SEND_METADATA: + if (op->send_ops && !calld->sent_initial_metadata) { + size_t nops = op->send_ops->nops; + grpc_stream_op *ops = op->send_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->sent_initial_metadata = 1; /* Send : prefixed headers, which have to be before any application - * layer headers. */ + layer headers. */ grpc_metadata_batch_add_head(&op->data.metadata, &calld->method, grpc_mdelem_ref(channeld->method)); grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme, @@ -88,17 +111,20 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_mdelem_ref(channeld->te_trailers)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type, grpc_mdelem_ref(channeld->content_type)); - grpc_call_next_op(elem, op); - break; - case GRPC_RECV_METADATA: - grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem); - grpc_call_next_op(elem, op); - break; - default: - /* pass control up or down the stack depending on op->dir */ - grpc_call_next_op(elem, op); break; + } } + + if (op->recv_ops && !calld->got_initial_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_ops = op->recv_ops; + calld->on_done_recv = op->on_done_recv; + calld->recv_user_data = op->recv_user_data; + op->on_done_recv = hc_on_recv; + op->recv_user_data = elem; + } + + grpc_call_next_op(elem, op); } /* Called on special channel events, such as disconnection or new incoming @@ -120,7 +146,11 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) {} + const void *server_transport_data) { + call_data *calld = elem->call_data; + calld->sent_initial_metadata = 0; + calld->got_initial_metadata = 0; +} /* Destructor for call_data */ static void destroy_call_elem(grpc_call_element *elem) { @@ -181,6 +211,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_client_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "http-client"}; diff --git a/src/core/channel/http_filter.c b/src/core/channel/http_filter.c deleted file mode 100644 index 453a0422d85..00000000000 --- a/src/core/channel/http_filter.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Copyright 2015, 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. - * - */ - -#include "src/core/channel/http_filter.h" -#include - -typedef struct call_data { - int unused; /* C89 requires at least one struct element */ -} call_data; - -typedef struct channel_data { - int unused; /* C89 requires at least one struct element */ -} channel_data; - -/* used to silence 'variable not used' warnings */ -static void ignore_unused(void *ignored) {} - -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - - ignore_unused(calld); - ignore_unused(channeld); - - switch (op->type) { - default: - /* pass control up or down the stack depending on op->dir */ - grpc_call_next_op(elem, op); - break; - } -} - -/* Called on special channel events, such as disconnection or new incoming - calls on the server */ -static void channel_op(grpc_channel_element *elem, - grpc_channel_element *from_elem, grpc_channel_op *op) { - /* grab pointers to our data from the channel element */ - channel_data *channeld = elem->channel_data; - - ignore_unused(channeld); - - switch (op->type) { - default: - /* pass control up or down the stack depending on op->dir */ - grpc_channel_next_op(elem, op); - break; - } -} - -/* Constructor for call_data */ -static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - /* initialize members */ - calld->unused = channeld->unused; -} - -/* Destructor for call_data */ -static void destroy_call_elem(grpc_call_element *elem) { - /* grab pointers to our data from the call element */ - call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - ignore_unused(calld); - ignore_unused(channeld); -} - -/* Constructor for channel_data */ -static void init_channel_elem(grpc_channel_element *elem, - const grpc_channel_args *args, grpc_mdctx *mdctx, - int is_first, int is_last) { - /* grab pointers to our data from the channel element */ - channel_data *channeld = elem->channel_data; - - /* The first and the last filters tend to be implemented differently to - handle the case that there's no 'next' filter to call on the up or down - path */ - GPR_ASSERT(!is_first); - GPR_ASSERT(!is_last); - - /* initialize members */ - channeld->unused = 0; -} - -/* Destructor for channel data */ -static void destroy_channel_elem(grpc_channel_element *elem) { - /* grab pointers to our data from the channel element */ - channel_data *channeld = elem->channel_data; - - ignore_unused(channeld); -} - -const grpc_channel_filter grpc_http_filter = { - call_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "http"}; diff --git a/src/core/channel/http_filter.h b/src/core/channel/http_filter.h deleted file mode 100644 index 1b116ad61f4..00000000000 --- a/src/core/channel/http_filter.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * - * Copyright 2015, 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. - * - */ - -#ifndef GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H -#define GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H - -#include "src/core/channel/channel_stack.h" - -/* Processes metadata that is common to both client and server for HTTP2 - transports. */ -extern const grpc_channel_filter grpc_http_filter; - -#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H */ diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 85224f28e5b..d18c38d93c8 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -52,6 +52,10 @@ typedef struct call_data { gpr_uint8 seen_scheme; gpr_uint8 seen_te_trailers; grpc_linked_mdelem status; + + grpc_stream_op_buffer *recv_ops; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; } call_data; typedef struct channel_data { @@ -143,63 +147,73 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { } } -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void hs_on_recv(void *user_data, int success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + if (success) { + size_t i; + size_t nops = calld->recv_ops->nops; + grpc_stream_op *ops = calld->recv_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->got_initial_metadata = 1; + grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); + /* Have we seen the required http2 transport headers? + (:method, :scheme, content-type, with :path and :authority covered + at the channel level right now) */ + if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && + calld->seen_path) { + /* do nothing */ + } else { + if (!calld->seen_post) { + gpr_log(GPR_ERROR, "Missing :method header"); + } + if (!calld->seen_scheme) { + gpr_log(GPR_ERROR, "Missing :scheme header"); + } + if (!calld->seen_te_trailers) { + gpr_log(GPR_ERROR, "Missing te trailers header"); + } + /* Error this call out */ + success = 0; + grpc_call_element_send_cancel(elem); + } + } + } + calld->on_done_recv(calld->recv_user_data, success); +} + +static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; + size_t i; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - switch (op->type) { - case GRPC_RECV_METADATA: - grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); - if (!calld->got_initial_metadata) { - calld->got_initial_metadata = 1; - /* Have we seen the required http2 transport headers? - (:method, :scheme, content-type, with :path and :authority covered - at the channel level right now) */ - if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers && - calld->seen_path) { - grpc_call_next_op(elem, op); - } else { - if (!calld->seen_post) { - gpr_log(GPR_ERROR, "Missing :method header"); - } - if (!calld->seen_scheme) { - gpr_log(GPR_ERROR, "Missing :scheme header"); - } - if (!calld->seen_te_trailers) { - gpr_log(GPR_ERROR, "Missing te trailers header"); - } - /* Error this call out */ - grpc_metadata_batch_destroy(&op->data.metadata); - op->done_cb(op->user_data, GRPC_OP_OK); - grpc_call_element_send_cancel(elem); - } - } else { - grpc_call_next_op(elem, op); - } - break; - case GRPC_SEND_METADATA: - /* If we haven't sent status 200 yet, we need to so so because it needs to - come before any non : prefixed metadata. */ - if (!calld->sent_status) { - calld->sent_status = 1; - grpc_metadata_batch_add_head(&op->data.metadata, &calld->status, - grpc_mdelem_ref(channeld->status_ok)); - } - grpc_call_next_op(elem, op); - break; - default: - /* pass control up or down the stack depending on op->dir */ - grpc_call_next_op(elem, op); + if (op->send_ops && !calld->sent_status) { + size_t nops = op->send_ops->nops; + grpc_stream_op *ops = op->send_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + calld->sent_status = 1; + grpc_metadata_batch_add_head(&op->data.metadata, &calld->status, + grpc_mdelem_ref(channeld->status_ok)); break; + } } + + if (op->recv_ops && !calld->got_initial_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_ops = op->recv_ops; + calld->on_done_recv = op->on_done_recv; + calld->recv_user_data = op->recv_user_data; + op->on_done_recv = hs_on_recv; + op->recv_user_data = elem; + } + + grpc_call_next_op(elem, op); } /* Called on special channel events, such as disconnection or new incoming @@ -321,6 +335,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_server_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "http-server"}; diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c index d987fa2bc10..403b60901bf 100644 --- a/src/core/channel/noop_filter.c +++ b/src/core/channel/noop_filter.c @@ -50,8 +50,7 @@ static void ignore_unused(void *ignored) {} - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void noop_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -59,12 +58,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, ignore_unused(calld); ignore_unused(channeld); - switch (op->type) { - default: - /* pass control up or down the stack depending on op->dir */ - grpc_call_next_op(elem, op); - break; - } + /* pass control down the stack */ + grpc_call_next_op(elem, op); } /* Called on special channel events, such as disconnection or new incoming @@ -131,6 +126,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_no_op_filter = { - call_op, channel_op, sizeof(call_data), + noop_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "no-op"}; diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 608442c0089..709ca0b3974 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -150,6 +150,9 @@ struct grpc_call { gpr_uint8 num_completed_requests; /* flag that we need to request more data */ gpr_uint8 need_more_data; + /* flags with bits corresponding to write states allowing us to determine + what was sent */ + gpr_uint8 last_send_contains; /* Active ioreqs. request_set and request_data contain one element per active ioreq @@ -214,6 +217,10 @@ struct grpc_call { size_t send_initial_metadata_count; gpr_timespec send_deadline; + grpc_stream_op_buffer send_ops; + grpc_stream_op_buffer recv_ops; + grpc_stream_state recv_state; + /* Data that the legacy api needs to track. To be deleted at some point soon */ legacy_state *legacy_state; @@ -234,9 +241,11 @@ struct grpc_call { } while (0) static void do_nothing(void *ignored, grpc_op_error also_ignored) {} -static send_action choose_send_action(grpc_call *call); -static void enact_send_action(grpc_call *call, send_action sa); static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline); +static void call_on_done_recv(void *call, int success); +static void call_on_done_send(void *call, int success); +static int fill_send_ops(grpc_call *call, grpc_transport_op *op); +static void execute_op(grpc_call *call, grpc_transport_op *op); grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, const void *server_transport_data, @@ -359,20 +368,6 @@ static grpc_call_error bind_cq(grpc_call *call, grpc_completion_queue *cq) { return GRPC_CALL_OK; } -static void request_more_data(grpc_call *call) { - grpc_call_op op; - - /* call down */ - op.type = GRPC_REQUEST_DATA; - op.dir = GRPC_CALL_DOWN; - op.flags = 0; - op.done_cb = do_nothing; - op.user_data = NULL; - op.bind_pollset = NULL; - - grpc_call_execute_op(call, &op); -} - static int is_op_live(grpc_call *call, grpc_ioreq_op op) { gpr_uint8 set = call->request_set[op]; reqinfo_master *master; @@ -384,16 +379,31 @@ static int is_op_live(grpc_call *call, grpc_ioreq_op op) { static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); } static void unlock(grpc_call *call) { - send_action sa = SEND_NOTHING; + grpc_transport_op op; completed_request completed_requests[GRPC_IOREQ_OP_COUNT]; int completing_requests = 0; - int need_more_data = - call->need_more_data && - (call->write_state >= WRITE_STATE_STARTED || !call->is_client); + int start_op = 0; int i; - if (need_more_data) { + memset(&op, 0, sizeof(op)); + + if (call->need_more_data && + (call->write_state >= WRITE_STATE_STARTED || !call->is_client)) { + op.recv_ops = &call->recv_ops; + op.recv_state = &call->recv_state; + op.on_done_recv = call_on_done_recv; + op.recv_user_data = call; call->need_more_data = 0; + grpc_call_internal_ref(call); + start_op = 1; + } + + if (!call->sending) { + if (fill_send_ops(call, &op)) { + call->sending = 1; + grpc_call_internal_ref(call); + start_op = 1; + } } if (!call->completing && call->num_completed_requests != 0) { @@ -405,22 +415,10 @@ static void unlock(grpc_call *call) { grpc_call_internal_ref(call); } - if (!call->sending) { - sa = choose_send_action(call); - if (sa != SEND_NOTHING) { - call->sending = 1; - grpc_call_internal_ref(call); - } - } - gpr_mu_unlock(&call->mu); - if (need_more_data) { - request_more_data(call); - } - - if (sa != SEND_NOTHING) { - enact_send_action(call, sa); + if (start_op) { + execute_op(call, &op); } if (completing_requests > 0) { @@ -577,6 +575,64 @@ static void finish_start_step(void *pc, grpc_op_error error) { error); } +static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, + grpc_metadata *metadata) { + size_t i; + grpc_mdelem_list out; + if (count == 0) { + out.head = out.tail = NULL; + return out; + } + for (i = 0; i < count; i++) { + grpc_metadata *md = &metadata[i]; + grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1]; + grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1]; + grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data; + assert(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data)); + l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key, + (const gpr_uint8 *)md->value, + md->value_length); + l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL; + l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL; + } + out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data); + out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data); + return out; +} + +static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { + grpc_ioreq_data data; + grpc_metadata_batch mdb; + size_t i; + GPR_ASSERT(op->send_ops == NULL); + + switch (call->write_state) { + case WRITE_STATE_INITIAL: + if (!is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) { + break; + } + data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA]; + mdb.list = chain_metadata_from_app( + call, data.send_metadata.count, data.send_metadata.metadata); + mdb.garbage.head = mdb.garbage.tail = NULL; + mdb.deadline = call->send_deadline; + for (i = 0; i < call->send_initial_metadata_count; i++) { + grpc_metadata_batch_link_head(&mdb, + &call->send_initial_metadata[i]); + } + grpc_sopb_add_metadata(&call->send_ops, mdb); + op->send_ops = &call->send_ops; + op->bind_pollset = grpc_cq_pollset(call->cq); + call->last_send_contains |= 1 << WRITE_STATE_INITIAL; + /* fall through intended */ + case WRITE_STATE_STARTED: + if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { + data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; + grpc_sopb_add_message(data.send_message); +abort(); + } +} + static send_action choose_send_action(grpc_call *call) { switch (call->write_state) { case WRITE_STATE_INITIAL: @@ -614,33 +670,7 @@ static send_action choose_send_action(grpc_call *call) { return SEND_NOTHING; } -static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, - grpc_metadata *metadata) { - size_t i; - grpc_mdelem_list out; - if (count == 0) { - out.head = out.tail = NULL; - return out; - } - for (i = 0; i < count; i++) { - grpc_metadata *md = &metadata[i]; - grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1]; - grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1]; - grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data; - assert(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data)); - l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key, - (const gpr_uint8 *)md->value, - md->value_length); - l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL; - l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL; - } - out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data); - out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data); - return out; -} - static void enact_send_action(grpc_call *call, send_action sa) { - grpc_ioreq_data data; grpc_call_op op; size_t i; gpr_uint32 flags = 0; @@ -654,37 +684,11 @@ static void enact_send_action(grpc_call *call, send_action sa) { flags |= GRPC_WRITE_BUFFER_HINT; /* fallthrough */ case SEND_INITIAL_METADATA: - data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA]; - op.type = GRPC_SEND_METADATA; - op.dir = GRPC_CALL_DOWN; - op.flags = flags; - op.data.metadata.list = chain_metadata_from_app( - call, data.send_metadata.count, data.send_metadata.metadata); - op.data.metadata.garbage.head = op.data.metadata.garbage.tail = NULL; - op.data.metadata.deadline = call->send_deadline; - for (i = 0; i < call->send_initial_metadata_count; i++) { - grpc_metadata_batch_link_head(&op.data.metadata, - &call->send_initial_metadata[i]); - } - call->send_initial_metadata_count = 0; - op.done_cb = finish_start_step; - op.user_data = call; - op.bind_pollset = grpc_cq_pollset(call->cq); - grpc_call_execute_op(call, &op); break; case SEND_BUFFERED_MESSAGE: flags |= GRPC_WRITE_BUFFER_HINT; /* fallthrough */ case SEND_MESSAGE: - data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; - op.type = GRPC_SEND_MESSAGE; - op.dir = GRPC_CALL_DOWN; - op.flags = flags; - op.data.message = data.send_message; - op.done_cb = finish_write_step; - op.user_data = call; - op.bind_pollset = NULL; - grpc_call_execute_op(call, &op); break; case SEND_TRAILING_METADATA_AND_FINISH: /* send trailing metadata */ diff --git a/src/core/surface/call.h b/src/core/surface/call.h index f8d0915349e..358e5560a35 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -106,7 +106,6 @@ void grpc_call_recv_message(grpc_call_element *surface_element, void grpc_call_read_closed(grpc_call_element *surface_element); void grpc_call_stream_closed(grpc_call_element *surface_element); -void grpc_call_execute_op(grpc_call *call, grpc_call_op *op); grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, grpc_ioreq_completion_func on_complete, void *user_data); diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index e32ee284e09..86bd5d20986 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -503,7 +503,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, gpr_mu_lock(&t->mu); t->calling_back = 1; - ref_transport(t); + ref_transport(t); /* matches unref at end of this function */ gpr_mu_unlock(&t->mu); sr = setup(arg, &t->base, t->metadata_context); @@ -515,7 +515,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, if (t->destroying) gpr_cv_signal(&t->cv); unlock(t); - ref_transport(t); + ref_transport(t); /* matches unref inside recv_data */ recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK); unref_transport(t); diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index c3901bf6088..dabe68f3bdd 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -50,22 +50,9 @@ typedef enum grpc_stream_op_code { Must be ignored by receivers */ GRPC_NO_OP, GRPC_OP_METADATA, - /* Begin a message/metadata element/status - as defined by - grpc_message_type. */ - GRPC_OP_BEGIN_MESSAGE, - /* Add a slice of data to the current message/metadata element/status. - Must not overflow the forward declared length. */ - GRPC_OP_SLICE + GRPC_OP_MESSAGE } grpc_stream_op_code; -/* Arguments for GRPC_OP_BEGIN */ -typedef struct grpc_begin_message { - /* How many bytes of data will this message contain */ - gpr_uint32 length; - /* Write flags for the message: see grpc.h GRPC_WRITE_xxx */ - gpr_uint32 flags; -} grpc_begin_message; - typedef struct grpc_linked_mdelem { grpc_mdelem *md; struct grpc_linked_mdelem *next; @@ -118,9 +105,8 @@ typedef struct grpc_stream_op { /* the arguments to this operation. union fields are named according to the associated op-code */ union { - grpc_begin_message begin_message; + grpc_byte_buffer *message; grpc_metadata_batch metadata; - gpr_slice slice; } data; } grpc_stream_op; @@ -148,16 +134,8 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops); /* Append a GRPC_NO_OP to a buffer */ void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb); -/* Append a GRPC_OP_BEGIN to a buffer */ -void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, - gpr_uint32 flags); +void grpc_sopb_add_message(grpc_stream_op_buffer *sopb, grpc_byte_buffer *bb); void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch metadata); -/* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */ -void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice); -/* Append a GRPC_OP_FLOW_CTL_CB to a buffer */ -void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb, - void (*cb)(void *arg, grpc_op_error error), - void *arg); /* Append a buffer to a buffer - does not ref/unref any internal objects */ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops); diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 6dd0fdaf468..f31011e56a6 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -78,6 +78,8 @@ struct grpc_transport_callbacks { void (*accept_stream)(void *user_data, grpc_transport *transport, const void *server_data); + void (*goaway)(void *user_data, grpc_transport *transport, grpc_status_code status, gpr_slice debug); + /* The transport has been closed */ void (*closed)(void *user_data, grpc_transport *transport); }; @@ -139,8 +141,14 @@ typedef struct grpc_transport_op { void *recv_user_data; grpc_pollset *bind_pollset; + + grpc_status_code cancel_with_status; } grpc_transport_op; +void grpc_transport_op_finish_with_failure(grpc_transport_op *op); + +char *grpc_transport_op_string(grpc_transport_op *op); + /* Send a batch of operations on a transport Takes ownership of any objects contained in ops. @@ -161,19 +169,6 @@ void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream, void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data), void *user_data); -/* Abort a stream - - Terminate reading and writing for a stream. A final recv_batch with no - operations and final_state == GRPC_STREAM_CLOSED will be received locally, - and no more data will be presented to the up-layer. - - TODO(ctiller): consider adding a HTTP/2 reason to this function. */ -void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream, - grpc_status_code status); - -void grpc_transport_add_to_pollset(grpc_transport *transport, - grpc_pollset *pollset); - /* Advise peer of pending connection termination. */ void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status, gpr_slice debug_data); diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c new file mode 100644 index 00000000000..5f7e1be2682 --- /dev/null +++ b/src/core/transport/transport_op_string.c @@ -0,0 +1,141 @@ +/* + * + * Copyright 2015, 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. + * + */ + +#include "src/core/channel/channel_stack.h" + +#include +#include +#include + +#include "src/core/support/string.h" +#include +#include + +static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { + gpr_strvec_add(b, gpr_strdup(" key=")); + gpr_strvec_add( + b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), + GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); + + gpr_strvec_add(b, gpr_strdup(" value=")); + gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice), + GPR_SLICE_LENGTH(md->value->slice), + GPR_HEXDUMP_PLAINTEXT)); +} + +static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { + grpc_linked_mdelem *m; + for (m = md.list.head; m != NULL; m = m->next) { + put_metadata(b, m->md); + } + if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) { + char *tmp; + gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec, + md.deadline.tv_nsec); + gpr_strvec_add(b, tmp); + } +} + +char *grpc_call_op_string(grpc_call_op *op) { + char *tmp; + char *out; + + gpr_strvec b; + gpr_strvec_init(&b); + + switch (op->dir) { + case GRPC_CALL_DOWN: + gpr_strvec_add(&b, gpr_strdup(">")); + break; + case GRPC_CALL_UP: + gpr_strvec_add(&b, gpr_strdup("<")); + break; + } + switch (op->type) { + case GRPC_SEND_METADATA: + gpr_strvec_add(&b, gpr_strdup("SEND_METADATA")); + put_metadata_list(&b, op->data.metadata); + break; + case GRPC_SEND_MESSAGE: + gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); + break; + case GRPC_SEND_PREFORMATTED_MESSAGE: + gpr_strvec_add(&b, gpr_strdup("SEND_PREFORMATTED_MESSAGE")); + break; + case GRPC_SEND_FINISH: + gpr_strvec_add(&b, gpr_strdup("SEND_FINISH")); + break; + case GRPC_REQUEST_DATA: + gpr_strvec_add(&b, gpr_strdup("REQUEST_DATA")); + break; + case GRPC_RECV_METADATA: + gpr_strvec_add(&b, gpr_strdup("RECV_METADATA")); + put_metadata_list(&b, op->data.metadata); + break; + case GRPC_RECV_MESSAGE: + gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); + break; + case GRPC_RECV_HALF_CLOSE: + gpr_strvec_add(&b, gpr_strdup("RECV_HALF_CLOSE")); + break; + case GRPC_RECV_FINISH: + gpr_strvec_add(&b, gpr_strdup("RECV_FINISH")); + break; + case GRPC_RECV_SYNTHETIC_STATUS: + gpr_asprintf(&tmp, "RECV_SYNTHETIC_STATUS status=%d message='%s'", + op->data.synthetic_status.status, + op->data.synthetic_status.message); + gpr_strvec_add(&b, tmp); + break; + case GRPC_CANCEL_OP: + gpr_strvec_add(&b, gpr_strdup("CANCEL_OP")); + break; + } + gpr_asprintf(&tmp, " flags=0x%08x", op->flags); + gpr_strvec_add(&b, tmp); + if (op->bind_pollset) { + gpr_strvec_add(&b, gpr_strdup("bind_pollset")); + } + + out = gpr_strvec_flatten(&b, NULL); + gpr_strvec_destroy(&b); + + return out; +} + +void grpc_call_log_op(char *file, int line, gpr_log_severity severity, + grpc_call_element *elem, grpc_call_op *op) { + char *str = grpc_call_op_string(op); + gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); + gpr_free(str); +} diff --git a/vsprojects/vs2010/grpc.vcxproj b/vsprojects/vs2010/grpc.vcxproj index f16ad85e5c7..c92efd8ca61 100644 --- a/vsprojects/vs2010/grpc.vcxproj +++ b/vsprojects/vs2010/grpc.vcxproj @@ -107,7 +107,6 @@ - @@ -229,8 +228,6 @@ - - @@ -247,8 +244,6 @@ - - @@ -423,6 +418,8 @@ + + diff --git a/vsprojects/vs2010/grpc.vcxproj.filters b/vsprojects/vs2010/grpc.vcxproj.filters index 1dfca58cb55..edce8d96526 100644 --- a/vsprojects/vs2010/grpc.vcxproj.filters +++ b/vsprojects/vs2010/grpc.vcxproj.filters @@ -61,9 +61,6 @@ src\core\tsi - - src\core\channel - src\core\channel @@ -88,9 +85,6 @@ src\core\channel - - src\core\channel - src\core\channel @@ -352,6 +346,9 @@ src\core\transport + + src\core\transport + @@ -443,9 +440,6 @@ src\core\channel - - src\core\channel - src\core\channel diff --git a/vsprojects/vs2010/grpc_unsecure.vcxproj b/vsprojects/vs2010/grpc_unsecure.vcxproj index 75b6dce9437..f0b94c09031 100644 --- a/vsprojects/vs2010/grpc_unsecure.vcxproj +++ b/vsprojects/vs2010/grpc_unsecure.vcxproj @@ -91,7 +91,6 @@ - @@ -175,8 +174,6 @@ - - @@ -193,8 +190,6 @@ - - @@ -369,6 +364,8 @@ + + diff --git a/vsprojects/vs2010/grpc_unsecure.vcxproj.filters b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters index 7c94d4d51e3..daca2c0c5a0 100644 --- a/vsprojects/vs2010/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters @@ -4,9 +4,6 @@ src\core\surface - - src\core\channel - src\core\channel @@ -31,9 +28,6 @@ src\core\channel - - src\core\channel - src\core\channel @@ -295,6 +289,9 @@ src\core\transport + + src\core\transport + @@ -338,9 +335,6 @@ src\core\channel - - src\core\channel - src\core\channel diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj index b606f91473c..fd6900e9b88 100644 --- a/vsprojects/vs2013/grpc.vcxproj +++ b/vsprojects/vs2013/grpc.vcxproj @@ -109,7 +109,6 @@ - @@ -231,8 +230,6 @@ - - @@ -249,8 +246,6 @@ - - @@ -425,6 +420,8 @@ + + diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters index 1dfca58cb55..edce8d96526 100644 --- a/vsprojects/vs2013/grpc.vcxproj.filters +++ b/vsprojects/vs2013/grpc.vcxproj.filters @@ -61,9 +61,6 @@ src\core\tsi - - src\core\channel - src\core\channel @@ -88,9 +85,6 @@ src\core\channel - - src\core\channel - src\core\channel @@ -352,6 +346,9 @@ src\core\transport + + src\core\transport + @@ -443,9 +440,6 @@ src\core\channel - - src\core\channel - src\core\channel diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj index b068274af9d..e170d1934e8 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj @@ -93,7 +93,6 @@ - @@ -177,8 +176,6 @@ - - @@ -195,8 +192,6 @@ - - @@ -371,6 +366,8 @@ + + diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters index 7c94d4d51e3..daca2c0c5a0 100644 --- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters @@ -4,9 +4,6 @@ src\core\surface - - src\core\channel - src\core\channel @@ -31,9 +28,6 @@ src\core\channel - - src\core\channel - src\core\channel @@ -295,6 +289,9 @@ src\core\transport + + src\core\transport + @@ -338,9 +335,6 @@ src\core\channel - - src\core\channel - src\core\channel From 58ce3f0e37f5dc0f525fe7ec007f12f1fc91ebeb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 07:54:24 -0700 Subject: [PATCH 03/58] call progress --- src/core/surface/call.c | 201 +++++++++++++--------------------------- 1 file changed, 65 insertions(+), 136 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 709ca0b3974..781d70c9ffd 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -81,9 +81,9 @@ typedef struct { grpc_ioreq_completion_func on_complete; void *user_data; /* a bit mask of which request ops are needed (1u << opid) */ - gpr_uint32 need_mask; + gpr_uint16 need_mask; /* a bit mask of which request ops are now completed */ - gpr_uint32 complete_mask; + gpr_uint16 complete_mask; } reqinfo_master; /* Status data for a request can come from several sources; this @@ -152,7 +152,7 @@ struct grpc_call { gpr_uint8 need_more_data; /* flags with bits corresponding to write states allowing us to determine what was sent */ - gpr_uint8 last_send_contains; + gpr_uint16 last_send_contains; /* Active ioreqs. request_set and request_data contain one element per active ioreq @@ -552,29 +552,24 @@ static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op, } } -static void finish_send_op(grpc_call *call, grpc_ioreq_op op, write_state ws, - grpc_op_error error) { +static void call_on_done_send(void *pc, int success) { + grpc_call *call = pc; + grpc_op_error error = success ? GRPC_OP_OK : GRPC_OP_ERROR; lock(call); - finish_ioreq_op(call, op, error); + if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) { + finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error); + } + if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) { + finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error); + } + if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) { + finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, error); + } call->sending = 0; - call->write_state = ws; unlock(call); grpc_call_internal_unref(call, 0); } -static void finish_write_step(void *pc, grpc_op_error error) { - finish_send_op(pc, GRPC_IOREQ_SEND_MESSAGE, WRITE_STATE_STARTED, error); -} - -static void finish_finish_step(void *pc, grpc_op_error error) { - finish_send_op(pc, GRPC_IOREQ_SEND_CLOSE, WRITE_STATE_WRITE_CLOSED, error); -} - -static void finish_start_step(void *pc, grpc_op_error error) { - finish_send_op(pc, GRPC_IOREQ_SEND_INITIAL_METADATA, WRITE_STATE_STARTED, - error); -} - static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, grpc_metadata *metadata) { size_t i; @@ -604,6 +599,7 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { grpc_ioreq_data data; grpc_metadata_batch mdb; size_t i; + char status_str[GPR_LTOA_MIN_BUFSIZE]; GPR_ASSERT(op->send_ops == NULL); switch (call->write_state) { @@ -623,117 +619,58 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { grpc_sopb_add_metadata(&call->send_ops, mdb); op->send_ops = &call->send_ops; op->bind_pollset = grpc_cq_pollset(call->cq); - call->last_send_contains |= 1 << WRITE_STATE_INITIAL; + call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA; + call->write_state = WRITE_STATE_STARTED; /* fall through intended */ case WRITE_STATE_STARTED: if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; - grpc_sopb_add_message(data.send_message); -abort(); - } -} - -static send_action choose_send_action(grpc_call *call) { - switch (call->write_state) { - case WRITE_STATE_INITIAL: - if (is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) { - if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE) || - is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) { - return SEND_BUFFERED_INITIAL_METADATA; - } else { - return SEND_INITIAL_METADATA; - } + grpc_sopb_add_message(&call->send_ops, data.send_message); + op->send_ops = &call->send_ops; + call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE; } - return SEND_NOTHING; - case WRITE_STATE_STARTED: - if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { - if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) { - return SEND_BUFFERED_MESSAGE; - } else { - return SEND_MESSAGE; - } - } else if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) { - finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_OK); - finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_OK); - if (call->is_client) { - return SEND_FINISH; - } else { - return SEND_TRAILING_METADATA_AND_FINISH; + if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) { + op->is_last_send = 1; + op->send_ops = &call->send_ops; + call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE; + call->write_state = WRITE_STATE_WRITE_CLOSED; + if (!call->is_client) { + /* send trailing metadata */ + data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA]; + mdb.list = chain_metadata_from_app( + call, data.send_metadata.count, data.send_metadata.metadata); + mdb.garbage.head = mdb.garbage.tail = NULL; + mdb.deadline = call->send_deadline; + /* send status */ + /* TODO(ctiller): cache common status values */ + data = call->request_data[GRPC_IOREQ_SEND_STATUS]; + gpr_ltoa(data.send_status.code, status_str); + grpc_metadata_batch_add_tail( + &mdb, &call->status_link, + grpc_mdelem_from_metadata_strings( + call->metadata_context, + grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)), + grpc_mdstr_from_string(call->metadata_context, status_str))); + if (data.send_status.details) { + grpc_metadata_batch_add_tail( + &mdb, &call->details_link, + grpc_mdelem_from_metadata_strings( + call->metadata_context, + grpc_mdstr_ref(grpc_channel_get_message_string(call->channel)), + grpc_mdstr_from_string(call->metadata_context, + data.send_status.details))); + } } } - return SEND_NOTHING; - case WRITE_STATE_WRITE_CLOSED: - return SEND_NOTHING; - } - gpr_log(GPR_ERROR, "should never reach here"); - abort(); - return SEND_NOTHING; -} - -static void enact_send_action(grpc_call *call, send_action sa) { - grpc_call_op op; - size_t i; - gpr_uint32 flags = 0; - char status_str[GPR_LTOA_MIN_BUFSIZE]; - - switch (sa) { - case SEND_NOTHING: - abort(); - break; - case SEND_BUFFERED_INITIAL_METADATA: - flags |= GRPC_WRITE_BUFFER_HINT; - /* fallthrough */ - case SEND_INITIAL_METADATA: break; - case SEND_BUFFERED_MESSAGE: - flags |= GRPC_WRITE_BUFFER_HINT; - /* fallthrough */ - case SEND_MESSAGE: - break; - case SEND_TRAILING_METADATA_AND_FINISH: - /* send trailing metadata */ - data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA]; - op.type = GRPC_SEND_METADATA; - op.dir = GRPC_CALL_DOWN; - op.flags = flags; - op.data.metadata.list = chain_metadata_from_app( - call, data.send_metadata.count, data.send_metadata.metadata); - op.data.metadata.garbage.head = op.data.metadata.garbage.tail = NULL; - op.data.metadata.deadline = call->send_deadline; - op.bind_pollset = NULL; - /* send status */ - /* TODO(ctiller): cache common status values */ - data = call->request_data[GRPC_IOREQ_SEND_STATUS]; - gpr_ltoa(data.send_status.code, status_str); - grpc_metadata_batch_add_tail( - &op.data.metadata, &call->status_link, - grpc_mdelem_from_metadata_strings( - call->metadata_context, - grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)), - grpc_mdstr_from_string(call->metadata_context, status_str))); - if (data.send_status.details) { - grpc_metadata_batch_add_tail( - &op.data.metadata, &call->details_link, - grpc_mdelem_from_metadata_strings( - call->metadata_context, - grpc_mdstr_ref(grpc_channel_get_message_string(call->channel)), - grpc_mdstr_from_string(call->metadata_context, - data.send_status.details))); - } - op.done_cb = do_nothing; - op.user_data = NULL; - grpc_call_execute_op(call, &op); - /* fallthrough: see choose_send_action for details */ - case SEND_FINISH: - op.type = GRPC_SEND_FINISH; - op.dir = GRPC_CALL_DOWN; - op.flags = 0; - op.done_cb = finish_finish_step; - op.user_data = call; - op.bind_pollset = NULL; - grpc_call_execute_op(call, &op); + case WRITE_STATE_WRITE_CLOSED: break; } + if (op->send_ops) { + op->on_done_send = call_on_done_send; + op->send_user_data = call; + } + return op->send_ops != NULL; } static grpc_call_error start_ioreq_error(grpc_call *call, @@ -875,19 +812,12 @@ void grpc_call_destroy(grpc_call *c) { grpc_call_internal_unref(c, 1); } -grpc_call_error grpc_call_cancel(grpc_call *c) { - grpc_call_element *elem; - grpc_call_op op; - - op.type = GRPC_CANCEL_OP; - op.dir = GRPC_CALL_DOWN; - op.flags = 0; - op.done_cb = do_nothing; - op.user_data = NULL; - op.bind_pollset = NULL; +grpc_call_error grpc_call_cancel(grpc_call *call) { + grpc_transport_op op; + memset(&op, 0, sizeof(op)); + op.cancel_with_status = GRPC_STATUS_CANCELLED; - elem = CALL_ELEM_FROM_CALL(c, 0); - elem->filter->call_op(elem, NULL, &op); + execute_op(call, &op); return GRPC_CALL_OK; } @@ -905,11 +835,10 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c, return grpc_call_cancel(c); } -void grpc_call_execute_op(grpc_call *call, grpc_call_op *op) { +static void execute_op(grpc_call *call, grpc_transport_op *op) { grpc_call_element *elem; - GPR_ASSERT(op->dir == GRPC_CALL_DOWN); elem = CALL_ELEM_FROM_CALL(call, 0); - elem->filter->call_op(elem, NULL, op); + elem->filter->start_transport_op(elem, op); } grpc_call *grpc_call_from_top_element(grpc_call_element *elem) { From 629b0ed8041f96968e8e61c2b4992d08a38cf28a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 11:14:26 -0700 Subject: [PATCH 04/58] Call compiles --- src/core/channel/connected_channel.c | 39 ---- src/core/surface/call.c | 263 ++++++++++++++++++++------- src/core/surface/call.h | 14 -- src/core/surface/channel.c | 23 +++ src/core/surface/channel.h | 1 + src/core/transport/stream_op.h | 28 ++- src/core/transport/transport.h | 15 -- 7 files changed, 246 insertions(+), 137 deletions(-) diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index d0b834a10a1..9e2d92ffbc2 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -45,8 +45,6 @@ #include #define MAX_BUFFER_LENGTH 8192 -/* the protobuf library will (by default) start warning at 100megs */ -#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) typedef struct connected_channel_channel_data { grpc_transport *transport; @@ -63,24 +61,6 @@ typedef struct connected_channel_call_data { #define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \ (((call_data *)(transport_stream)) - 1) -#if 0 -/* Copy the contents of a byte buffer into stream ops */ -static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, - grpc_stream_op_buffer *sopb) { - size_t i; - - switch (byte_buffer->type) { - case GRPC_BB_SLICE_BUFFER: - for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) { - gpr_slice slice = byte_buffer->data.slice_buffer.slices[i]; - gpr_slice_ref(slice); - grpc_sopb_add_slice(sopb, slice); - } - break; - } -} -#endif - /* Intercept a call operation and either push it directly up or translate it into transport stream operations */ static void con_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { @@ -145,25 +125,6 @@ static void init_channel_elem(grpc_channel_element *elem, GPR_ASSERT(is_last); GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); cd->transport = NULL; - -#if 0 - cd->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; - if (args) { - for (i = 0; i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { - if (args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s ignored: it must be an integer", - GRPC_ARG_MAX_MESSAGE_LENGTH); - } else if (args->args[i].value.integer < 0) { - gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", - GRPC_ARG_MAX_MESSAGE_LENGTH); - } else { - cd->max_message_length = args->args[i].value.integer; - } - } - } - } -#endif } /* Destructor for channel_data */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index fb2efac74e6..7fcf6e2b04b 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -144,12 +144,14 @@ struct grpc_call { gpr_uint8 have_alarm; /* are we currently performing a send operation */ gpr_uint8 sending; + /* are we currently performing a recv operation */ + gpr_uint8 receiving; /* are we currently completing requests */ gpr_uint8 completing; /* pairs with completed_requests */ gpr_uint8 num_completed_requests; - /* flag that we need to request more data */ - gpr_uint8 need_more_data; + /* are we currently reading a message? */ + gpr_uint8 reading_message; /* flags with bits corresponding to write states allowing us to determine what was sent */ gpr_uint16 last_send_contains; @@ -221,6 +223,9 @@ struct grpc_call { grpc_stream_op_buffer recv_ops; grpc_stream_state recv_state; + gpr_slice_buffer incoming_message; + gpr_uint32 incoming_message_length; + /* Data that the legacy api needs to track. To be deleted at some point soon */ legacy_state *legacy_state; @@ -246,6 +251,8 @@ static void call_on_done_recv(void *call, int success); static void call_on_done_send(void *call, int success); static int fill_send_ops(grpc_call *call, grpc_transport_op *op); static void execute_op(grpc_call *call, grpc_transport_op *op); +static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata); +static void finish_read_ops(grpc_call *call); grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, const void *server_transport_data, @@ -378,6 +385,15 @@ static int is_op_live(grpc_call *call, grpc_ioreq_op op) { static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); } +static int need_more_data(grpc_call *call) { + return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) || + is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) || + is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || + is_op_live(call, GRPC_IOREQ_RECV_STATUS) || + is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || + is_op_live(call, GRPC_IOREQ_RECV_CLOSE); +} + static void unlock(grpc_call *call) { grpc_transport_op op; completed_request completed_requests[GRPC_IOREQ_OP_COUNT]; @@ -387,13 +403,14 @@ static void unlock(grpc_call *call) { memset(&op, 0, sizeof(op)); - if (call->need_more_data && - (call->write_state >= WRITE_STATE_STARTED || !call->is_client)) { + if (!call->receiving && + (call->write_state >= WRITE_STATE_STARTED || !call->is_client) && + need_more_data(call)) { op.recv_ops = &call->recv_ops; op.recv_state = &call->recv_state; op.on_done_recv = call_on_done_recv; op.recv_user_data = call; - call->need_more_data = 0; + call->receiving = 1; grpc_call_internal_ref(call); start_op = 1; } @@ -570,6 +587,121 @@ static void call_on_done_send(void *pc, int success) { grpc_call_internal_unref(call, 0); } +static void finish_message(grpc_call *call) { + /* TODO(ctiller): this could be a lot faster if coded directly */ + grpc_byte_buffer *byte_buffer = grpc_byte_buffer_create( + call->incoming_message.slices, call->incoming_message.count); + gpr_slice_buffer_reset_and_unref(&call->incoming_message); + + grpc_bbq_push(&call->incoming_queue, byte_buffer); + + GPR_ASSERT(call->incoming_message.count == 0); + call->reading_message = 0; +} + +static int begin_message(grpc_call *call, grpc_begin_message msg) { + /* can't begin a message when we're still reading a message */ + if (call->reading_message) { + char *message = NULL; + gpr_asprintf( + &message, "Message terminated early; read %d bytes, expected %d", + (int)call->incoming_message.length, (int)call->incoming_message_length); + grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); + gpr_free(message); + return 0; + } + /* stash away parameters, and prepare for incoming slices */ + if (msg.length > grpc_channel_get_max_message_length(call->channel)) { + char *message = NULL; + gpr_asprintf( + &message, + "Maximum message length of %d exceeded by a message of length %d", + grpc_channel_get_max_message_length(call->channel), msg.length); + grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); + gpr_free(message); + return 0; + } else if (msg.length > 0) { + call->reading_message = 1; + call->incoming_message_length = msg.length; + return 1; + } else { + finish_message(call); + return 1; + } +} + +static int add_slice_to_message(grpc_call *call, gpr_slice slice) { + if (GPR_SLICE_LENGTH(slice) == 0) { + gpr_slice_unref(slice); + return 1; + } + /* we have to be reading a message to know what to do here */ + if (!call->reading_message) { + grpc_call_cancel_with_status( + call, GRPC_STATUS_INVALID_ARGUMENT, + "Received payload data while not reading a message"); + return 0; + } + /* append the slice to the incoming buffer */ + gpr_slice_buffer_add(&call->incoming_message, slice); + if (call->incoming_message.length > call->incoming_message_length) { + /* if we got too many bytes, complain */ + char *message = NULL; + gpr_asprintf( + &message, "Receiving message overflow; read %d bytes, expected %d", + (int)call->incoming_message.length, (int)call->incoming_message_length); + grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message); + gpr_free(message); + return 0; + } else if (call->incoming_message.length == call->incoming_message_length) { + finish_message(call); + return 1; + } else { + return 1; + } +} + +static void call_on_done_recv(void *pc, int success) { + grpc_call *call = pc; + size_t i; + int unref = 0; + lock(call); + 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 (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; + unref = 1; + } + if (!success) { + abort(); + } + finish_read_ops(call); + unlock(call); + + if (unref) { + grpc_call_internal_unref(call, 0); + } +} + static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, grpc_metadata *metadata) { size_t i; @@ -595,6 +727,22 @@ static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, return out; } +/* Copy the contents of a byte buffer into stream ops */ +static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, + grpc_stream_op_buffer *sopb) { + size_t i; + + switch (byte_buffer->type) { + case GRPC_BB_SLICE_BUFFER: + for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) { + gpr_slice slice = byte_buffer->data.slice_buffer.slices[i]; + gpr_slice_ref(slice); + grpc_sopb_add_slice(sopb, slice); + } + break; + } +} + static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { grpc_ioreq_data data; grpc_metadata_batch mdb; @@ -608,24 +756,25 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { break; } data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA]; - mdb.list = chain_metadata_from_app( - call, data.send_metadata.count, data.send_metadata.metadata); + mdb.list = chain_metadata_from_app(call, data.send_metadata.count, + data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = call->send_deadline; for (i = 0; i < call->send_initial_metadata_count; i++) { - grpc_metadata_batch_link_head(&mdb, - &call->send_initial_metadata[i]); + grpc_metadata_batch_link_head(&mdb, &call->send_initial_metadata[i]); } grpc_sopb_add_metadata(&call->send_ops, mdb); op->send_ops = &call->send_ops; op->bind_pollset = grpc_cq_pollset(call->cq); call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA; call->write_state = WRITE_STATE_STARTED; - /* fall through intended */ + /* fall through intended */ case WRITE_STATE_STARTED: if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; - grpc_sopb_add_message(&call->send_ops, data.send_message); + grpc_sopb_add_begin_message( + &call->send_ops, grpc_byte_buffer_length(data.send_message), 0); + copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops); op->send_ops = &call->send_ops; call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE; } @@ -637,8 +786,8 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { if (!call->is_client) { /* send trailing metadata */ data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA]; - mdb.list = chain_metadata_from_app( - call, data.send_metadata.count, data.send_metadata.metadata); + mdb.list = chain_metadata_from_app(call, data.send_metadata.count, + data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; mdb.deadline = call->send_deadline; /* send status */ @@ -656,7 +805,8 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { &mdb, &call->details_link, grpc_mdelem_from_metadata_strings( call->metadata_context, - grpc_mdstr_ref(grpc_channel_get_message_string(call->channel)), + grpc_mdstr_ref( + grpc_channel_get_message_string(call->channel)), grpc_mdstr_from_string(call->metadata_context, data.send_status.details))); } @@ -779,10 +929,6 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs, master->on_complete = completion; master->user_data = user_data; - if (have_ops & (1u << GRPC_IOREQ_RECV_MESSAGE)) { - call->need_more_data = 1; - } - finish_read_ops(call); early_out_write_ops(call); @@ -867,28 +1013,6 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now()); } -static void set_read_state_locked(grpc_call *call, read_state state) { - GPR_ASSERT(call->read_state < state); - call->read_state = state; - finish_read_ops(call); -} - -static void set_read_state(grpc_call *call, read_state state) { - lock(call); - set_read_state_locked(call, state); - unlock(call); -} - -void grpc_call_read_closed(grpc_call_element *elem) { - set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED); -} - -void grpc_call_stream_closed(grpc_call_element *elem) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - set_read_state(call, READ_STATE_STREAM_CLOSED); - grpc_call_internal_unref(call, 0); -} - /* we offset status by a small amount when storing it into transport metadata as metadata cannot store a 0 value (which is used as OK for grpc_status_codes */ @@ -912,35 +1036,13 @@ static gpr_uint32 decode_status(grpc_mdelem *md) { return status; } -void grpc_call_recv_message(grpc_call_element *elem, - grpc_byte_buffer *byte_buffer) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - lock(call); - grpc_bbq_push(&call->incoming_queue, byte_buffer); - finish_read_ops(call); - unlock(call); -} - -void grpc_call_recv_synthetic_status(grpc_call_element *elem, - grpc_status_code status, - const char *message) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - lock(call); - set_status_code(call, STATUS_FROM_CORE, status); - set_status_details(call, STATUS_FROM_CORE, - grpc_mdstr_from_string(call->metadata_context, message)); - unlock(call); -} - -int grpc_call_recv_metadata(grpc_call_element *elem, grpc_metadata_batch *md) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); +static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) { grpc_linked_mdelem *l; grpc_metadata_array *dest; grpc_metadata *mdusr; int is_trailing; grpc_mdctx *mdctx = call->metadata_context; - lock(call); is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA; for (l = md->list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; @@ -976,9 +1078,8 @@ int grpc_call_recv_metadata(grpc_call_element *elem, grpc_metadata_batch *md) { set_deadline_alarm(call, md->deadline); } if (!is_trailing) { - set_read_state_locked(call, READ_STATE_GOT_INITIAL_METADATA); + call->read_state = READ_STATE_GOT_INITIAL_METADATA; } - unlock(call); grpc_mdctx_lock(mdctx); for (l = md->list.head; l; l = l->next) { @@ -988,13 +1089,43 @@ int grpc_call_recv_metadata(grpc_call_element *elem, grpc_metadata_batch *md) { grpc_mdctx_locked_mdelem_unref(mdctx, l->md); } grpc_mdctx_unlock(mdctx); +} + +#if 0 +void grpc_call_read_closed(grpc_call_element *elem) { + set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED); +} - return !is_trailing; +void grpc_call_stream_closed(grpc_call_element *elem) { + grpc_call *call = CALL_FROM_TOP_ELEM(elem); + set_read_state(call, READ_STATE_STREAM_CLOSED); + grpc_call_internal_unref(call, 0); +} + +void grpc_call_recv_message(grpc_call_element *elem, + grpc_byte_buffer *byte_buffer) { + grpc_call *call = CALL_FROM_TOP_ELEM(elem); + lock(call); + grpc_bbq_push(&call->incoming_queue, byte_buffer); + finish_read_ops(call); + unlock(call); +} + +void grpc_call_recv_synthetic_status(grpc_call_element *elem, + grpc_status_code status, + const char *message) { + grpc_call *call = CALL_FROM_TOP_ELEM(elem); + lock(call); + set_status_code(call, STATUS_FROM_CORE, status); + set_status_details(call, STATUS_FROM_CORE, + grpc_mdstr_from_string(call->metadata_context, message)); + unlock(call); } grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { return CALL_STACK_FROM_CALL(call); } +#endif /* * BATCH API IMPLEMENTATION diff --git a/src/core/surface/call.h b/src/core/surface/call.h index 358e5560a35..199beb17386 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -96,26 +96,12 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call); void grpc_call_internal_ref(grpc_call *call); void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion); -/* Helpers for grpc_client, grpc_server filters to publish received data to - the completion queue/surface layer */ -/* receive metadata - returns 1 if this was initial metadata */ -int grpc_call_recv_metadata(grpc_call_element *surface_element, - grpc_metadata_batch *md); -void grpc_call_recv_message(grpc_call_element *surface_element, - grpc_byte_buffer *message); -void grpc_call_read_closed(grpc_call_element *surface_element); -void grpc_call_stream_closed(grpc_call_element *surface_element); - grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, grpc_ioreq_completion_func on_complete, void *user_data); grpc_call_stack *grpc_call_get_call_stack(grpc_call *call); -void grpc_call_recv_synthetic_status(grpc_call_element *elem, - grpc_status_code status, - const char *message); - /* Given the top call_element, get the call object. */ grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element); diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index 29b042e7c1a..f1d71afaf27 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -52,6 +52,7 @@ typedef struct registered_call { struct grpc_channel { int is_client; gpr_refcount refs; + gpr_uint32 max_message_length; grpc_mdctx *metadata_context; grpc_mdstr *grpc_status_string; grpc_mdstr *grpc_message_string; @@ -68,9 +69,13 @@ struct grpc_channel { #define CHANNEL_FROM_TOP_ELEM(top_elem) \ CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) +/* the protobuf library will (by default) start warning at 100megs */ +#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) + grpc_channel *grpc_channel_create_from_filters( const grpc_channel_filter **filters, size_t num_filters, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) { + size_t i; size_t size = sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters); grpc_channel *channel = gpr_malloc(size); @@ -88,6 +93,24 @@ grpc_channel *grpc_channel_create_from_filters( CHANNEL_STACK_FROM_CHANNEL(channel)); gpr_mu_init(&channel->registered_call_mu); channel->registered_calls = NULL; + + channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH; + if (args) { + for (i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) { + if (args->args[i].type != GRPC_ARG_INTEGER) { + gpr_log(GPR_ERROR, "%s ignored: it must be an integer", + GRPC_ARG_MAX_MESSAGE_LENGTH); + } else if (args->args[i].value.integer < 0) { + gpr_log(GPR_ERROR, "%s ignored: it must be >= 0", + GRPC_ARG_MAX_MESSAGE_LENGTH); + } else { + channel->max_message_length = args->args[i].value.integer; + } + } + } + } + return channel; } diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h index d3e51185eec..05d57a905b3 100644 --- a/src/core/surface/channel.h +++ b/src/core/surface/channel.h @@ -44,6 +44,7 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel); grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel); grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel); grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel); +gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel); void grpc_client_channel_closed(grpc_channel_element *elem); diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index dabe68f3bdd..c3901bf6088 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -50,9 +50,22 @@ typedef enum grpc_stream_op_code { Must be ignored by receivers */ GRPC_NO_OP, GRPC_OP_METADATA, - GRPC_OP_MESSAGE + /* Begin a message/metadata element/status - as defined by + grpc_message_type. */ + GRPC_OP_BEGIN_MESSAGE, + /* Add a slice of data to the current message/metadata element/status. + Must not overflow the forward declared length. */ + GRPC_OP_SLICE } grpc_stream_op_code; +/* Arguments for GRPC_OP_BEGIN */ +typedef struct grpc_begin_message { + /* How many bytes of data will this message contain */ + gpr_uint32 length; + /* Write flags for the message: see grpc.h GRPC_WRITE_xxx */ + gpr_uint32 flags; +} grpc_begin_message; + typedef struct grpc_linked_mdelem { grpc_mdelem *md; struct grpc_linked_mdelem *next; @@ -105,8 +118,9 @@ typedef struct grpc_stream_op { /* the arguments to this operation. union fields are named according to the associated op-code */ union { - grpc_byte_buffer *message; + grpc_begin_message begin_message; grpc_metadata_batch metadata; + gpr_slice slice; } data; } grpc_stream_op; @@ -134,8 +148,16 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops); /* Append a GRPC_NO_OP to a buffer */ void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb); -void grpc_sopb_add_message(grpc_stream_op_buffer *sopb, grpc_byte_buffer *bb); +/* Append a GRPC_OP_BEGIN to a buffer */ +void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, + gpr_uint32 flags); void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch metadata); +/* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */ +void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice); +/* Append a GRPC_OP_FLOW_CTL_CB to a buffer */ +void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb, + void (*cb)(void *arg, grpc_op_error error), + void *arg); /* Append a buffer to a buffer - does not ref/unref any internal objects */ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops); diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index f31011e56a6..264245d351f 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -113,21 +113,6 @@ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, void grpc_transport_destroy_stream(grpc_transport *transport, grpc_stream *stream); -/* Enable/disable incoming data for a stream. - - This effectively disables new window becoming available for a given stream, - but does not prevent existing window from being consumed by a sender: the - caller must still be prepared to receive some additional data after this - call. - - Arguments: - transport - the transport on which to create this stream - stream - the grpc_stream to destroy (memory is still owned by the - caller, but any child memory must be cleaned up) - allow - is it allowed that new window be opened up? */ -void grpc_transport_set_allow_window_updates(grpc_transport *transport, - grpc_stream *stream, int allow); - /* Transport op: a set of operations to perform on a transport */ typedef struct grpc_transport_op { grpc_stream_op_buffer *send_ops; From be18b8db301b800edef382389749632e4099afaf Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 14:00:47 -0700 Subject: [PATCH 05/58] Beginning transport work --- src/core/surface/channel_create.c | 4 +- src/core/surface/client.c | 29 +---- src/core/surface/lame_client.c | 19 +--- src/core/surface/server.c | 124 +++++++++++---------- src/core/surface/server_chttp2.c | 4 +- src/core/transport/chttp2/stream_encoder.c | 10 -- src/core/transport/chttp2_transport.c | 88 ++++++++++----- src/core/transport/transport.h | 3 + src/core/transport/transport_impl.h | 12 +- 9 files changed, 138 insertions(+), 155 deletions(-) diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c index 3104b1d00d5..5f3e9bec0c8 100644 --- a/src/core/surface/channel_create.c +++ b/src/core/surface/channel_create.c @@ -44,7 +44,6 @@ #include "src/core/channel/client_setup.h" #include "src/core/channel/connected_channel.h" #include "src/core/channel/http_client_filter.h" -#include "src/core/channel/http_filter.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" @@ -176,8 +175,7 @@ static void done_setup(void *sp) { static grpc_transport_setup_result complete_setup(void *channel_stack, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter, - &grpc_http_filter}; + static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter}; return grpc_client_channel_transport_setup_complete( channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); diff --git a/src/core/surface/client.c b/src/core/surface/client.c index 2f898ff7d7a..4669c59ee4b 100644 --- a/src/core/surface/client.c +++ b/src/core/surface/client.c @@ -43,32 +43,9 @@ typedef struct { void *unused; } call_data; typedef struct { void *unused; } channel_data; -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void client_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - - switch (op->type) { - case GRPC_RECV_METADATA: - grpc_call_recv_metadata(elem, &op->data.metadata); - break; - case GRPC_RECV_MESSAGE: - grpc_call_recv_message(elem, op->data.message); - op->done_cb(op->user_data, GRPC_OP_OK); - break; - case GRPC_RECV_HALF_CLOSE: - grpc_call_read_closed(elem); - break; - case GRPC_RECV_FINISH: - grpc_call_stream_closed(elem); - break; - case GRPC_RECV_SYNTHETIC_STATUS: - grpc_call_recv_synthetic_status(elem, op->data.synthetic_status.status, - op->data.synthetic_status.message); - break; - default: - GPR_ASSERT(op->dir == GRPC_CALL_DOWN); - grpc_call_next_op(elem, op); - } + grpc_call_next_op(elem, op); } static void channel_op(grpc_channel_element *elem, @@ -104,6 +81,6 @@ static void init_channel_elem(grpc_channel_element *elem, static void destroy_channel_elem(grpc_channel_element *elem) {} const grpc_channel_filter grpc_client_surface_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + client_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "client", }; diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index 78170806f17..4e9eb808d78 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -46,22 +46,9 @@ typedef struct { void *unused; } call_data; typedef struct { void *unused; } channel_data; -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void lame_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - - switch (op->type) { - case GRPC_SEND_METADATA: - grpc_metadata_batch_destroy(&op->data.metadata); - grpc_call_recv_synthetic_status(elem, GRPC_STATUS_UNKNOWN, - "Rpc sent on a lame channel."); - grpc_call_stream_closed(elem); - break; - default: - break; - } - - op->done_cb(op->user_data, GRPC_OP_ERROR); + grpc_transport_op_finish_with_failure(op); } static void channel_op(grpc_channel_element *elem, @@ -93,7 +80,7 @@ static void init_channel_elem(grpc_channel_element *elem, static void destroy_channel_elem(grpc_channel_element *elem) {} static const grpc_channel_filter lame_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "lame-client", }; diff --git a/src/core/surface/server.c b/src/core/surface/server.c index e7719298701..82d1323a4b1 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -173,13 +173,19 @@ struct call_data { grpc_call *call; call_state state; - gpr_timespec deadline; grpc_mdstr *path; grpc_mdstr *host; + gpr_timespec deadline; + int got_initial_metadata; legacy_data *legacy; grpc_completion_queue *cq_new; + grpc_stream_op_buffer *recv_ops; + grpc_stream_state *recv_state; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; + call_data **root[CALL_LIST_COUNT]; call_link links[CALL_LIST_COUNT]; }; @@ -371,46 +377,6 @@ static void kill_zombie(void *elem, int success) { grpc_call_destroy(grpc_call_from_top_element(elem)); } -static void stream_closed(grpc_call_element *elem) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->server->mu); - switch (calld->state) { - case ACTIVATED: - break; - case PENDING: - call_list_remove(calld, PENDING_START); - /* fallthrough intended */ - case NOT_STARTED: - calld->state = ZOMBIED; - grpc_iomgr_add_callback(kill_zombie, elem); - break; - case ZOMBIED: - break; - } - gpr_mu_unlock(&chand->server->mu); - grpc_call_stream_closed(elem); -} - -static void read_closed(grpc_call_element *elem) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->server->mu); - switch (calld->state) { - case ACTIVATED: - case PENDING: - grpc_call_read_closed(elem); - break; - case NOT_STARTED: - calld->state = ZOMBIED; - grpc_iomgr_add_callback(kill_zombie, elem); - break; - case ZOMBIED: - break; - } - gpr_mu_unlock(&chand->server->mu); -} - static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; channel_data *chand = elem->channel_data; @@ -425,33 +391,69 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { return md; } -static void call_op(grpc_call_element *elem, grpc_call_element *from_elemn, - grpc_call_op *op) { +static void server_on_recv(void *ptr, int success) { + grpc_call_element *elem = ptr; call_data *calld = elem->call_data; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - switch (op->type) { - case GRPC_RECV_METADATA: + channel_data *chand = elem->channel_data; + + if (success && !calld->got_initial_metadata) { + size_t i; + size_t nops = calld->recv_ops->nops; + grpc_stream_op *ops = calld->recv_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); - if (grpc_call_recv_metadata(elem, &op->data.metadata)) { + if (0 != gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future)) { calld->deadline = op->data.metadata.deadline; - start_new_rpc(elem); } + calld->got_initial_metadata = 1; + start_new_rpc(elem); break; - case GRPC_RECV_MESSAGE: - grpc_call_recv_message(elem, op->data.message); - op->done_cb(op->user_data, GRPC_OP_OK); - break; - case GRPC_RECV_HALF_CLOSE: - read_closed(elem); - break; - case GRPC_RECV_FINISH: - stream_closed(elem); + } + } + + switch (*calld->recv_state) { + case GRPC_STREAM_OPEN: break; + case GRPC_STREAM_SEND_CLOSED: break; + case GRPC_STREAM_RECV_CLOSED: + gpr_mu_lock(&chand->server->mu); + if (calld->state == NOT_STARTED) { + calld->state = ZOMBIED; + grpc_iomgr_add_callback(kill_zombie, elem); + } + gpr_mu_unlock(&chand->server->mu); break; - default: - GPR_ASSERT(op->dir == GRPC_CALL_DOWN); - grpc_call_next_op(elem, op); + case GRPC_STREAM_CLOSED: + gpr_mu_lock(&chand->server->mu); + if (calld->state == NOT_STARTED) { + calld->state = ZOMBIED; + grpc_iomgr_add_callback(kill_zombie, elem); + } else if (calld->state == PENDING) { + call_list_remove(calld, PENDING_START); + } + gpr_mu_unlock(&chand->server->mu); break; } + + calld->on_done_recv(calld->recv_user_data, success); +} + +static void server_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + call_data *calld = elem->call_data; + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + + if (op->recv_ops) { + /* substitute our callback for the higher callback */ + calld->recv_ops = op->recv_ops; + calld->recv_state = op->recv_state; + calld->on_done_recv = op->on_done_recv; + calld->recv_user_data = op->recv_user_data; + op->on_done_recv = server_on_recv; + op->recv_user_data = elem; + } + + grpc_call_next_op(elem, op); } static void channel_op(grpc_channel_element *elem, @@ -592,7 +594,7 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } static const grpc_channel_filter server_surface_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + server_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "server", }; diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index f3b9219f8b0..ebde5095a99 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -33,7 +33,6 @@ #include -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_server.h" @@ -46,8 +45,7 @@ static grpc_transport_setup_result setup_transport(void *server, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter, - &grpc_http_filter}; + static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; return grpc_server_setup_transport(server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c index 5ca31d6bc72..203de993143 100644 --- a/src/core/transport/chttp2/stream_encoder.c +++ b/src/core/transport/chttp2/stream_encoder.c @@ -481,12 +481,6 @@ gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count, break; case GRPC_OP_METADATA: grpc_metadata_batch_assert_ok(&op->data.metadata); - case GRPC_OP_FLOW_CTL_CB: - /* these just get copied as they don't impact the number of flow - controlled bytes */ - grpc_sopb_append(outops, op, 1); - curop++; - break; case GRPC_OP_BEGIN_MESSAGE: /* begin op: for now we just convert the op to a slice and fall through - this lets us reuse the slice framing code below */ @@ -567,10 +561,6 @@ void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof, GPR_ERROR, "These stream ops should be filtered out by grpc_chttp2_preencode"); abort(); - case GRPC_OP_FLOW_CTL_CB: - op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK); - curop++; - break; case GRPC_OP_METADATA: /* Encode a metadata batch; store the returned values, representing a metadata element that needs to be unreffed back into the metadata diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 86bd5d20986..9aee7ca4f19 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -91,10 +91,6 @@ typedef enum { /* streams that are waiting to start because there are too many concurrent streams on the connection */ WAITING_FOR_CONCURRENCY, - /* streams that want to callback the application */ - PENDING_CALLBACKS, - /* streams that *ARE* calling back to the application */ - EXECUTING_CALLBACKS, STREAM_LIST_COUNT /* must be last */ } stream_list_id; @@ -182,6 +178,18 @@ typedef struct { gpr_slice debug; } pending_goaway; +typedef struct { + void (*cb)(void *user_data, int success); + void *user_data; + int status; +} op_closure; + +typedef struct { + op_closure *callbacks; + size_t count; + size_t capacity; +} op_closure_array; + struct transport { grpc_transport base; /* must be first */ const grpc_transport_callbacks *cb; @@ -202,6 +210,10 @@ struct transport { gpr_uint8 closed; error_state error_state; + /* queued callbacks */ + op_closure_array pending_callbacks; + op_closure_array executing_callbacks; + /* stream indexing */ gpr_uint32 next_stream_id; gpr_uint32 last_incoming_stream_id; @@ -289,6 +301,9 @@ struct stream { gpr_uint8 allow_window_updates; gpr_uint8 published_close; + op_closure send_done_closure; + op_closure recv_done_closure; + stream_link links[STREAM_LIST_COUNT]; gpr_uint8 included[STREAM_LIST_COUNT]; @@ -416,6 +431,8 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, GPR_ASSERT(strlen(CLIENT_CONNECT_STRING) == CLIENT_CONNECT_STRLEN); + memset(t, 0, sizeof(*t)); + t->base.vtable = &vtable; t->ep = ep; /* one ref is for destroy, the other for when ep becomes NULL */ @@ -427,27 +444,16 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, t->str_grpc_timeout = grpc_mdstr_from_string(t->metadata_context, "grpc-timeout"); t->reading = 1; - t->writing = 0; t->error_state = ERROR_STATE_NONE; t->next_stream_id = is_client ? 1 : 2; - t->last_incoming_stream_id = 0; - t->destroying = 0; - t->closed = 0; t->is_client = is_client; t->outgoing_window = DEFAULT_WINDOW; t->incoming_window = DEFAULT_WINDOW; t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; t->deframe_state = is_client ? DTS_FH_0 : DTS_CLIENT_PREFIX_0; - t->expect_continuation_stream_id = 0; - t->pings = NULL; - t->ping_count = 0; - t->ping_capacity = 0; t->ping_counter = gpr_now().tv_nsec; grpc_chttp2_hpack_compressor_init(&t->hpack_compressor, mdctx); grpc_chttp2_goaway_parser_init(&t->goaway_parser); - t->pending_goaways = NULL; - t->num_pending_goaways = 0; - t->cap_pending_goaways = 0; gpr_slice_buffer_init(&t->outbuf); gpr_slice_buffer_init(&t->qbuf); grpc_sopb_init(&t->nuke_later_sopb); @@ -462,7 +468,6 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, needed. TODO(ctiller): tune this */ grpc_chttp2_stream_map_init(&t->stream_map, 8); - memset(&t->lists, 0, sizeof(t->lists)); /* copy in initial settings to all setting sets */ for (i = 0; i < NUM_SETTING_SETS; i++) { @@ -708,8 +713,6 @@ static void stream_list_add_tail(transport *t, stream *s, stream_list_id id) { } static void stream_list_join(transport *t, stream *s, stream_list_id id) { - if (id == PENDING_CALLBACKS) - GPR_ASSERT(t->cb != NULL || t->error_state == ERROR_STATE_NONE); if (s->included[id]) { return; } @@ -988,6 +991,32 @@ static void maybe_start_some_streams(transport *t) { } } +static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *op) { + transport *t = (transport *)gt; + stream *s = (stream *)gs; + + lock(t); + + if (op->send_ops) { + abort(); + } + + if (op->recv_ops) { + abort(); + } + + if (op->bind_pollset) { + abort(); + } + + if (op->cancel_with_status) { + abort(); + } + + unlock(t); +} + +#if 0 static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops, size_t ops_count, int is_last) { transport *t = (transport *)gt; @@ -1016,6 +1045,7 @@ static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops, unlock(t); } +#endif static void abort_stream(grpc_transport *gt, grpc_stream *gs, grpc_status_code status) { @@ -1831,6 +1861,12 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed, } static int prepare_callbacks(transport *t) { + op_closure_array temp = t->pending_callbacks; + t->pending_callbacks = t->executing_callbacks; + t->executing_callbacks = temp; + return t->executing_callbacks.count > 0; + +#if 0 stream *s; int n = 0; while ((s = stream_list_remove_head(t, PENDING_CALLBACKS))) { @@ -1855,16 +1891,16 @@ static int prepare_callbacks(transport *t) { } } return n; +#endif } static void run_callbacks(transport *t, const grpc_transport_callbacks *cb) { - stream *s; - while ((s = stream_list_remove_head(t, EXECUTING_CALLBACKS))) { - size_t nops = s->callback_sopb.nops; - s->callback_sopb.nops = 0; - cb->recv_batch(t->cb_user_data, &t->base, (grpc_stream *)s, - s->callback_sopb.ops, nops, s->callback_state); + size_t i; + for (i = 0; i < t->executing_callbacks.count; i++) { + op_closure c = t->executing_callbacks.callbacks[i]; + c.cb(c.user_data, c.status); } + t->executing_callbacks.count = 0; } static void call_cb_closed(transport *t, const grpc_transport_callbacks *cb) { @@ -1885,8 +1921,8 @@ static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { */ static const grpc_transport_vtable vtable = { - sizeof(stream), init_stream, send_batch, set_allow_window_updates, - add_to_pollset, destroy_stream, abort_stream, goaway, close_transport, + sizeof(stream), init_stream, perform_op, + add_to_pollset, destroy_stream, goaway, close_transport, send_ping, destroy_transport}; void grpc_create_chttp2_transport(grpc_transport_setup_callback setup, diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 264245d351f..d0007680e3a 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -132,6 +132,9 @@ typedef struct grpc_transport_op { void grpc_transport_op_finish_with_failure(grpc_transport_op *op); +/* TODO(ctiller): remove this */ +void grpc_transport_add_to_pollset(grpc_transport *transport, grpc_pollset *pollset); + char *grpc_transport_op_string(grpc_transport_op *op); /* Send a batch of operations on a transport diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h index ac275c75606..ef79ac0741b 100644 --- a/src/core/transport/transport_impl.h +++ b/src/core/transport/transport_impl.h @@ -46,12 +46,8 @@ typedef struct grpc_transport_vtable { const void *server_data); /* implementation of grpc_transport_send_batch */ - void (*send_batch)(grpc_transport *self, grpc_stream *stream, - grpc_stream_op *ops, size_t ops_count, int is_last); - - /* implementation of grpc_transport_set_allow_window_updates */ - void (*set_allow_window_updates)(grpc_transport *self, grpc_stream *stream, - int allow); + void (*perform_op)(grpc_transport *self, grpc_stream *stream, + grpc_transport_op *op); /* implementation of grpc_transport_add_to_pollset */ void (*add_to_pollset)(grpc_transport *self, grpc_pollset *pollset); @@ -59,10 +55,6 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_destroy_stream */ void (*destroy_stream)(grpc_transport *self, grpc_stream *stream); - /* implementation of grpc_transport_abort_stream */ - void (*abort_stream)(grpc_transport *self, grpc_stream *stream, - grpc_status_code status); - /* implementation of grpc_transport_goaway */ void (*goaway)(grpc_transport *self, grpc_status_code status, gpr_slice debug_data); From c079c111cb953a8f2671be86bcfb6e77b5805e08 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 15:23:39 -0700 Subject: [PATCH 06/58] Transport compiles --- src/core/transport/chttp2_transport.c | 269 ++++++++++++++------------ 1 file changed, 145 insertions(+), 124 deletions(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 9aee7ca4f19..fed30887896 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -91,6 +91,9 @@ typedef enum { /* streams that are waiting to start because there are too many concurrent streams on the connection */ WAITING_FOR_CONCURRENCY, + /* streams that have finished reading: we wait until unlock to coalesce + all changes into one callback */ + FINISHED_READ_OP, STREAM_LIST_COUNT /* must be last */ } stream_list_id; @@ -137,6 +140,12 @@ typedef enum { DTS_FRAME } deframe_transport_state; +typedef enum { + WRITE_STATE_OPEN, + WRITE_STATE_QUEUED_CLOSE, + WRITE_STATE_SENT_CLOSE +} WRITE_STATE; + typedef struct { stream *head; stream *tail; @@ -181,7 +190,7 @@ typedef struct { typedef struct { void (*cb)(void *user_data, int success); void *user_data; - int status; + int success; } op_closure; typedef struct { @@ -293,12 +302,10 @@ struct stream { /* when the application requests writes be closed, the write_closed is 'queued'; when the close is flow controlled into the send path, we are 'sending' it; when the write has been performed it is 'sent' */ - gpr_uint8 queued_write_closed; - gpr_uint8 sending_write_closed; - gpr_uint8 sent_write_closed; + WRITE_STATE write_state; + gpr_uint8 send_closed; gpr_uint8 read_closed; gpr_uint8 cancelled; - gpr_uint8 allow_window_updates; gpr_uint8 published_close; op_closure send_done_closure; @@ -314,7 +321,10 @@ struct stream { gpr_timespec incoming_deadline; /* sops from application */ - grpc_stream_op_buffer outgoing_sopb; + grpc_stream_op_buffer *outgoing_sopb; + grpc_stream_op_buffer *incoming_sopb; + grpc_stream_state *publish_state; + grpc_stream_state published_state; /* sops that have passed flow control to be written */ grpc_stream_op_buffer writing_sopb; @@ -363,6 +373,13 @@ static void become_skip_parser(transport *t); static void recv_data(void *tp, gpr_slice *slices, size_t nslices, grpc_endpoint_cb_status error); +static void schedule_cb(transport *t, op_closure closure, int success); +static void maybe_finish_read(transport *t, stream *s); +static void maybe_join_window_updates(transport *t, stream *s); +static void finish_reads(transport *t); +static void add_to_pollset_locked(transport *t, grpc_pollset *pollset); + + /* * CONSTRUCTION/DESTRUCTION/REFCOUNTING */ @@ -582,6 +599,8 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, transport *t = (transport *)gt; stream *s = (stream *)gs; + memset(s, 0, sizeof(*s)); + ref_transport(t); if (!server_data) { @@ -597,20 +616,7 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; s->incoming_window = t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->queued_write_closed = 0; - s->sending_write_closed = 0; - s->sent_write_closed = 0; - s->read_closed = 0; - s->cancelled = 0; - s->allow_window_updates = 0; - s->published_close = 0; - s->incoming_metadata_count = 0; - s->incoming_metadata_capacity = 0; - s->incoming_metadata = NULL; s->incoming_deadline = gpr_inf_future; - memset(&s->links, 0, sizeof(s->links)); - memset(&s->included, 0, sizeof(s->included)); - grpc_sopb_init(&s->outgoing_sopb); grpc_sopb_init(&s->writing_sopb); grpc_sopb_init(&s->callback_sopb); grpc_chttp2_data_parser_init(&s->parser); @@ -647,7 +653,7 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { gpr_mu_unlock(&t->mu); - grpc_sopb_destroy(&s->outgoing_sopb); + GPR_ASSERT(s->outgoing_sopb == NULL); grpc_sopb_destroy(&s->writing_sopb); grpc_sopb_destroy(&s->callback_sopb); grpc_chttp2_data_parser_destroy(&s->parser); @@ -765,6 +771,8 @@ static void unlock(transport *t) { finalize_cancellations(t); } + finish_reads(t); + /* gather any callbacks that need to be made */ if (!t->calling_back && cb) { perform_callbacks = prepare_callbacks(t); @@ -868,22 +876,23 @@ static int prepare_write(transport *t) { while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE)) && s->outgoing_window > 0) { window_delta = grpc_chttp2_preencode( - s->outgoing_sopb.ops, &s->outgoing_sopb.nops, + s->outgoing_sopb->ops, &s->outgoing_sopb->nops, GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb); t->outgoing_window -= window_delta; s->outgoing_window -= window_delta; - s->sending_write_closed = - s->queued_write_closed && s->outgoing_sopb.nops == 0; - if (s->writing_sopb.nops > 0 || s->sending_write_closed) { + if (s->write_state == WRITE_STATE_QUEUED_CLOSE && s->outgoing_sopb->nops == 0) { + s->send_closed = 1; + } + if (s->writing_sopb.nops > 0 || s->send_closed) { stream_list_join(t, s, WRITING); } - /* if there are still writes to do and the stream still has window - available, then schedule a further write */ - if (s->outgoing_sopb.nops > 0 && s->outgoing_window > 0) { - GPR_ASSERT(!t->outgoing_window); - stream_list_add_tail(t, s, WRITABLE); + /* we should either exhaust window or have no ops left, but not both */ + GPR_ASSERT(s->outgoing_sopb->nops == 0 || s->outgoing_window <= 0); + if (s->outgoing_sopb->nops == 0) { + s->outgoing_sopb = NULL; + schedule_cb(t, s->send_done_closure, 1); } } @@ -915,10 +924,10 @@ static void finalize_outbuf(transport *t) { while ((s = stream_list_remove_head(t, WRITING))) { grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops, - s->sending_write_closed, s->id, &t->hpack_compressor, + s->send_closed, s->id, &t->hpack_compressor, &t->outbuf); s->writing_sopb.nops = 0; - if (s->sending_write_closed) { + if (s->send_closed) { stream_list_join(t, s, WRITTEN_CLOSED); } } @@ -932,8 +941,10 @@ static void finish_write_common(transport *t, int success) { drop_connection(t); } while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) { - s->sent_write_closed = 1; - if (!s->cancelled) stream_list_join(t, s, PENDING_CALLBACKS); + s->write_state = WRITE_STATE_SENT_CLOSE; + if (!s->cancelled) { + maybe_finish_read(t, s); + } } t->outbuf.count = 0; t->outbuf.length = 0; @@ -998,66 +1009,53 @@ static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *o lock(t); if (op->send_ops) { - abort(); + GPR_ASSERT(s->outgoing_sopb == NULL); + s->send_done_closure.cb = op->on_done_send; + s->send_done_closure.user_data = op->send_user_data; + if (!s->cancelled) { + s->outgoing_sopb = op->send_ops; + if (op->is_last_send && s->write_state == WRITE_STATE_OPEN) { + s->write_state = WRITE_STATE_QUEUED_CLOSE; + } + if (s->id == 0) { + stream_list_join(t, s, WAITING_FOR_CONCURRENCY); + maybe_start_some_streams(t); + } else if (s->outgoing_window > 0) { + stream_list_join(t, s, WRITABLE); + } + } else { + schedule_nuke_sopb(t, op->send_ops); + schedule_cb(t, s->send_done_closure, 0); + } } if (op->recv_ops) { - abort(); + GPR_ASSERT(s->incoming_sopb == NULL); + s->recv_done_closure.cb = op->on_done_recv; + s->recv_done_closure.user_data = op->recv_user_data; + if (!s->cancelled) { + s->incoming_sopb = op->recv_ops; + s->incoming_sopb->nops = 0; + s->publish_state = op->recv_state; + maybe_finish_read(t, s); + maybe_join_window_updates(t, s); + } else { + schedule_cb(t, s->recv_done_closure, 0); + } } if (op->bind_pollset) { - abort(); + add_to_pollset_locked(t, op->bind_pollset); } - if (op->cancel_with_status) { - abort(); + if (op->cancel_with_status != GRPC_STATUS_OK) { + cancel_stream(t, s, op->cancel_with_status, grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), + 1); } unlock(t); } -#if 0 -static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops, - size_t ops_count, int is_last) { - transport *t = (transport *)gt; - stream *s = (stream *)gs; - - lock(t); - - if (is_last) { - s->queued_write_closed = 1; - } - if (!s->cancelled) { - grpc_sopb_append(&s->outgoing_sopb, ops, ops_count); - if (s->id == 0) { - stream_list_join(t, s, WAITING_FOR_CONCURRENCY); - maybe_start_some_streams(t); - } else { - stream_list_join(t, s, WRITABLE); - } - } else { - grpc_sopb_append(&t->nuke_later_sopb, ops, ops_count); - } - if (is_last && s->outgoing_sopb.nops == 0 && s->read_closed && - !s->published_close) { - stream_list_join(t, s, PENDING_CALLBACKS); - } - - unlock(t); -} -#endif - -static void abort_stream(grpc_transport *gt, grpc_stream *gs, - grpc_status_code status) { - transport *t = (transport *)gt; - stream *s = (stream *)gs; - - lock(t); - cancel_stream(t, s, status, grpc_chttp2_grpc_status_to_http2_error(status), - 1); - unlock(t); -} - static void send_ping(grpc_transport *gt, void (*cb)(void *user_data), void *user_data) { transport *t = (transport *)gt; @@ -1093,8 +1091,8 @@ static void finalize_cancellations(transport *t) { while ((s = stream_list_remove_head(t, CANCELLED))) { s->read_closed = 1; - s->sent_write_closed = 1; - stream_list_join(t, s, PENDING_CALLBACKS); + s->write_state = WRITE_STATE_SENT_CLOSE; + maybe_finish_read(t, s); } } @@ -1118,12 +1116,15 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, if (s) { /* clear out any unreported input & output: nobody cares anymore */ - had_outgoing = s->outgoing_sopb.nops != 0; + had_outgoing = s->outgoing_sopb && s->outgoing_sopb->nops != 0; schedule_nuke_sopb(t, &s->parser.incoming_sopb); - schedule_nuke_sopb(t, &s->outgoing_sopb); + if (s->outgoing_sopb) { + schedule_nuke_sopb(t, s->outgoing_sopb); + schedule_cb(t, s->send_done_closure, 0); + } if (s->cancelled) { send_rst = 0; - } else if (!s->read_closed || !s->sent_write_closed || had_outgoing) { + } else if (!s->read_closed || s->write_state != WRITE_STATE_SENT_CLOSE || had_outgoing) { s->cancelled = 1; stream_list_join(t, s, CANCELLED); @@ -1141,7 +1142,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, break; } - stream_list_join(t, s, PENDING_CALLBACKS); + maybe_finish_read(t, s); } } if (!id) send_rst = 0; @@ -1180,8 +1181,14 @@ static void drop_connection(transport *t) { end_all_the_calls(t); } +static void maybe_finish_read(transport *t, stream *s) { + if (s->incoming_sopb) { + stream_list_join(t, s, FINISHED_READ_OP); + } +} + static void maybe_join_window_updates(transport *t, stream *s) { - if (s->allow_window_updates && + if (s->incoming_sopb != NULL && s->incoming_window < t->settings[LOCAL_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] * @@ -1190,6 +1197,7 @@ static void maybe_join_window_updates(transport *t, stream *s) { } } +#if 0 static void set_allow_window_updates(grpc_transport *tp, grpc_stream *sp, int allow) { transport *t = (transport *)tp; @@ -1204,6 +1212,7 @@ static void set_allow_window_updates(grpc_transport *tp, grpc_stream *sp, } unlock(t); } +#endif static grpc_chttp2_parse_error update_incoming_window(transport *t, stream *s) { if (t->incoming_frame_size > t->incoming_window) { @@ -1301,7 +1310,6 @@ static void on_header(void *tp, grpc_mdelem *md) { grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); - stream_list_join(t, s, PENDING_CALLBACKS); if (md->key == t->str_grpc_timeout) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); if (!cached_timeout) { @@ -1320,6 +1328,7 @@ static void on_header(void *tp, grpc_mdelem *md) { } else { add_incoming_metadata(t, s, md); } + maybe_finish_read(t, s); } static int init_header_frame_parser(transport *t, int is_continuation) { @@ -1531,14 +1540,14 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { case GRPC_CHTTP2_PARSE_OK: if (st.end_of_stream) { t->incoming_stream->read_closed = 1; - stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS); + maybe_finish_read(t, t->incoming_stream); } if (st.need_flush_reads) { - stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS); + maybe_finish_read(t, t->incoming_stream); } if (st.metadata_boundary) { add_metadata_batch(t, t->incoming_stream); - stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS); + maybe_finish_read(t, t->incoming_stream); } if (st.ack_settings) { gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create()); @@ -1579,7 +1588,7 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { int was_window_empty = s->outgoing_window <= 0; s->outgoing_window += st.initial_window_update; if (was_window_empty && s->outgoing_window > 0 && - s->outgoing_sopb.nops > 0) { + s->outgoing_sopb && s->outgoing_sopb->nops > 0) { stream_list_join(t, s, WRITABLE); } } @@ -1598,7 +1607,7 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { s->outgoing_window += st.window_update; /* if this window update makes outgoing ops writable again, flag that */ - if (was_window_empty && s->outgoing_sopb.nops) { + if (was_window_empty && s->outgoing_sopb && s->outgoing_sopb->nops > 0) { stream_list_join(t, s, WRITABLE); } } @@ -1860,45 +1869,49 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed, return GRPC_STREAM_OPEN; } +static void finish_reads(transport *t) { + stream *s; + + while ((s = stream_list_remove_head(t, FINISHED_READ_OP)) != NULL) { + int publish = 0; + GPR_ASSERT(s->incoming_sopb); + *s->publish_state = compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, + s->read_closed); + if (*s->publish_state != s->published_state) { + s->published_state = *s->publish_state; + publish = 1; + } + if (s->parser.incoming_sopb.nops > 0) { + grpc_sopb_swap(s->incoming_sopb, &s->parser.incoming_sopb); + publish = 1; + } + if (publish) { + schedule_cb(t, s->recv_done_closure, 1); + } + } +} + +static void schedule_cb(transport *t, op_closure closure, int success) { + if (t->pending_callbacks.capacity == t->pending_callbacks.count) { + t->pending_callbacks.capacity = GPR_MAX(t->pending_callbacks.capacity * 2, 8); + t->pending_callbacks.callbacks = gpr_realloc(t->pending_callbacks.callbacks, t->pending_callbacks.capacity * sizeof(*t->pending_callbacks.callbacks)); + } + closure.success = success; + t->pending_callbacks.callbacks[t->pending_callbacks.count++] = closure; +} + static int prepare_callbacks(transport *t) { op_closure_array temp = t->pending_callbacks; t->pending_callbacks = t->executing_callbacks; t->executing_callbacks = temp; return t->executing_callbacks.count > 0; - -#if 0 - stream *s; - int n = 0; - while ((s = stream_list_remove_head(t, PENDING_CALLBACKS))) { - int execute = 1; - - s->callback_state = compute_state(s->sent_write_closed, s->read_closed); - if (s->callback_state == GRPC_STREAM_CLOSED) { - remove_from_stream_map(t, s); - if (s->published_close) { - execute = 0; - } else if (s->incoming_metadata_count) { - add_metadata_batch(t, s); - } - s->published_close = 1; - } - - grpc_sopb_swap(&s->parser.incoming_sopb, &s->callback_sopb); - - if (execute) { - stream_list_add_tail(t, s, EXECUTING_CALLBACKS); - n = 1; - } - } - return n; -#endif } static void run_callbacks(transport *t, const grpc_transport_callbacks *cb) { size_t i; for (i = 0; i < t->executing_callbacks.count; i++) { op_closure c = t->executing_callbacks.callbacks[i]; - c.cb(c.user_data, c.status); + c.cb(c.user_data, c.success); } t->executing_callbacks.count = 0; } @@ -1907,12 +1920,20 @@ static void call_cb_closed(transport *t, const grpc_transport_callbacks *cb) { cb->closed(t->cb_user_data, &t->base); } -static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { - transport *t = (transport *)gt; - lock(t); +/* + * POLLSET STUFF + */ + +static void add_to_pollset_locked(transport *t, grpc_pollset *pollset) { if (t->ep) { grpc_endpoint_add_to_pollset(t->ep, pollset); } +} + +static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { + transport *t = (transport *)gt; + lock(t); + add_to_pollset_locked(t, pollset); unlock(t); } From fbf5be26a3ab98115eec118a9858b000dd9fc045 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 16:17:09 -0700 Subject: [PATCH 07/58] One test compiles --- src/core/surface/call.c | 36 +----- src/core/surface/channel.c | 4 + src/core/transport/chttp2_transport.c | 5 +- src/core/transport/stream_op.c | 14 +-- src/core/transport/stream_op.h | 6 +- src/core/transport/transport.c | 16 +-- src/core/transport/transport_op_string.c | 115 ++++++++++-------- .../end2end/fixtures/chttp2_socket_pair.c | 6 +- 8 files changed, 80 insertions(+), 122 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 7fcf6e2b04b..18be81308d8 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -283,6 +283,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, call->send_deadline = send_deadline; grpc_channel_internal_ref(channel); call->metadata_context = grpc_channel_get_metadata_context(channel); + grpc_sopb_init(&call->send_ops); + grpc_sopb_init(&call->recv_ops); /* one ref is dropped in response to destroy, the other in stream_closed */ gpr_ref_init(&call->internal_refcount, 2); @@ -330,6 +332,8 @@ static void destroy_call(void *call, int ignored_success) { destroy_legacy_state(c->legacy_state); } grpc_bbq_destroy(&c->incoming_queue); + grpc_sopb_destroy(&c->send_ops); + grpc_sopb_destroy(&c->recv_ops); gpr_free(c); } @@ -1091,41 +1095,9 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) { grpc_mdctx_unlock(mdctx); } -#if 0 -void grpc_call_read_closed(grpc_call_element *elem) { - set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED); -} - -void grpc_call_stream_closed(grpc_call_element *elem) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - set_read_state(call, READ_STATE_STREAM_CLOSED); - grpc_call_internal_unref(call, 0); -} - -void grpc_call_recv_message(grpc_call_element *elem, - grpc_byte_buffer *byte_buffer) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - lock(call); - grpc_bbq_push(&call->incoming_queue, byte_buffer); - finish_read_ops(call); - unlock(call); -} - -void grpc_call_recv_synthetic_status(grpc_call_element *elem, - grpc_status_code status, - const char *message) { - grpc_call *call = CALL_FROM_TOP_ELEM(elem); - lock(call); - set_status_code(call, STATUS_FROM_CORE, status); - set_status_details(call, STATUS_FROM_CORE, - grpc_mdstr_from_string(call->metadata_context, message)); - unlock(call); -} - grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) { return CALL_STACK_FROM_CALL(call); } -#endif /* * BATCH API IMPLEMENTATION diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index f1d71afaf27..de2f354c782 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -242,3 +242,7 @@ grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) { grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) { return channel->grpc_message_string; } + +gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) { + return channel->max_message_length; +} \ No newline at end of file diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index fed30887896..9c2af560c13 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1503,8 +1503,6 @@ static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) { return window + window_update < MAX_WINDOW; } -static void free_md(void *p, grpc_op_error result) { gpr_free(p); } - static void add_metadata_batch(transport *t, stream *s) { grpc_metadata_batch b; size_t i; @@ -1522,8 +1520,7 @@ static void add_metadata_batch(transport *t, stream *s) { s->incoming_metadata[s->incoming_metadata_count - 1].next = NULL; grpc_sopb_add_metadata(&s->parser.incoming_sopb, b); - grpc_sopb_add_flow_ctl_cb(&s->parser.incoming_sopb, free_md, - s->incoming_metadata); + /* TODO(ctiller): don't leak incoming_metadata */ /* reset */ s->incoming_deadline = gpr_inf_future; diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c index 882c078d512..ea22b0e1c82 100644 --- a/src/core/transport/stream_op.c +++ b/src/core/transport/stream_op.c @@ -81,9 +81,6 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) { case GRPC_OP_METADATA: grpc_metadata_batch_destroy(&ops[i].data.metadata); break; - case GRPC_OP_FLOW_CTL_CB: - ops[i].data.flow_ctl_cb.cb(ops[i].data.flow_ctl_cb.arg, GRPC_OP_ERROR); - break; case GRPC_NO_OP: case GRPC_OP_BEGIN_MESSAGE: break; @@ -119,6 +116,7 @@ static grpc_stream_op *add(grpc_stream_op_buffer *sopb) { assert_contained_metadata_ok(sopb->ops, sopb->nops); + GPR_ASSERT(sopb->nops <= sopb->capacity); if (sopb->nops == sopb->capacity) { expandto(sopb, GROW(sopb->capacity)); } @@ -158,16 +156,6 @@ void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) { assert_contained_metadata_ok(sopb->ops, sopb->nops); } -void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb, - void (*cb)(void *arg, grpc_op_error error), - void *arg) { - grpc_stream_op *op = add(sopb); - op->type = GRPC_OP_FLOW_CTL_CB; - op->data.flow_ctl_cb.cb = cb; - op->data.flow_ctl_cb.arg = arg; - assert_contained_metadata_ok(sopb->ops, sopb->nops); -} - void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops) { size_t orig_nops = sopb->nops; diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index c3901bf6088..f5de64d583a 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -154,12 +154,10 @@ void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch metadata); /* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */ void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice); -/* Append a GRPC_OP_FLOW_CTL_CB to a buffer */ -void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb, - void (*cb)(void *arg, grpc_op_error error), - void *arg); /* Append a buffer to a buffer - does not ref/unref any internal objects */ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t nops); +char *grpc_sopb_string(grpc_stream_op_buffer *sopb); + #endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */ diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index ef0020dc58b..35195348e70 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -56,14 +56,9 @@ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, return transport->vtable->init_stream(transport, stream, server_data); } -void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream, - grpc_stream_op *ops, size_t nops, int is_last) { - transport->vtable->send_batch(transport, stream, ops, nops, is_last); -} - -void grpc_transport_set_allow_window_updates(grpc_transport *transport, - grpc_stream *stream, int allow) { - transport->vtable->set_allow_window_updates(transport, stream, allow); +void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream, + grpc_transport_op *op) { + transport->vtable->perform_op(transport, stream, op); } void grpc_transport_add_to_pollset(grpc_transport *transport, @@ -76,11 +71,6 @@ void grpc_transport_destroy_stream(grpc_transport *transport, transport->vtable->destroy_stream(transport, stream); } -void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream, - grpc_status_code status) { - transport->vtable->abort_stream(transport, stream, status); -} - void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data), void *user_data) { transport->vtable->ping(transport, cb, user_data); diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index 5f7e1be2682..e886690234f 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -66,65 +66,76 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { } } -char *grpc_call_op_string(grpc_call_op *op) { +char *grpc_sopb_string(grpc_stream_op_buffer *sopb) { + char *out; + char *tmp; + size_t i; + gpr_strvec b; + gpr_strvec_init(&b); + + for (i = 0; i < sopb->nops; i++) { + grpc_stream_op *op = &sopb->ops[i]; + if (i) gpr_strvec_add(&b, gpr_strdup(", ")); + switch (op->type) { + case GRPC_NO_OP: + gpr_strvec_add(&b, gpr_strdup("NO_OP")); + break; + case GRPC_OP_BEGIN_MESSAGE: + gpr_asprintf(&tmp, "BEGIN_MESSAGE:%d", op->data.begin_message.length); + gpr_strvec_add(&b, tmp); + break; + case GRPC_OP_SLICE: + gpr_asprintf(&tmp, "SLICE:%d", GPR_SLICE_LENGTH(op->data.slice)); + break; + case GRPC_OP_METADATA: + put_metadata_list(&b, op->data.metadata); + break; + } + } + + out = gpr_strvec_flatten(&b, NULL); + gpr_strvec_destroy(&b); + + return out; +} + +char *grpc_transport_op_string(grpc_transport_op *op) { char *tmp; char *out; + int first = 1; gpr_strvec b; gpr_strvec_init(&b); - switch (op->dir) { - case GRPC_CALL_DOWN: - gpr_strvec_add(&b, gpr_strdup(">")); - break; - case GRPC_CALL_UP: - gpr_strvec_add(&b, gpr_strdup("<")); - break; + if (op->send_ops) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("SEND")); + if (op->is_last_send) { + gpr_strvec_add(&b, gpr_strdup("_LAST")); + } + gpr_strvec_add(&b, gpr_strdup("[")); + gpr_strvec_add(&b, grpc_sopb_string(op->send_ops)); + gpr_strvec_add(&b, gpr_strdup("]")); } - switch (op->type) { - case GRPC_SEND_METADATA: - gpr_strvec_add(&b, gpr_strdup("SEND_METADATA")); - put_metadata_list(&b, op->data.metadata); - break; - case GRPC_SEND_MESSAGE: - gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE")); - break; - case GRPC_SEND_PREFORMATTED_MESSAGE: - gpr_strvec_add(&b, gpr_strdup("SEND_PREFORMATTED_MESSAGE")); - break; - case GRPC_SEND_FINISH: - gpr_strvec_add(&b, gpr_strdup("SEND_FINISH")); - break; - case GRPC_REQUEST_DATA: - gpr_strvec_add(&b, gpr_strdup("REQUEST_DATA")); - break; - case GRPC_RECV_METADATA: - gpr_strvec_add(&b, gpr_strdup("RECV_METADATA")); - put_metadata_list(&b, op->data.metadata); - break; - case GRPC_RECV_MESSAGE: - gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); - break; - case GRPC_RECV_HALF_CLOSE: - gpr_strvec_add(&b, gpr_strdup("RECV_HALF_CLOSE")); - break; - case GRPC_RECV_FINISH: - gpr_strvec_add(&b, gpr_strdup("RECV_FINISH")); - break; - case GRPC_RECV_SYNTHETIC_STATUS: - gpr_asprintf(&tmp, "RECV_SYNTHETIC_STATUS status=%d message='%s'", - op->data.synthetic_status.status, - op->data.synthetic_status.message); - gpr_strvec_add(&b, tmp); - break; - case GRPC_CANCEL_OP: - gpr_strvec_add(&b, gpr_strdup("CANCEL_OP")); - break; + + if (op->recv_ops) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("RECV")); } - gpr_asprintf(&tmp, " flags=0x%08x", op->flags); - gpr_strvec_add(&b, tmp); + if (op->bind_pollset) { - gpr_strvec_add(&b, gpr_strdup("bind_pollset")); + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_strvec_add(&b, gpr_strdup("BIND")); + } + + if (op->cancel_with_status != GRPC_STATUS_OK) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = 0; + gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); + gpr_strvec_add(&b, tmp); } out = gpr_strvec_flatten(&b, NULL); @@ -134,8 +145,8 @@ char *grpc_call_op_string(grpc_call_op *op) { } void grpc_call_log_op(char *file, int line, gpr_log_severity severity, - grpc_call_element *elem, grpc_call_op *op) { - char *str = grpc_call_op_string(op); + grpc_call_element *elem, grpc_transport_op *op) { + char *str = grpc_transport_op_string(op); gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str); gpr_free(str); } diff --git a/test/core/end2end/fixtures/chttp2_socket_pair.c b/test/core/end2end/fixtures/chttp2_socket_pair.c index 1225f7db0c2..acc0a69708a 100644 --- a/test/core/end2end/fixtures/chttp2_socket_pair.c +++ b/test/core/end2end/fixtures/chttp2_socket_pair.c @@ -37,7 +37,6 @@ #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_client_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/endpoint_pair.h" @@ -60,8 +59,7 @@ static grpc_transport_setup_result server_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { grpc_end2end_test_fixture *f = ts; - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter, - &grpc_http_filter}; + static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; return grpc_server_setup_transport(f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } @@ -76,7 +74,7 @@ static grpc_transport_setup_result client_setup_transport( sp_client_setup *cs = ts; const grpc_channel_filter *filters[] = { - &grpc_client_surface_filter, &grpc_http_client_filter, &grpc_http_filter, + &grpc_client_surface_filter, &grpc_http_client_filter, &grpc_connected_channel_filter}; size_t nfilters = sizeof(filters) / sizeof(*filters); grpc_channel *channel = grpc_channel_create_from_filters( From 09b49d7c68afe586ca41ea6706a5d1b620889007 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 16:40:23 -0700 Subject: [PATCH 08/58] Add newline --- src/core/surface/channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index de2f354c782..78f9144c19c 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -245,4 +245,4 @@ grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) { gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) { return channel->max_message_length; -} \ No newline at end of file +} From e5cb23ba550878c2e562cd2df9ba0d857da63667 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Apr 2015 16:58:37 -0700 Subject: [PATCH 09/58] Fix accidental delete --- src/core/transport/chttp2/stream_encoder.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c index 203de993143..9b62aefd0be 100644 --- a/src/core/transport/chttp2/stream_encoder.c +++ b/src/core/transport/chttp2/stream_encoder.c @@ -481,6 +481,11 @@ gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count, break; case GRPC_OP_METADATA: grpc_metadata_batch_assert_ok(&op->data.metadata); + /* these just get copied as they don't impact the number of flow + controlled bytes */ + grpc_sopb_append(outops, op, 1); + curop++; + break; case GRPC_OP_BEGIN_MESSAGE: /* begin op: for now we just convert the op to a slice and fall through - this lets us reuse the slice framing code below */ From 3f2c2214b718ee61ddfd52efe922e652535aa537 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 07:56:33 -0700 Subject: [PATCH 10/58] Fiddling with an initial op --- src/core/channel/census_filter.c | 30 +++++++++++++--------- src/core/channel/channel_stack.c | 3 ++- src/core/channel/channel_stack.h | 4 ++- src/core/channel/child_channel.c | 6 ++--- src/core/channel/child_channel.h | 2 +- src/core/channel/client_channel.c | 3 ++- src/core/channel/connected_channel.c | 7 +++--- src/core/transport/chttp2_transport.c | 1 + src/core/transport/transport.h | 36 +++++++++++++-------------- 9 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c index 3e0fc39fc9a..47461f7f2b3 100644 --- a/src/core/channel/census_filter.c +++ b/src/core/channel/census_filter.c @@ -82,15 +82,18 @@ static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb, call_da } } -static void client_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { +static void client_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; - GPR_ASSERT(calld != NULL); - GPR_ASSERT(chand != NULL); - GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); if (op->send_ops) { extract_and_annotate_method_tag(op->send_ops, calld, chand); } +} + +static void client_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { + call_data* calld = elem->call_data; + GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); + client_mutate_op(elem, op); grpc_call_next_op(elem, op); } @@ -104,12 +107,8 @@ static void server_on_done_recv(void *ptr, int success) { calld->on_done_recv(calld->recv_user_data, success); } -static void server_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { +static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { call_data* calld = elem->call_data; - channel_data* chand = elem->channel_data; - GPR_ASSERT(calld != NULL); - GPR_ASSERT(chand != NULL); - GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); if (op->recv_ops) { /* substitute our callback for the op callback */ calld->recv_ops = op->recv_ops; @@ -118,7 +117,12 @@ static void server_start_transport_op(grpc_call_element* elem, grpc_transport_op op->on_done_recv = server_on_done_recv; op->recv_user_data = elem; } - /* Always pass control up or down the stack depending on op->dir */ +} + +static void server_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { + call_data* calld = elem->call_data; + GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); + server_mutate_op(elem, op); grpc_call_next_op(elem, op); } @@ -136,12 +140,13 @@ static void channel_op(grpc_channel_element* elem, } static void client_init_call_elem(grpc_call_element* elem, - const void* server_transport_data) { + const void* server_transport_data, grpc_transport_op *initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); init_rpc_stats(&d->stats); d->start_ts = gpr_now(); d->op_id = census_tracing_start_op(); + if (initial_op) client_mutate_op(elem, initial_op); } static void client_destroy_call_elem(grpc_call_element* elem) { @@ -152,12 +157,13 @@ static void client_destroy_call_elem(grpc_call_element* elem) { } static void server_init_call_elem(grpc_call_element* elem, - const void* server_transport_data) { + const void* server_transport_data, grpc_transport_op *initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); init_rpc_stats(&d->stats); d->start_ts = gpr_now(); d->op_id = census_tracing_start_op(); + if (initial_op) server_mutate_op(elem, initial_op); } static void server_destroy_call_elem(grpc_call_element* elem) { diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index c121e270056..022100e8bd7 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -148,6 +148,7 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack) { void grpc_call_stack_init(grpc_channel_stack *channel_stack, const void *transport_server_data, + grpc_transport_op *initial_op, grpc_call_stack *call_stack) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); size_t count = channel_stack->count; @@ -165,7 +166,7 @@ void grpc_call_stack_init(grpc_channel_stack *channel_stack, call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].call_data = user_data; - call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data); + call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data, initial_op); user_data += ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); } diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index 75897ff6516..94b12639fc8 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -121,7 +121,8 @@ typedef struct { transport and is on the server. Most filters want to ignore this argument.*/ void (*init_call_elem)(grpc_call_element *elem, - const void *server_transport_data); + const void *server_transport_data, + grpc_transport_op *initial_op); /* Destroy per call data. The filter does not need to do any chaining */ void (*destroy_call_elem)(grpc_call_element *elem); @@ -200,6 +201,7 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack); server. */ void grpc_call_stack_init(grpc_channel_stack *channel_stack, const void *transport_server_data, + grpc_transport_op *initial_op, grpc_call_stack *call_stack); /* Destroy a call stack */ void grpc_call_stack_destroy(grpc_call_stack *stack); diff --git a/src/core/channel/child_channel.c b/src/core/channel/child_channel.c index 244417384a7..817a2a8c70a 100644 --- a/src/core/channel/child_channel.c +++ b/src/core/channel/child_channel.c @@ -121,7 +121,7 @@ static void lb_channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void lb_init_call_elem(grpc_call_element *elem, - const void *server_transport_data) {} + const void *server_transport_data, grpc_transport_op *initial_op) {} /* Destructor for call_data */ static void lb_destroy_call_elem(grpc_call_element *elem) {} @@ -261,13 +261,13 @@ void grpc_child_channel_handle_op(grpc_child_channel *channel, } grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, - grpc_call_element *parent) { + grpc_call_element *parent, grpc_transport_op *initial_op) { grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size); grpc_call_element *lbelem; lb_call_data *lbcalld; lb_channel_data *lbchand; - grpc_call_stack_init(channel, NULL, stk); + grpc_call_stack_init(channel, NULL, initial_op, stk); lbelem = LINK_BACK_ELEM_FROM_CALL(stk); lbchand = lbelem->channel_data; lbcalld = lbelem->call_data; diff --git a/src/core/channel/child_channel.h b/src/core/channel/child_channel.h index 38695402ab0..264a8bbb826 100644 --- a/src/core/channel/child_channel.h +++ b/src/core/channel/child_channel.h @@ -57,7 +57,7 @@ void grpc_child_channel_destroy(grpc_child_channel *channel, int wait_for_callbacks); grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, - grpc_call_element *parent); + grpc_call_element *parent, grpc_transport_op *initial_op); grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call); void grpc_child_call_destroy(grpc_child_call *call); diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 6ad50cb9448..e6b0f7bba8f 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -105,7 +105,8 @@ static int prepare_activate(grpc_call_element *elem, calld->state = CALL_ACTIVE; /* create a child call */ - calld->s.active.child_call = grpc_child_channel_create_call(on_child, elem); + /* TODO(ctiller): pass the waiting op down here */ + calld->s.active.child_call = grpc_child_channel_create_call(on_child, elem, NULL); return 1; } diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 9e2d92ffbc2..5a5a8499072 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -95,15 +95,16 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, + grpc_transport_op *initial_op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; int r; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); - r = grpc_transport_init_stream(chand->transport, + r = grpc_transport_1chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), - server_transport_data); + server_transport_data, initial_op); GPR_ASSERT(r == 0); } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 9c2af560c13..acdc98b86b4 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -607,6 +607,7 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, lock(t); s->id = 0; } else { + /* already locked */ s->id = (gpr_uint32)(gpr_uintptr)server_data; t->incoming_stream = s; grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index d0007680e3a..a51e01d3c96 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -60,6 +60,23 @@ typedef enum grpc_stream_state { GRPC_STREAM_CLOSED } grpc_stream_state; +/* Transport op: a set of operations to perform on a transport */ +typedef struct grpc_transport_op { + grpc_stream_op_buffer *send_ops; + int is_last_send; + void (*on_done_send)(void *user_data, int success); + void *send_user_data; + + grpc_stream_op_buffer *recv_ops; + grpc_stream_state *recv_state; + void (*on_done_recv)(void *user_data, int success); + void *recv_user_data; + + grpc_pollset *bind_pollset; + + grpc_status_code cancel_with_status; +} grpc_transport_op; + /* Callbacks made from the transport to the upper layers of grpc. */ struct grpc_transport_callbacks { /* Initialize a new stream on behalf of the transport. @@ -98,7 +115,7 @@ size_t grpc_transport_stream_size(grpc_transport *transport); server_data - either NULL for a client initiated stream, or a pointer supplied from the accept_stream callback function */ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, - const void *server_data); + const void *server_data, grpc_transport_op *initial_op); /* Destroy transport data for a stream. @@ -113,23 +130,6 @@ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, void grpc_transport_destroy_stream(grpc_transport *transport, grpc_stream *stream); -/* Transport op: a set of operations to perform on a transport */ -typedef struct grpc_transport_op { - grpc_stream_op_buffer *send_ops; - int is_last_send; - void (*on_done_send)(void *user_data, int success); - void *send_user_data; - - grpc_stream_op_buffer *recv_ops; - grpc_stream_state *recv_state; - void (*on_done_recv)(void *user_data, int success); - void *recv_user_data; - - grpc_pollset *bind_pollset; - - grpc_status_code cancel_with_status; -} grpc_transport_op; - void grpc_transport_op_finish_with_failure(grpc_transport_op *op); /* TODO(ctiller): remove this */ From 50d9db534c202a2a473d7b5d54f105174ec7f727 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 10:52:14 -0700 Subject: [PATCH 11/58] Flesh out initial_op --- src/core/channel/client_channel.c | 5 ++- src/core/channel/connected_channel.c | 2 +- src/core/channel/http_client_filter.c | 12 ++++-- src/core/channel/http_server_filter.c | 59 ++++----------------------- src/core/channel/noop_filter.c | 22 ++++++---- src/core/surface/call.c | 2 +- src/core/surface/client.c | 2 +- src/core/surface/lame_client.c | 6 ++- src/core/surface/server.c | 11 +++-- src/core/transport/chttp2_transport.c | 20 +++++---- src/core/transport/transport.c | 4 +- src/core/transport/transport_impl.h | 2 +- 12 files changed, 65 insertions(+), 82 deletions(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index e6b0f7bba8f..77c49510382 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -325,9 +325,12 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { call_data *calld = elem->call_data; + /* TODO(ctiller): is there something useful we can do here? */ + GPR_ASSERT(initial_op == NULL); + GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GPR_ASSERT(server_transport_data == NULL); calld->elem = elem; diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 5a5a8499072..9b7db6124a1 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -102,7 +102,7 @@ static void init_call_elem(grpc_call_element *elem, int r; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); - r = grpc_transport_1chand->transport, + r = grpc_transport_init_stream(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), server_transport_data, initial_op); GPR_ASSERT(r == 0); diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index 72874084017..45a74363619 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -87,13 +87,11 @@ static void hc_on_recv(void *user_data, int success) { calld->on_done_recv(calld->recv_user_data, success); } -static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; size_t i; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - if (op->send_ops && !calld->sent_initial_metadata) { size_t nops = op->send_ops->nops; grpc_stream_op *ops = op->send_ops->ops; @@ -123,7 +121,11 @@ static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_op *op op->on_done_recv = hc_on_recv; op->recv_user_data = elem; } +} +static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + hc_mutate_op(elem, op); grpc_call_next_op(elem, op); } @@ -146,10 +148,12 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, + grpc_transport_op *initial_op) { call_data *calld = elem->call_data; calld->sent_initial_metadata = 0; calld->got_initial_metadata = 0; + if (initial_op) hc_mutate_op(elem, initial_op); } /* Destructor for call_data */ diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index 31ed8a33930..e5174acd681 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -38,12 +38,6 @@ #include #include -typedef struct { - grpc_mdelem *path; - grpc_mdelem *content_type; - grpc_byte_buffer *content; -} gettable; - typedef struct call_data { gpr_uint8 got_initial_metadata; gpr_uint8 seen_path; @@ -73,9 +67,6 @@ typedef struct channel_data { grpc_mdstr *host_key; grpc_mdctx *mdctx; - - size_t gettable_count; - gettable *gettables; } channel_data; /* used to silence 'variable not used' warnings */ @@ -187,12 +178,11 @@ static void hs_on_recv(void *user_data, int success) { calld->on_done_recv(calld->recv_user_data, success); } -static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; size_t i; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); if (op->send_ops && !calld->sent_status) { size_t nops = op->send_ops->nops; @@ -215,7 +205,11 @@ static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_op *op op->on_done_recv = hs_on_recv; op->recv_user_data = elem; } +} +static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + hs_mutate_op(elem, op); grpc_call_next_op(elem, op); } @@ -238,15 +232,12 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; - channel_data *channeld = elem->channel_data; - - ignore_unused(channeld); - /* initialize members */ memset(calld, 0, sizeof(*calld)); + if (initial_op) hs_mutate_op(elem, initial_op); } /* Destructor for call_data */ @@ -256,9 +247,6 @@ static void destroy_call_elem(grpc_call_element *elem) {} static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { - size_t i; - size_t gettable_capacity = 0; - /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; @@ -284,46 +272,13 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc"); channeld->mdctx = mdctx; - - /* initialize http download support */ - channeld->gettable_count = 0; - channeld->gettables = NULL; - for (i = 0; i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_SERVE_OVER_HTTP)) { - gettable *g; - gpr_slice slice; - grpc_http_server_page *p = args->args[i].value.pointer.p; - if (channeld->gettable_count == gettable_capacity) { - gettable_capacity = - GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1); - channeld->gettables = gpr_realloc(channeld->gettables, - gettable_capacity * sizeof(gettable)); - } - g = &channeld->gettables[channeld->gettable_count++]; - g->path = grpc_mdelem_from_strings(mdctx, ":path", p->path); - g->content_type = - grpc_mdelem_from_strings(mdctx, "content-type", p->content_type); - slice = gpr_slice_from_copied_string(p->content); - g->content = grpc_byte_buffer_create(&slice, 1); - gpr_slice_unref(slice); - } - } } /* Destructor for channel data */ static void destroy_channel_elem(grpc_channel_element *elem) { - size_t i; - /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; - for (i = 0; i < channeld->gettable_count; i++) { - grpc_mdelem_unref(channeld->gettables[i].path); - grpc_mdelem_unref(channeld->gettables[i].content_type); - grpc_byte_buffer_destroy(channeld->gettables[i].content); - } - gpr_free(channeld->gettables); - grpc_mdelem_unref(channeld->te_trailers); grpc_mdelem_unref(channeld->status_ok); grpc_mdelem_unref(channeld->status_not_found); diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c index 403b60901bf..62e57ce285d 100644 --- a/src/core/channel/noop_filter.c +++ b/src/core/channel/noop_filter.c @@ -45,12 +45,7 @@ typedef struct channel_data { /* used to silence 'variable not used' warnings */ static void ignore_unused(void *ignored) {} -/* Called either: - - in response to an API call (or similar) from above, to send something - - a network event (or similar) from below, to receive something - op contains type and call direction information, in addition to the data - that is being sent or received. */ -static void noop_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -58,6 +53,17 @@ static void noop_start_transport_op(grpc_call_element *elem, grpc_transport_op * ignore_unused(calld); ignore_unused(channeld); + /* do nothing */ +} + +/* Called either: + - in response to an API call (or similar) from above, to send something + - a network event (or similar) from below, to receive something + op contains type and call direction information, in addition to the data + that is being sent or received. */ +static void noop_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + noop_mutate_op(elem, op); + /* pass control down the stack */ grpc_call_next_op(elem, op); } @@ -81,13 +87,15 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; /* initialize members */ calld->unused = channeld->unused; + + if (initial_op) noop_mutate_op(elem, initial_op); } /* Destructor for call_data */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 18be81308d8..c39e6cf3a42 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -288,7 +288,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, /* one ref is dropped in response to destroy, the other in stream_closed */ gpr_ref_init(&call->internal_refcount, 2); - grpc_call_stack_init(channel_stack, server_transport_data, + grpc_call_stack_init(channel_stack, server_transport_data, NULL, CALL_STACK_FROM_CALL(call)); if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) { set_deadline_alarm(call, send_deadline); diff --git a/src/core/surface/client.c b/src/core/surface/client.c index 4669c59ee4b..7eb99895f72 100644 --- a/src/core/surface/client.c +++ b/src/core/surface/client.c @@ -67,7 +67,7 @@ static void channel_op(grpc_channel_element *elem, } static void init_call_elem(grpc_call_element *elem, - const void *transport_server_data) {} + const void *transport_server_data, grpc_transport_op *initial_op) {} static void destroy_call_elem(grpc_call_element *elem) {} diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index 4e9eb808d78..f95e2a16c29 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -66,7 +66,11 @@ static void channel_op(grpc_channel_element *elem, } static void init_call_elem(grpc_call_element *elem, - const void *transport_server_data) {} + const void *transport_server_data, grpc_transport_op *initial_op) { + if (initial_op) { + grpc_transport_op_finish_with_failure(initial_op); + } +} static void destroy_call_elem(grpc_call_element *elem) {} diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 82d1323a4b1..e9d6f86734b 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -439,9 +439,8 @@ static void server_on_recv(void *ptr, int success) { calld->on_done_recv(calld->recv_user_data, success); } -static void server_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); if (op->recv_ops) { /* substitute our callback for the higher callback */ @@ -452,7 +451,11 @@ static void server_start_transport_op(grpc_call_element *elem, grpc_transport_op op->on_done_recv = server_on_recv; op->recv_user_data = elem; } +} +static void server_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + server_mutate_op(elem, op); grpc_call_next_op(elem, op); } @@ -504,7 +507,7 @@ static void shutdown_channel(channel_data *chand) { } static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; memset(calld, 0, sizeof(call_data)); @@ -516,6 +519,8 @@ static void init_call_elem(grpc_call_element *elem, gpr_mu_unlock(&chand->server->mu); server_ref(chand->server); + + server_mutate_op(elem, initial_op); } static void destroy_call_elem(grpc_call_element *elem) { diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index acdc98b86b4..d7156142fb8 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -378,7 +378,7 @@ static void maybe_finish_read(transport *t, stream *s); static void maybe_join_window_updates(transport *t, stream *s); static void finish_reads(transport *t); static void add_to_pollset_locked(transport *t, grpc_pollset *pollset); - +static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op); /* * CONSTRUCTION/DESTRUCTION/REFCOUNTING @@ -595,7 +595,7 @@ static void goaway(grpc_transport *gt, grpc_status_code status, } static int init_stream(grpc_transport *gt, grpc_stream *gs, - const void *server_data) { + const void *server_data, grpc_transport_op *initial_op) { transport *t = (transport *)gt; stream *s = (stream *)gs; @@ -622,6 +622,8 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, grpc_sopb_init(&s->callback_sopb); grpc_chttp2_data_parser_init(&s->parser); + if (initial_op) perform_op_locked(t, s, initial_op); + if (!server_data) { unlock(t); } @@ -1003,12 +1005,7 @@ static void maybe_start_some_streams(transport *t) { } } -static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *op) { - transport *t = (transport *)gt; - stream *s = (stream *)gs; - - lock(t); - +static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { if (op->send_ops) { GPR_ASSERT(s->outgoing_sopb == NULL); s->send_done_closure.cb = op->on_done_send; @@ -1053,7 +1050,14 @@ static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *o cancel_stream(t, s, op->cancel_with_status, grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), 1); } +} +static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *op) { + transport *t = (transport *)gt; + stream *s = (stream *)gs; + + lock(t); + perform_op_locked(t, s, op); unlock(t); } diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index 35195348e70..ab2f7c34705 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -52,8 +52,8 @@ void grpc_transport_destroy(grpc_transport *transport) { } int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, - const void *server_data) { - return transport->vtable->init_stream(transport, stream, server_data); + const void *server_data, grpc_transport_op *initial_op) { + return transport->vtable->init_stream(transport, stream, server_data, initial_op); } void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream, diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h index ef79ac0741b..75d8d51e20d 100644 --- a/src/core/transport/transport_impl.h +++ b/src/core/transport/transport_impl.h @@ -43,7 +43,7 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_init_stream */ int (*init_stream)(grpc_transport *self, grpc_stream *stream, - const void *server_data); + const void *server_data, grpc_transport_op *initial_op); /* implementation of grpc_transport_send_batch */ void (*perform_op)(grpc_transport *self, grpc_stream *stream, From 06aeea7e9440cccd019c910cb68e306063d28632 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 10:54:45 -0700 Subject: [PATCH 12/58] clang-format --- src/core/channel/census_filter.c | 50 +++++++++++-------- src/core/channel/channel_stack.c | 3 +- src/core/channel/child_channel.c | 20 ++++---- src/core/channel/child_channel.h | 5 +- src/core/channel/client_channel.c | 20 ++++---- src/core/channel/connected_channel.c | 18 +++---- src/core/channel/http_client_filter.c | 9 ++-- src/core/channel/http_server_filter.c | 12 +++-- src/core/channel/noop_filter.c | 12 +++-- src/core/surface/channel.h | 2 +- src/core/surface/channel_create.c | 3 +- src/core/surface/client.c | 11 ++-- src/core/surface/lame_client.c | 12 +++-- src/core/surface/server.c | 17 ++++--- src/core/surface/server_chttp2.c | 3 +- src/core/transport/chttp2/stream_encoder.c | 8 +-- src/core/transport/chttp2_transport.c | 48 ++++++++++-------- src/core/transport/stream_op.h | 29 ++++++----- src/core/transport/transport.c | 6 ++- src/core/transport/transport.h | 11 ++-- src/core/transport/transport_impl.h | 2 +- .../end2end/fixtures/chttp2_socket_pair.c | 9 ++-- 22 files changed, 177 insertions(+), 133 deletions(-) diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c index 47461f7f2b3..7e393a01a6a 100644 --- a/src/core/channel/census_filter.c +++ b/src/core/channel/census_filter.c @@ -51,9 +51,9 @@ typedef struct call_data { gpr_timespec start_ts; /* recv callback */ - grpc_stream_op_buffer *recv_ops; - void (*on_done_recv)(void *user_data, int success); - void *recv_user_data; + grpc_stream_op_buffer* recv_ops; + void (*on_done_recv)(void* user_data, int success); + void* recv_user_data; } call_data; typedef struct channel_data { @@ -65,24 +65,26 @@ static void init_rpc_stats(census_rpc_stats* stats) { stats->cnt = 1; } -static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb, call_data* calld, +static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb, + call_data* calld, channel_data* chand) { grpc_linked_mdelem* m; size_t i; for (i = 0; i < sopb->nops; i++) { - grpc_stream_op * op = &sopb->ops[i]; + grpc_stream_op* op = &sopb->ops[i]; if (op->type != GRPC_OP_METADATA) continue; for (m = op->data.metadata.list.head; m != NULL; m = m->next) { if (m->md->key == chand->path_str) { - gpr_log(GPR_DEBUG, "%s", (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); - census_add_method_tag( - calld->op_id, (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + gpr_log(GPR_DEBUG, "%s", + (const char*)GPR_SLICE_START_PTR(m->md->value->slice)); + census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR( + m->md->value->slice)); } } } } -static void client_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { +static void client_mutate_op(grpc_call_element* elem, grpc_transport_op* op) { call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; if (op->send_ops) { @@ -90,15 +92,16 @@ static void client_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { } } -static void client_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { +static void client_start_transport_op(grpc_call_element* elem, + grpc_transport_op* op) { call_data* calld = elem->call_data; GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); client_mutate_op(elem, op); grpc_call_next_op(elem, op); } -static void server_on_done_recv(void *ptr, int success) { - grpc_call_element *elem = ptr; +static void server_on_done_recv(void* ptr, int success) { + grpc_call_element* elem = ptr; call_data* calld = elem->call_data; channel_data* chand = elem->channel_data; if (success) { @@ -107,7 +110,7 @@ static void server_on_done_recv(void *ptr, int success) { calld->on_done_recv(calld->recv_user_data, success); } -static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { +static void server_mutate_op(grpc_call_element* elem, grpc_transport_op* op) { call_data* calld = elem->call_data; if (op->recv_ops) { /* substitute our callback for the op callback */ @@ -119,7 +122,8 @@ static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { } } -static void server_start_transport_op(grpc_call_element* elem, grpc_transport_op* op) { +static void server_start_transport_op(grpc_call_element* elem, + grpc_transport_op* op) { call_data* calld = elem->call_data; GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); server_mutate_op(elem, op); @@ -140,7 +144,8 @@ static void channel_op(grpc_channel_element* elem, } static void client_init_call_elem(grpc_call_element* elem, - const void* server_transport_data, grpc_transport_op *initial_op) { + const void* server_transport_data, + grpc_transport_op* initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); init_rpc_stats(&d->stats); @@ -157,7 +162,8 @@ static void client_destroy_call_elem(grpc_call_element* elem) { } static void server_init_call_elem(grpc_call_element* elem, - const void* server_transport_data, grpc_transport_op *initial_op) { + const void* server_transport_data, + grpc_transport_op* initial_op) { call_data* d = elem->call_data; GPR_ASSERT(d != NULL); init_rpc_stats(&d->stats); @@ -194,11 +200,11 @@ static void destroy_channel_elem(grpc_channel_element* elem) { } const grpc_channel_filter grpc_client_census_filter = { - client_start_transport_op, channel_op, sizeof(call_data), client_init_call_elem, - client_destroy_call_elem, sizeof(channel_data), init_channel_elem, - destroy_channel_elem, "census-client"}; + client_start_transport_op, channel_op, sizeof(call_data), + client_init_call_elem, client_destroy_call_elem, sizeof(channel_data), + init_channel_elem, destroy_channel_elem, "census-client"}; const grpc_channel_filter grpc_server_census_filter = { - server_start_transport_op, channel_op, sizeof(call_data), server_init_call_elem, - server_destroy_call_elem, sizeof(channel_data), init_channel_elem, - destroy_channel_elem, "census-server"}; + server_start_transport_op, channel_op, sizeof(call_data), + server_init_call_elem, server_destroy_call_elem, sizeof(channel_data), + init_channel_elem, destroy_channel_elem, "census-server"}; diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c index 022100e8bd7..311f4f08ce6 100644 --- a/src/core/channel/channel_stack.c +++ b/src/core/channel/channel_stack.c @@ -166,7 +166,8 @@ void grpc_call_stack_init(grpc_channel_stack *channel_stack, call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; call_elems[i].call_data = user_data; - call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data, initial_op); + call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data, + initial_op); user_data += ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data); } diff --git a/src/core/channel/child_channel.c b/src/core/channel/child_channel.c index 817a2a8c70a..a2f3c54290a 100644 --- a/src/core/channel/child_channel.c +++ b/src/core/channel/child_channel.c @@ -60,11 +60,10 @@ typedef struct { gpr_uint8 sent_farewell; } lb_channel_data; -typedef struct { - grpc_child_channel *channel; -} lb_call_data; +typedef struct { grpc_child_channel *channel; } lb_call_data; -static void lb_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void lb_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { grpc_call_next_op(elem, op); } @@ -121,7 +120,8 @@ static void lb_channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void lb_init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) {} + const void *server_transport_data, + grpc_transport_op *initial_op) {} /* Destructor for call_data */ static void lb_destroy_call_elem(grpc_call_element *elem) {} @@ -154,9 +154,10 @@ static void lb_destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_child_channel_top_filter = { - lb_start_transport_op, lb_channel_op, sizeof(lb_call_data), - lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data), - lb_init_channel_elem, lb_destroy_channel_elem, "child-channel", }; + lb_start_transport_op, lb_channel_op, sizeof(lb_call_data), + lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data), + lb_init_channel_elem, lb_destroy_channel_elem, "child-channel", +}; /* grpc_child_channel proper */ @@ -261,7 +262,8 @@ void grpc_child_channel_handle_op(grpc_child_channel *channel, } grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, - grpc_call_element *parent, grpc_transport_op *initial_op) { + grpc_call_element *parent, + grpc_transport_op *initial_op) { grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size); grpc_call_element *lbelem; lb_call_data *lbcalld; diff --git a/src/core/channel/child_channel.h b/src/core/channel/child_channel.h index 264a8bbb826..556a1c731ce 100644 --- a/src/core/channel/child_channel.h +++ b/src/core/channel/child_channel.h @@ -57,8 +57,9 @@ void grpc_child_channel_destroy(grpc_child_channel *channel, int wait_for_callbacks); grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, - grpc_call_element *parent, grpc_transport_op *initial_op); + grpc_call_element *parent, + grpc_transport_op *initial_op); grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call); void grpc_child_call_destroy(grpc_child_call *call); -#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */ +#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */ diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 77c49510382..642822a2670 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -106,7 +106,8 @@ static int prepare_activate(grpc_call_element *elem, /* create a child call */ /* TODO(ctiller): pass the waiting op down here */ - calld->s.active.child_call = grpc_child_channel_create_call(on_child, elem, NULL); + calld->s.active.child_call = + grpc_child_channel_create_call(on_child, elem, NULL); return 1; } @@ -184,9 +185,7 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) { chand->waiting_child_count = new_count; } -static void send_up_cancelled_ops(grpc_call_element *elem) { - abort(); -} +static void send_up_cancelled_ops(grpc_call_element *elem) { abort(); } static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; @@ -219,8 +218,8 @@ static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { abort(); } -static void cc_start_transport_op(grpc_call_element *elem, - grpc_transport_op *op) { +static void cc_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { call_data *calld = elem->call_data; GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); @@ -325,7 +324,8 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { call_data *calld = elem->call_data; /* TODO(ctiller): is there something useful we can do here? */ @@ -392,9 +392,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_client_channel_filter = { - cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - "client-channel", + cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "client-channel", }; grpc_transport_setup_result grpc_client_channel_transport_setup_complete( diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c index 9b7db6124a1..14dda886983 100644 --- a/src/core/channel/connected_channel.c +++ b/src/core/channel/connected_channel.c @@ -50,9 +50,7 @@ typedef struct connected_channel_channel_data { grpc_transport *transport; } channel_data; -typedef struct connected_channel_call_data { - void *unused; -} call_data; +typedef struct connected_channel_call_data { void *unused; } call_data; /* We perform a small hack to locate transport data alongside the connected channel data in call allocations, to allow everything to be pulled in minimal @@ -63,13 +61,15 @@ typedef struct connected_channel_call_data { /* Intercept a call operation and either push it directly up or translate it into transport stream operations */ -static void con_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void con_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - grpc_transport_perform_op(chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); + grpc_transport_perform_op(chand->transport, + TRANSPORT_STREAM_FROM_CALL_DATA(calld), op); } /* Currently we assume all channel operations should just be pushed up. */ @@ -136,8 +136,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_connected_channel_filter = { - con_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, "connected", + con_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "connected", }; /* Transport callback to accept a new stream... calls up to handle it */ @@ -189,8 +190,7 @@ static void transport_closed(void *user_data, grpc_transport *transport) { } const grpc_transport_callbacks connected_channel_transport_callbacks = { - accept_stream, - transport_goaway, transport_closed, + accept_stream, transport_goaway, transport_closed, }; grpc_transport_setup_result grpc_connected_channel_bind_transport( diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index 45a74363619..9805f325a64 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -123,7 +123,8 @@ static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { } } -static void hc_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void hc_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); hc_mutate_op(elem, op); grpc_call_next_op(elem, op); @@ -215,6 +216,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_client_filter = { - hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - "http-client"}; + hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "http-client"}; diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c index e5174acd681..1f64df68e36 100644 --- a/src/core/channel/http_server_filter.c +++ b/src/core/channel/http_server_filter.c @@ -207,7 +207,8 @@ static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { } } -static void hs_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void hs_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); hs_mutate_op(elem, op); grpc_call_next_op(elem, op); @@ -232,7 +233,8 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; /* initialize members */ @@ -293,6 +295,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_http_server_filter = { - hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - "http-server"}; + hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "http-server"}; diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c index 62e57ce285d..1d2be716d77 100644 --- a/src/core/channel/noop_filter.c +++ b/src/core/channel/noop_filter.c @@ -61,7 +61,8 @@ static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ -static void noop_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void noop_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { noop_mutate_op(elem, op); /* pass control down the stack */ @@ -87,7 +88,8 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -134,6 +136,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_no_op_filter = { - noop_start_transport_op, channel_op, sizeof(call_data), - init_call_elem, destroy_call_elem, sizeof(channel_data), - init_channel_elem, destroy_channel_elem, "no-op"}; + noop_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "no-op"}; diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h index 05d57a905b3..388be357113 100644 --- a/src/core/surface/channel.h +++ b/src/core/surface/channel.h @@ -51,4 +51,4 @@ void grpc_client_channel_closed(grpc_channel_element *elem); void grpc_channel_internal_ref(grpc_channel *channel); void grpc_channel_internal_unref(grpc_channel *channel); -#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */ +#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */ diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c index 5f3e9bec0c8..daa8d3a7c6a 100644 --- a/src/core/surface/channel_create.c +++ b/src/core/surface/channel_create.c @@ -175,7 +175,8 @@ static void done_setup(void *sp) { static grpc_transport_setup_result complete_setup(void *channel_stack, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter}; + static grpc_channel_filter const *extra_filters[] = { + &grpc_http_client_filter}; return grpc_client_channel_transport_setup_complete( channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); diff --git a/src/core/surface/client.c b/src/core/surface/client.c index 7eb99895f72..8ac4dd1e0e2 100644 --- a/src/core/surface/client.c +++ b/src/core/surface/client.c @@ -43,7 +43,8 @@ typedef struct { void *unused; } call_data; typedef struct { void *unused; } channel_data; -static void client_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void client_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); grpc_call_next_op(elem, op); } @@ -67,7 +68,8 @@ static void channel_op(grpc_channel_element *elem, } static void init_call_elem(grpc_call_element *elem, - const void *transport_server_data, grpc_transport_op *initial_op) {} + const void *transport_server_data, + grpc_transport_op *initial_op) {} static void destroy_call_elem(grpc_call_element *elem) {} @@ -81,6 +83,7 @@ static void init_channel_elem(grpc_channel_element *elem, static void destroy_channel_elem(grpc_channel_element *elem) {} const grpc_channel_filter grpc_client_surface_filter = { - client_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, "client", + client_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "client", }; diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index f95e2a16c29..c93222344d0 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -46,7 +46,8 @@ typedef struct { void *unused; } call_data; typedef struct { void *unused; } channel_data; -static void lame_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void lame_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); grpc_transport_op_finish_with_failure(op); } @@ -66,7 +67,8 @@ static void channel_op(grpc_channel_element *elem, } static void init_call_elem(grpc_call_element *elem, - const void *transport_server_data, grpc_transport_op *initial_op) { + const void *transport_server_data, + grpc_transport_op *initial_op) { if (initial_op) { grpc_transport_op_finish_with_failure(initial_op); } @@ -84,9 +86,9 @@ static void init_channel_elem(grpc_channel_element *elem, static void destroy_channel_elem(grpc_channel_element *elem) {} static const grpc_channel_filter lame_filter = { - lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, - "lame-client", + lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "lame-client", }; grpc_channel *grpc_lame_client_channel_create(void) { diff --git a/src/core/surface/server.c b/src/core/surface/server.c index e9d6f86734b..202fafca25d 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -414,8 +414,10 @@ static void server_on_recv(void *ptr, int success) { } switch (*calld->recv_state) { - case GRPC_STREAM_OPEN: break; - case GRPC_STREAM_SEND_CLOSED: break; + case GRPC_STREAM_OPEN: + break; + case GRPC_STREAM_SEND_CLOSED: + break; case GRPC_STREAM_RECV_CLOSED: gpr_mu_lock(&chand->server->mu); if (calld->state == NOT_STARTED) { @@ -453,7 +455,8 @@ static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) { } } -static void server_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { +static void server_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); server_mutate_op(elem, op); grpc_call_next_op(elem, op); @@ -507,7 +510,8 @@ static void shutdown_channel(channel_data *chand) { } static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; memset(calld, 0, sizeof(call_data)); @@ -599,8 +603,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } static const grpc_channel_filter server_surface_filter = { - server_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, "server", + server_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "server", }; static void addcq(grpc_server *server, grpc_completion_queue *cq) { diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index ebde5095a99..7b5c2f227b3 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -45,7 +45,8 @@ static grpc_transport_setup_result setup_transport(void *server, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; + static grpc_channel_filter const *extra_filters[] = { + &grpc_http_server_filter}; return grpc_server_setup_transport(server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c index 9b62aefd0be..cf1e66bf8be 100644 --- a/src/core/transport/chttp2/stream_encoder.c +++ b/src/core/transport/chttp2/stream_encoder.c @@ -481,10 +481,10 @@ gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count, break; case GRPC_OP_METADATA: grpc_metadata_batch_assert_ok(&op->data.metadata); - /* these just get copied as they don't impact the number of flow - controlled bytes */ - grpc_sopb_append(outops, op, 1); - curop++; + /* these just get copied as they don't impact the number of flow + controlled bytes */ + grpc_sopb_append(outops, op, 1); + curop++; break; case GRPC_OP_BEGIN_MESSAGE: /* begin op: for now we just convert the op to a slice and fall diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index d7156142fb8..ebc715f3b8c 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -525,7 +525,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, gpr_mu_lock(&t->mu); t->calling_back = 1; - ref_transport(t); /* matches unref at end of this function */ + ref_transport(t); /* matches unref at end of this function */ gpr_mu_unlock(&t->mu); sr = setup(arg, &t->base, t->metadata_context); @@ -537,7 +537,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup, if (t->destroying) gpr_cv_signal(&t->cv); unlock(t); - ref_transport(t); /* matches unref inside recv_data */ + ref_transport(t); /* matches unref inside recv_data */ recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK); unref_transport(t); @@ -884,7 +884,8 @@ static int prepare_write(transport *t) { t->outgoing_window -= window_delta; s->outgoing_window -= window_delta; - if (s->write_state == WRITE_STATE_QUEUED_CLOSE && s->outgoing_sopb->nops == 0) { + if (s->write_state == WRITE_STATE_QUEUED_CLOSE && + s->outgoing_sopb->nops == 0) { s->send_closed = 1; } if (s->writing_sopb.nops > 0 || s->send_closed) { @@ -927,8 +928,7 @@ static void finalize_outbuf(transport *t) { while ((s = stream_list_remove_head(t, WRITING))) { grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops, - s->send_closed, s->id, &t->hpack_compressor, - &t->outbuf); + s->send_closed, s->id, &t->hpack_compressor, &t->outbuf); s->writing_sopb.nops = 0; if (s->send_closed) { stream_list_join(t, s, WRITTEN_CLOSED); @@ -1047,12 +1047,14 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { } if (op->cancel_with_status != GRPC_STATUS_OK) { - cancel_stream(t, s, op->cancel_with_status, grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), - 1); + cancel_stream( + t, s, op->cancel_with_status, + grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), 1); } } -static void perform_op(grpc_transport *gt, grpc_stream *gs, grpc_transport_op *op) { +static void perform_op(grpc_transport *gt, grpc_stream *gs, + grpc_transport_op *op) { transport *t = (transport *)gt; stream *s = (stream *)gs; @@ -1129,7 +1131,8 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, } if (s->cancelled) { send_rst = 0; - } else if (!s->read_closed || s->write_state != WRITE_STATE_SENT_CLOSE || had_outgoing) { + } else if (!s->read_closed || s->write_state != WRITE_STATE_SENT_CLOSE || + had_outgoing) { s->cancelled = 1; stream_list_join(t, s, CANCELLED); @@ -1586,11 +1589,11 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { } if (st.initial_window_update) { for (i = 0; i < t->stream_map.count; i++) { - stream *s = (stream*)(t->stream_map.values[i]); + stream *s = (stream *)(t->stream_map.values[i]); int was_window_empty = s->outgoing_window <= 0; s->outgoing_window += st.initial_window_update; - if (was_window_empty && s->outgoing_window > 0 && - s->outgoing_sopb && s->outgoing_sopb->nops > 0) { + if (was_window_empty && s->outgoing_window > 0 && s->outgoing_sopb && + s->outgoing_sopb->nops > 0) { stream_list_join(t, s, WRITABLE); } } @@ -1609,7 +1612,8 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { s->outgoing_window += st.window_update; /* if this window update makes outgoing ops writable again, flag that */ - if (was_window_empty && s->outgoing_sopb && s->outgoing_sopb->nops > 0) { + if (was_window_empty && s->outgoing_sopb && + s->outgoing_sopb->nops > 0) { stream_list_join(t, s, WRITABLE); } } @@ -1877,8 +1881,8 @@ static void finish_reads(transport *t) { while ((s = stream_list_remove_head(t, FINISHED_READ_OP)) != NULL) { int publish = 0; GPR_ASSERT(s->incoming_sopb); - *s->publish_state = compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, - s->read_closed); + *s->publish_state = + compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, s->read_closed); if (*s->publish_state != s->published_state) { s->published_state = *s->publish_state; publish = 1; @@ -1895,8 +1899,12 @@ static void finish_reads(transport *t) { static void schedule_cb(transport *t, op_closure closure, int success) { if (t->pending_callbacks.capacity == t->pending_callbacks.count) { - t->pending_callbacks.capacity = GPR_MAX(t->pending_callbacks.capacity * 2, 8); - t->pending_callbacks.callbacks = gpr_realloc(t->pending_callbacks.callbacks, t->pending_callbacks.capacity * sizeof(*t->pending_callbacks.callbacks)); + t->pending_callbacks.capacity = + GPR_MAX(t->pending_callbacks.capacity * 2, 8); + t->pending_callbacks.callbacks = + gpr_realloc(t->pending_callbacks.callbacks, + t->pending_callbacks.capacity * + sizeof(*t->pending_callbacks.callbacks)); } closure.success = success; t->pending_callbacks.callbacks[t->pending_callbacks.count++] = closure; @@ -1944,9 +1952,9 @@ static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { */ static const grpc_transport_vtable vtable = { - sizeof(stream), init_stream, perform_op, - add_to_pollset, destroy_stream, goaway, close_transport, - send_ping, destroy_transport}; + sizeof(stream), init_stream, perform_op, + add_to_pollset, destroy_stream, goaway, + close_transport, send_ping, destroy_transport}; void grpc_create_chttp2_transport(grpc_transport_setup_callback setup, void *arg, diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h index f5de64d583a..95497a3cc8e 100644 --- a/src/core/transport/stream_op.h +++ b/src/core/transport/stream_op.h @@ -86,29 +86,31 @@ typedef struct grpc_metadata_batch { void grpc_metadata_batch_init(grpc_metadata_batch *comd); void grpc_metadata_batch_destroy(grpc_metadata_batch *comd); void grpc_metadata_batch_merge(grpc_metadata_batch *target, - grpc_metadata_batch *add); + grpc_metadata_batch *add); void grpc_metadata_batch_link_head(grpc_metadata_batch *comd, - grpc_linked_mdelem *storage); + grpc_linked_mdelem *storage); void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd, - grpc_linked_mdelem *storage); + grpc_linked_mdelem *storage); void grpc_metadata_batch_add_head(grpc_metadata_batch *comd, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add); void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd, - grpc_linked_mdelem *storage, - grpc_mdelem *elem_to_add); + grpc_linked_mdelem *storage, + grpc_mdelem *elem_to_add); void grpc_metadata_batch_filter(grpc_metadata_batch *comd, - grpc_mdelem *(*filter)(void *user_data, - grpc_mdelem *elem), - void *user_data); + grpc_mdelem *(*filter)(void *user_data, + grpc_mdelem *elem), + void *user_data); #ifndef NDEBUG void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd); #else -#define grpc_metadata_batch_assert_ok(comd) do {} while (0) +#define grpc_metadata_batch_assert_ok(comd) \ + do { \ + } while (0) #endif /* Represents a single operation performed on a stream/transport */ @@ -151,7 +153,8 @@ void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb); /* Append a GRPC_OP_BEGIN to a buffer */ void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, gpr_uint32 flags); -void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch metadata); +void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, + grpc_metadata_batch metadata); /* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */ void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice); /* Append a buffer to a buffer - does not ref/unref any internal objects */ @@ -160,4 +163,4 @@ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, char *grpc_sopb_string(grpc_stream_op_buffer *sopb); -#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */ +#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */ diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index ab2f7c34705..724cb0ea686 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -52,8 +52,10 @@ void grpc_transport_destroy(grpc_transport *transport) { } int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, - const void *server_data, grpc_transport_op *initial_op) { - return transport->vtable->init_stream(transport, stream, server_data, initial_op); + const void *server_data, + grpc_transport_op *initial_op) { + return transport->vtable->init_stream(transport, stream, server_data, + initial_op); } void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream, diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index a51e01d3c96..5036dfc2de2 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -95,7 +95,8 @@ struct grpc_transport_callbacks { void (*accept_stream)(void *user_data, grpc_transport *transport, const void *server_data); - void (*goaway)(void *user_data, grpc_transport *transport, grpc_status_code status, gpr_slice debug); + void (*goaway)(void *user_data, grpc_transport *transport, + grpc_status_code status, gpr_slice debug); /* The transport has been closed */ void (*closed)(void *user_data, grpc_transport *transport); @@ -115,7 +116,8 @@ size_t grpc_transport_stream_size(grpc_transport *transport); server_data - either NULL for a client initiated stream, or a pointer supplied from the accept_stream callback function */ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream, - const void *server_data, grpc_transport_op *initial_op); + const void *server_data, + grpc_transport_op *initial_op); /* Destroy transport data for a stream. @@ -133,7 +135,8 @@ void grpc_transport_destroy_stream(grpc_transport *transport, void grpc_transport_op_finish_with_failure(grpc_transport_op *op); /* TODO(ctiller): remove this */ -void grpc_transport_add_to_pollset(grpc_transport *transport, grpc_pollset *pollset); +void grpc_transport_add_to_pollset(grpc_transport *transport, + grpc_pollset *pollset); char *grpc_transport_op_string(grpc_transport_op *op); @@ -205,4 +208,4 @@ void grpc_transport_setup_initiate(grpc_transport_setup *setup); used as a destruction call by setup). */ void grpc_transport_setup_cancel(grpc_transport_setup *setup); -#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */ +#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */ diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h index 75d8d51e20d..479e15338f8 100644 --- a/src/core/transport/transport_impl.h +++ b/src/core/transport/transport_impl.h @@ -76,4 +76,4 @@ struct grpc_transport { const grpc_transport_vtable *vtable; }; -#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */ +#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */ diff --git a/test/core/end2end/fixtures/chttp2_socket_pair.c b/test/core/end2end/fixtures/chttp2_socket_pair.c index acc0a69708a..d19ceb178bc 100644 --- a/test/core/end2end/fixtures/chttp2_socket_pair.c +++ b/test/core/end2end/fixtures/chttp2_socket_pair.c @@ -59,7 +59,8 @@ static grpc_transport_setup_result server_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { grpc_end2end_test_fixture *f = ts; - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; + static grpc_channel_filter const *extra_filters[] = { + &grpc_http_server_filter}; return grpc_server_setup_transport(f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } @@ -73,9 +74,9 @@ static grpc_transport_setup_result client_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { sp_client_setup *cs = ts; - const grpc_channel_filter *filters[] = { - &grpc_client_surface_filter, &grpc_http_client_filter, - &grpc_connected_channel_filter}; + const grpc_channel_filter *filters[] = {&grpc_client_surface_filter, + &grpc_http_client_filter, + &grpc_connected_channel_filter}; size_t nfilters = sizeof(filters) / sizeof(*filters); grpc_channel *channel = grpc_channel_create_from_filters( filters, nfilters, cs->client_args, mdctx, 1); From 482ef8b0db9e330ba9752d60de4dcece336dbeca Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 11:38:20 -0700 Subject: [PATCH 13/58] Add required NULL check --- src/core/surface/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 202fafca25d..28f42f0fc3c 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -524,7 +524,7 @@ static void init_call_elem(grpc_call_element *elem, server_ref(chand->server); - server_mutate_op(elem, initial_op); + if (initial_op) server_mutate_op(elem, initial_op); } static void destroy_call_elem(grpc_call_element *elem) { From 7e8489ae402d8d551654b3d75a2e8933506ee386 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 12:41:16 -0700 Subject: [PATCH 14/58] Fix double-set of alarm --- src/core/surface/call.c | 19 +++++++++++++++++-- src/core/transport/chttp2_transport.c | 18 +----------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index c39e6cf3a42..83c8f4c7797 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -260,6 +260,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, size_t add_initial_metadata_count, gpr_timespec send_deadline) { size_t i; + grpc_transport_op initial_op; + grpc_transport_op *initial_op_ptr = NULL; grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_call *call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); @@ -288,7 +290,19 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, /* one ref is dropped in response to destroy, the other in stream_closed */ gpr_ref_init(&call->internal_refcount, 2); - grpc_call_stack_init(channel_stack, server_transport_data, NULL, + /* server hack: start reads immediately so we can get initial metadata. + TODO(ctiller): figure out a cleaner solution */ + if (!call->is_client) { + memset(&initial_op, 0, sizeof(initial_op)); + initial_op.recv_ops = &call->recv_ops; + initial_op.recv_state = &call->recv_state; + initial_op.on_done_recv = call_on_done_recv; + initial_op.recv_user_data = call; + call->receiving = 1; + grpc_call_internal_ref(call); + initial_op_ptr = &initial_op; + } + grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) { set_deadline_alarm(call, send_deadline); @@ -793,7 +807,6 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { mdb.list = chain_metadata_from_app(call, data.send_metadata.count, data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; - mdb.deadline = call->send_deadline; /* send status */ /* TODO(ctiller): cache common status values */ data = call->request_data[GRPC_IOREQ_SEND_STATUS]; @@ -814,6 +827,7 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { grpc_mdstr_from_string(call->metadata_context, data.send_status.details))); } + grpc_sopb_add_metadata(&call->send_ops, mdb); } } break; @@ -1011,6 +1025,7 @@ static void call_alarm(void *arg, int success) { static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { if (call->have_alarm) { gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice"); + return; } grpc_call_internal_ref(call); call->have_alarm = 1; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index ebc715f3b8c..2261b087a20 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1205,23 +1205,6 @@ static void maybe_join_window_updates(transport *t, stream *s) { } } -#if 0 -static void set_allow_window_updates(grpc_transport *tp, grpc_stream *sp, - int allow) { - transport *t = (transport *)tp; - stream *s = (stream *)sp; - - lock(t); - s->allow_window_updates = allow; - if (allow) { - maybe_join_window_updates(t, s); - } else { - stream_list_remove(t, s, WINDOW_UPDATE); - } - unlock(t); -} -#endif - static grpc_chttp2_parse_error update_incoming_window(transport *t, stream *s) { if (t->incoming_frame_size > t->incoming_window) { gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", @@ -1892,6 +1875,7 @@ static void finish_reads(transport *t) { publish = 1; } if (publish) { + s->incoming_sopb = NULL; schedule_cb(t, s->recv_done_closure, 1); } } From 6e84aba85fefc084c53325d949eb81b6fbfa919f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 15:08:17 -0700 Subject: [PATCH 15/58] Make the things compile again --- src/core/security/auth.c | 55 +++++++++++-------- src/core/security/server_secure_chttp2.c | 4 +- src/core/surface/call.c | 3 + src/core/surface/secure_channel_create.c | 3 +- src/core/transport/transport.c | 9 +++ src/core/transport/transport_op_string.c | 7 ++- test/core/channel/channel_stack_test.c | 8 +-- test/core/end2end/fixtures/chttp2_fullstack.c | 1 - .../end2end/fixtures/chttp2_fullstack_uds.c | 1 - .../chttp2_socket_pair_one_byte_at_a_time.c | 6 +- .../transport/chttp2/stream_encoder_test.c | 5 -- test/core/transport/stream_op_test.c | 11 +--- 12 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 4af2c67d83c..5d241781f17 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -51,7 +51,9 @@ typedef struct { grpc_credentials *creds; grpc_mdstr *host; grpc_mdstr *method; - grpc_call_op op; + grpc_transport_op op; + size_t op_md_idx; + int sent_initial_metadata; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; } call_data; @@ -75,14 +77,17 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, grpc_credentials_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; - grpc_call_op op = calld->op; + grpc_transport_op *op = &calld->op; + grpc_metadata_batch *mdb; size_t i; GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); + GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx && op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); + mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata; for (i = 0; i < num_md; i++) { - grpc_metadata_batch_add_tail(&op.data.metadata, &calld->md_links[i], + grpc_metadata_batch_add_tail(mdb, &calld->md_links[i], grpc_mdelem_ref(md_elems[i])); } - grpc_call_next_op(elem, &op); + grpc_call_next_op(elem, op); } static char *build_service_url(const char *url_scheme, call_data *calld) { @@ -105,7 +110,7 @@ static char *build_service_url(const char *url_scheme, call_data *calld) { return service_url; } -static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { +static void send_security_metadata(grpc_call_element *elem, grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -144,9 +149,8 @@ static void on_host_checked(void *user_data, grpc_security_status status) { gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", grpc_mdstr_as_c_string(calld->host)); bubbleup_error(elem, error_msg); - grpc_metadata_batch_destroy(&calld->op.data.metadata); gpr_free(error_msg); - calld->op.done_cb(calld->op.user_data, GRPC_OP_ERROR); + grpc_transport_op_finish_with_failure(&calld->op); } } @@ -155,16 +159,22 @@ static void on_host_checked(void *user_data, grpc_security_status status) { - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ -static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void auth_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; grpc_linked_mdelem *l; + size_t i; - switch (op->type) { - case GRPC_SEND_METADATA: - for (l = op->data.metadata.list.head; l != NULL; l = l->next) { + if (op->send_ops && !calld->sent_initial_metadata) { + size_t nops = op->send_ops->nops; + grpc_stream_op *ops = op->send_ops->ops; + for (i = 0; i < nops; i++) { + grpc_stream_op *sop = &ops[i]; + if (sop->type != GRPC_OP_METADATA) continue; + calld->sent_initial_metadata = 1; + for (l = sop->data.metadata.list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; /* Pointer comparison is OK for md_elems created from the same context. */ @@ -189,20 +199,19 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, "Invalid host %s set in :authority metadata.", call_host); bubbleup_error(elem, error_msg); - grpc_metadata_batch_destroy(&calld->op.data.metadata); gpr_free(error_msg); - op->done_cb(op->user_data, GRPC_OP_ERROR); + grpc_transport_op_finish_with_failure(&calld->op); } - break; + return; /* early exit */ } } send_security_metadata(elem, op); - break; - default: - /* pass control up or down the stack depending on op->dir */ - grpc_call_next_op(elem, op); - break; + return; /* early exit */ + } } + + /* pass control up or down the stack */ + grpc_call_next_op(elem, op); } /* Called on special channel events, such as disconnection or new incoming @@ -214,13 +223,15 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { /* TODO(jboeuf): Find a way to pass-in the credentials from the caller here. */ call_data *calld = elem->call_data; calld->creds = NULL; calld->host = NULL; calld->method = NULL; + + GPR_ASSERT(!initial_op || !initial_op->send_ops); } /* Destructor for call_data */ @@ -288,5 +299,5 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_client_auth_filter = { - call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, + auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, destroy_channel_elem, "auth"}; diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 5b7d99ce401..0698161b6d6 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -35,7 +35,6 @@ #include -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" @@ -73,8 +72,7 @@ static void state_unref(grpc_server_secure_state *state) { static grpc_transport_setup_result setup_transport(void *server, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter, - &grpc_http_filter}; + static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; return grpc_server_setup_transport(server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 83c8f4c7797..5b8a985142d 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -598,6 +598,8 @@ static void call_on_done_send(void *pc, int success) { finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error); } if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) { + finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, error); + finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, error); finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, error); } call->sending = 0; @@ -684,6 +686,7 @@ static void call_on_done_recv(void *pc, int success) { size_t i; int unref = 0; lock(call); + call->receiving = 0; for (i = 0; success && i < call->recv_ops.nops; i++) { grpc_stream_op *op = &call->recv_ops.ops[i]; switch (op->type) { diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index e7d223bfda9..0bcbe38131b 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -44,7 +44,6 @@ #include "src/core/channel/client_setup.h" #include "src/core/channel/connected_channel.h" #include "src/core/channel/http_client_filter.h" -#include "src/core/channel/http_filter.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" #include "src/core/security/auth.h" @@ -193,7 +192,7 @@ static grpc_transport_setup_result complete_setup(void *channel_stack, grpc_transport *transport, grpc_mdctx *mdctx) { static grpc_channel_filter const *extra_filters[] = { - &grpc_client_auth_filter, &grpc_http_client_filter, &grpc_http_filter}; + &grpc_client_auth_filter, &grpc_http_client_filter}; return grpc_client_channel_transport_setup_complete( channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index 724cb0ea686..bc9f4b43879 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -85,3 +85,12 @@ void grpc_transport_setup_cancel(grpc_transport_setup *setup) { void grpc_transport_setup_initiate(grpc_transport_setup *setup) { setup->vtable->initiate(setup); } + +void grpc_transport_op_finish_with_failure(grpc_transport_op *op) { + if (op->send_ops) { + op->on_done_send(op->send_user_data, 0); + } + if (op->recv_ops) { + op->on_done_recv(op->recv_user_data, 0); + } +} \ No newline at end of file diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index e886690234f..54f501f8980 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -42,7 +42,7 @@ #include static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { - gpr_strvec_add(b, gpr_strdup(" key=")); + gpr_strvec_add(b, gpr_strdup("key=")); gpr_strvec_add( b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice), GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT)); @@ -56,6 +56,7 @@ static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { grpc_linked_mdelem *m; for (m = md.list.head; m != NULL; m = m->next) { + if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", ")); put_metadata(b, m->md); } if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) { @@ -75,7 +76,7 @@ char *grpc_sopb_string(grpc_stream_op_buffer *sopb) { for (i = 0; i < sopb->nops; i++) { grpc_stream_op *op = &sopb->ops[i]; - if (i) gpr_strvec_add(&b, gpr_strdup(", ")); + if (i > 0) gpr_strvec_add(&b, gpr_strdup(", ")); switch (op->type) { case GRPC_NO_OP: gpr_strvec_add(&b, gpr_strdup("NO_OP")); @@ -88,7 +89,9 @@ char *grpc_sopb_string(grpc_stream_op_buffer *sopb) { gpr_asprintf(&tmp, "SLICE:%d", GPR_SLICE_LENGTH(op->data.slice)); break; case GRPC_OP_METADATA: + gpr_strvec_add(&b, gpr_strdup("METADATA{")); put_metadata_list(&b, op->data.metadata); + gpr_strvec_add(&b, gpr_strdup("}")); break; } } diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index e92db592493..1d1331eb9f2 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -55,7 +55,7 @@ static void channel_init_func(grpc_channel_element *elem, } static void call_init_func(grpc_call_element *elem, - const void *server_transport_data) { + const void *server_transport_data, grpc_transport_op *initial_op) { ++*(int *)(elem->channel_data); *(int *)(elem->call_data) = 0; } @@ -66,8 +66,8 @@ static void call_destroy_func(grpc_call_element *elem) { ++*(int *)(elem->channel_data); } -static void call_func(grpc_call_element *elem, grpc_call_element *from_elem, - grpc_call_op *op) { +static void call_func(grpc_call_element *elem, + grpc_transport_op *op) { ++*(int *)(elem->call_data); } @@ -112,7 +112,7 @@ static void test_create_channel_stack(void) { GPR_ASSERT(*channel_data == 0); call_stack = gpr_malloc(channel_stack->call_stack_size); - grpc_call_stack_init(channel_stack, NULL, call_stack); + grpc_call_stack_init(channel_stack, NULL, NULL, call_stack); GPR_ASSERT(call_stack->count == 1); call_elem = grpc_call_stack_element(call_stack, 0); GPR_ASSERT(call_elem->filter == channel_elem->filter); diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c index ab7c7f4caa9..d7de5e54348 100644 --- a/test/core/end2end/fixtures/chttp2_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_fullstack.c @@ -37,7 +37,6 @@ #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/surface/channel.h" #include "src/core/surface/client.h" diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds.c b/test/core/end2end/fixtures/chttp2_fullstack_uds.c index 27e4baf3c01..53803b0f1d8 100644 --- a/test/core/end2end/fixtures/chttp2_fullstack_uds.c +++ b/test/core/end2end/fixtures/chttp2_fullstack_uds.c @@ -39,7 +39,6 @@ #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/support/string.h" #include "src/core/surface/channel.h" diff --git a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c index 9f6ad980063..d861034f8f8 100644 --- a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c +++ b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c @@ -37,7 +37,6 @@ #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" -#include "src/core/channel/http_filter.h" #include "src/core/channel/http_client_filter.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/endpoint_pair.h" @@ -60,8 +59,7 @@ static grpc_transport_setup_result server_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { grpc_end2end_test_fixture *f = ts; - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter, - &grpc_http_filter}; + static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; return grpc_server_setup_transport(f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } @@ -76,7 +74,7 @@ static grpc_transport_setup_result client_setup_transport( sp_client_setup *cs = ts; const grpc_channel_filter *filters[] = { - &grpc_client_surface_filter, &grpc_http_client_filter, &grpc_http_filter, + &grpc_client_surface_filter, &grpc_http_client_filter, &grpc_connected_channel_filter}; size_t nfilters = sizeof(filters) / sizeof(*filters); grpc_channel *channel = grpc_channel_create_from_filters( diff --git a/test/core/transport/chttp2/stream_encoder_test.c b/test/core/transport/chttp2/stream_encoder_test.c index bda8298eb38..91833440cd8 100644 --- a/test/core/transport/chttp2/stream_encoder_test.c +++ b/test/core/transport/chttp2/stream_encoder_test.c @@ -102,15 +102,10 @@ static void verify_sopb(size_t window_available, int eof, gpr_slice_unref(expect); } -static void assert_result_ok(void *user_data, grpc_op_error error) { - GPR_ASSERT(error == GRPC_OP_OK); -} - static void test_small_data_framing(void) { grpc_sopb_add_no_op(&g_sopb); verify_sopb(10, 0, 0, ""); - grpc_sopb_add_flow_ctl_cb(&g_sopb, assert_result_ok, NULL); grpc_sopb_add_slice(&g_sopb, create_test_slice(3)); verify_sopb(10, 0, 3, "000003 0000 deadbeef 000102"); diff --git a/test/core/transport/stream_op_test.c b/test/core/transport/stream_op_test.c index 58852238948..613acd62072 100644 --- a/test/core/transport/stream_op_test.c +++ b/test/core/transport/stream_op_test.c @@ -38,10 +38,6 @@ #include #include "test/core/util/test_config.h" -static void flow_ctl_cb_fails(void *ignored, grpc_op_error error) { - GPR_ASSERT(error == GRPC_OP_ERROR); -} - static void assert_slices_equal(gpr_slice a, gpr_slice b) { GPR_ASSERT(a.refcount == b.refcount); if (a.refcount) { @@ -60,7 +56,6 @@ int main(int argc, char **argv) { gpr_slice test_slice_2 = gpr_slice_malloc(2); gpr_slice test_slice_3 = gpr_slice_malloc(3); gpr_slice test_slice_4 = gpr_slice_malloc(4); - char x; unsigned i; grpc_stream_op_buffer buf; @@ -78,7 +73,6 @@ int main(int argc, char **argv) { grpc_sopb_add_slice(&buf, test_slice_2); grpc_sopb_add_slice(&buf, test_slice_3); grpc_sopb_add_slice(&buf, test_slice_4); - grpc_sopb_add_flow_ctl_cb(&buf, flow_ctl_cb_fails, &x); grpc_sopb_add_no_op(&buf); /* verify that the data went in ok */ @@ -94,10 +88,7 @@ int main(int argc, char **argv) { assert_slices_equal(buf.ops[3].data.slice, test_slice_3); GPR_ASSERT(buf.ops[4].type == GRPC_OP_SLICE); assert_slices_equal(buf.ops[4].data.slice, test_slice_4); - GPR_ASSERT(buf.ops[5].type == GRPC_OP_FLOW_CTL_CB); - GPR_ASSERT(buf.ops[5].data.flow_ctl_cb.cb == flow_ctl_cb_fails); - GPR_ASSERT(buf.ops[5].data.flow_ctl_cb.arg == &x); - GPR_ASSERT(buf.ops[6].type == GRPC_NO_OP); + GPR_ASSERT(buf.ops[5].type == GRPC_NO_OP); /* initialize the second buffer */ grpc_sopb_init(&buf2); From fa4f99404f083ecd6416cc35b97de6a6522f0569 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 15:22:09 -0700 Subject: [PATCH 16/58] Add init/destroy, and a debug-only assert on bad headers --- src/core/surface/call.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 5b8a985142d..556a3b600ea 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -287,6 +287,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, call->metadata_context = grpc_channel_get_metadata_context(channel); grpc_sopb_init(&call->send_ops); grpc_sopb_init(&call->recv_ops); + gpr_slice_buffer_init(&call->incoming_message); /* one ref is dropped in response to destroy, the other in stream_closed */ gpr_ref_init(&call->internal_refcount, 2); @@ -348,6 +349,7 @@ static void destroy_call(void *call, int ignored_success) { grpc_bbq_destroy(&c->incoming_queue); grpc_sopb_destroy(&c->send_ops); grpc_sopb_destroy(&c->recv_ops); + gpr_slice_buffer_destroy(&c->incoming_message); gpr_free(c); } @@ -1028,6 +1030,7 @@ static void call_alarm(void *arg, int success) { static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { if (call->have_alarm) { gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice"); + assert(0); return; } grpc_call_internal_ref(call); From 3928c7a1a68e5649b6180b1e8449a137cc745c8b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 16:00:47 -0700 Subject: [PATCH 17/58] Add a hack to ensure one-op-at-a-time during connection establishment --- src/core/surface/call.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 556a3b600ea..c6fc56891d4 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -302,6 +302,10 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, call->receiving = 1; grpc_call_internal_ref(call); initial_op_ptr = &initial_op; + } else { + /* we clear this when we've sent initial metadata -- this is very much + a hack to avoid two ops ending up in client_channel */ + call->receiving = 2; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); @@ -595,6 +599,10 @@ static void call_on_done_send(void *pc, int success) { lock(call); if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error); + if (call->is_client) { + GPR_ASSERT(call->receiving == 2); + call->receiving = 0; + } } if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error); @@ -604,6 +612,7 @@ static void call_on_done_send(void *pc, int success) { finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, error); finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, error); } + call->last_send_contains = 0; call->sending = 0; unlock(call); grpc_call_internal_unref(call, 0); From e889314fa2ff4d755c400a481831cc0c39a4c893 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 16:02:01 -0700 Subject: [PATCH 18/58] Allow round-robin again in flow control --- src/core/transport/chttp2_transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 2261b087a20..3d276b16299 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -893,10 +893,11 @@ static int prepare_write(transport *t) { } /* we should either exhaust window or have no ops left, but not both */ - GPR_ASSERT(s->outgoing_sopb->nops == 0 || s->outgoing_window <= 0); if (s->outgoing_sopb->nops == 0) { s->outgoing_sopb = NULL; schedule_cb(t, s->send_done_closure, 1); + } else if (s->outgoing_window) { + stream_list_add_tail(t, s, WRITABLE); } } From d393f1043155352243a3c6278a9b255d4b381cd6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 16:11:51 -0700 Subject: [PATCH 19/58] Fix uninitialized variable --- src/core/surface/call.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index c6fc56891d4..135ab040ae3 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -821,6 +821,7 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { mdb.list = chain_metadata_from_app(call, data.send_metadata.count, data.send_metadata.metadata); mdb.garbage.head = mdb.garbage.tail = NULL; + mdb.deadline = gpr_inf_future; /* send status */ /* TODO(ctiller): cache common status values */ data = call->request_data[GRPC_IOREQ_SEND_STATUS]; From 7e320ba5187a1c57b8e8144a941f2fe82e4f600b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 16:28:07 -0700 Subject: [PATCH 20/58] Add newline --- src/core/transport/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index bc9f4b43879..987dd4c9180 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -93,4 +93,4 @@ void grpc_transport_op_finish_with_failure(grpc_transport_op *op) { if (op->recv_ops) { op->on_done_recv(op->recv_user_data, 0); } -} \ No newline at end of file +} From 7abc8d21494596d56358b5d8c6c953bee40bd85a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Apr 2015 16:43:55 -0700 Subject: [PATCH 21/58] Add missing clear --- src/core/transport/chttp2_transport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 3d276b16299..7a7c2bdfd48 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1128,6 +1128,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, schedule_nuke_sopb(t, &s->parser.incoming_sopb); if (s->outgoing_sopb) { schedule_nuke_sopb(t, s->outgoing_sopb); + s->outgoing_sopb = NULL; schedule_cb(t, s->send_done_closure, 0); } if (s->cancelled) { From 7d4a96a58b9770ad1cb41492f2afb49d7f3d9fd2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 07:54:07 -0700 Subject: [PATCH 22/58] Publish cancellation metadata --- src/core/transport/chttp2_transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 7a7c2bdfd48..a02fb936770 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -379,6 +379,7 @@ static void maybe_join_window_updates(transport *t, stream *s); static void finish_reads(transport *t); static void add_to_pollset_locked(transport *t, grpc_pollset *pollset); static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op); +static void add_metadata_batch(transport *t, stream *s); /* * CONSTRUCTION/DESTRUCTION/REFCOUNTING @@ -1151,7 +1152,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, default: break; } - + add_metadata_batch(t, s); maybe_finish_read(t, s); } } From 48b9fde74e291d1fcbc2f975c58befb44d7e90d9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 08:04:59 -0700 Subject: [PATCH 23/58] call progress --- src/core/surface/call.c | 79 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 135ab040ae3..21390b59f00 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -610,7 +610,7 @@ static void call_on_done_send(void *pc, int success) { if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, error); finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, error); - finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, error); + finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, GRPC_OP_OK); } call->last_send_contains = 0; call->sending = 0; @@ -698,35 +698,41 @@ static void call_on_done_recv(void *pc, int success) { int unref = 0; lock(call); call->receiving = 0; - 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) { + 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 (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; + unref = 1; + } + finish_read_ops(call); + } else { + finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_ERROR); + finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_ERROR); + finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, GRPC_OP_ERROR); + finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_OP_ERROR); + finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_ERROR); + finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_ERROR); } - 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; - unref = 1; - } - if (!success) { - abort(); - } - finish_read_ops(call); unlock(call); if (unref) { @@ -992,26 +998,27 @@ void grpc_call_destroy(grpc_call *c) { } grpc_call_error grpc_call_cancel(grpc_call *call) { - grpc_transport_op op; - memset(&op, 0, sizeof(op)); - op.cancel_with_status = GRPC_STATUS_CANCELLED; - - execute_op(call, &op); - - return GRPC_CALL_OK; + return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled"); } grpc_call_error grpc_call_cancel_with_status(grpc_call *c, grpc_status_code status, const char *description) { + grpc_transport_op op; grpc_mdstr *details = description ? grpc_mdstr_from_string(c->metadata_context, description) : NULL; + memset(&op, 0, sizeof(op)); + op.cancel_with_status = status; + lock(c); set_status_code(c, STATUS_FROM_API_OVERRIDE, status); set_status_details(c, STATUS_FROM_API_OVERRIDE, details); unlock(c); - return grpc_call_cancel(c); + + execute_op(c, &op); + + return GRPC_CALL_OK; } static void execute_op(grpc_call *call, grpc_transport_op *op) { From 4e87e0076716338039b747a15a1df37f721b188a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 08:49:10 -0700 Subject: [PATCH 24/58] Fix uninitialized variable --- src/core/security/auth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 5d241781f17..4dbc25675b9 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -173,6 +173,7 @@ static void auth_start_transport_op(grpc_call_element *elem, for (i = 0; i < nops; i++) { grpc_stream_op *sop = &ops[i]; if (sop->type != GRPC_OP_METADATA) continue; + calld->op_md_idx = i; calld->sent_initial_metadata = 1; for (l = sop->data.metadata.list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; @@ -230,6 +231,7 @@ static void init_call_elem(grpc_call_element *elem, calld->creds = NULL; calld->host = NULL; calld->method = NULL; + calld->sent_initial_metadata = 0; GPR_ASSERT(!initial_op || !initial_op->send_ops); } From e70413c91607378857e739f496fac034b368ab85 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 10:12:34 -0700 Subject: [PATCH 25/58] Handle reading after cancellation --- src/core/channel/client_channel.c | 46 +++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 642822a2670..0ad108ad6b4 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -58,6 +58,7 @@ typedef struct { /* the sending child (may be null) */ grpc_child_channel *active_child; + grpc_mdctx *mdctx; /* calls waiting for a channel to be ready */ call_data **waiting_children; @@ -92,6 +93,10 @@ struct call_data { grpc_child_call *child_call; } active; grpc_transport_op waiting_op; + struct { + grpc_linked_mdelem status; + grpc_linked_mdelem details; + } cancelled; } s; }; @@ -185,12 +190,38 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) { chand->waiting_child_count = new_count; } -static void send_up_cancelled_ops(grpc_call_element *elem) { abort(); } +static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (op->send_ops) { + op->on_done_send(op->send_user_data, 0); + } + if (op->recv_ops) { + char status[GPR_LTOA_MIN_BUFSIZE]; + grpc_metadata_batch mdb; + gpr_ltoa(GRPC_STATUS_CANCELLED, status); + calld->s.cancelled.status.md = grpc_mdelem_from_strings(chand->mdctx, + "grpc-status", status); + calld->s.cancelled.details.md = grpc_mdelem_from_strings(chand->mdctx, + "grpc-message", "Cancelled"); + calld->s.cancelled.status.prev = calld->s.cancelled.details.next = NULL; + calld->s.cancelled.status.next = &calld->s.cancelled.details; + calld->s.cancelled.details.prev = &calld->s.cancelled.status; + mdb.list.head = &calld->s.cancelled.status; + mdb.list.tail = &calld->s.cancelled.details; + mdb.garbage.head = mdb.garbage.tail = NULL; + mdb.deadline = gpr_inf_future; + grpc_sopb_add_metadata(op->recv_ops, mdb); + *op->recv_state = GRPC_STREAM_CLOSED; + op->on_done_recv(op->recv_user_data, 1); + } +} static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_call_element *child_elem; + grpc_transport_op waiting_op; gpr_mu_lock(&chand->mu); switch (calld->state) { @@ -200,18 +231,21 @@ static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { child_elem->filter->start_transport_op(child_elem, op); return; /* early out */ case CALL_WAITING: + waiting_op = calld->s.waiting_op; remove_waiting_child(chand, calld); calld->state = CALL_CANCELLED; gpr_mu_unlock(&chand->mu); - send_up_cancelled_ops(elem); + handle_op_after_cancellation(elem, &waiting_op); + handle_op_after_cancellation(elem, op); return; /* early out */ case CALL_CREATED: calld->state = CALL_CANCELLED; gpr_mu_unlock(&chand->mu); - send_up_cancelled_ops(elem); + handle_op_after_cancellation(elem, op); return; /* early out */ case CALL_CANCELLED: gpr_mu_unlock(&chand->mu); + handle_op_after_cancellation(elem, op); return; /* early out */ } gpr_log(GPR_ERROR, "should never reach here"); @@ -232,6 +266,11 @@ static void cc_start_transport_op(grpc_call_element *elem, return; } + if (calld->state == CALL_CANCELLED) { + handle_op_after_cancellation(elem, op); + return; + } + if (!calld->got_first_op) { calld->got_first_op = 1; start_rpc(elem, op); @@ -371,6 +410,7 @@ static void init_channel_elem(grpc_channel_element *elem, chand->transport_setup = NULL; chand->transport_setup_initiated = 0; chand->args = grpc_channel_args_copy(args); + chand->mdctx = metadata_context; } /* Destructor for channel_data */ From f87b60916970ca0e4ea0a512dd0b1fe1069898b0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 10:13:05 -0700 Subject: [PATCH 26/58] Fix array size --- test/core/transport/stream_op_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/transport/stream_op_test.c b/test/core/transport/stream_op_test.c index 613acd62072..546080deb90 100644 --- a/test/core/transport/stream_op_test.c +++ b/test/core/transport/stream_op_test.c @@ -76,7 +76,7 @@ int main(int argc, char **argv) { grpc_sopb_add_no_op(&buf); /* verify that the data went in ok */ - GPR_ASSERT(buf.nops == 7); + GPR_ASSERT(buf.nops == 6); GPR_ASSERT(buf.ops[0].type == GRPC_OP_BEGIN_MESSAGE); GPR_ASSERT(buf.ops[0].data.begin_message.length == 1); GPR_ASSERT(buf.ops[0].data.begin_message.flags == 2); From a940752deefd463fd07eb529af715813d7fdcd8d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 10:37:57 -0700 Subject: [PATCH 27/58] Take a lock every time through client_channel - to simplify logic and ensure correctness --- src/core/channel/client_channel.c | 174 +++++++++++++----------------- src/core/surface/call.c | 8 -- 2 files changed, 76 insertions(+), 106 deletions(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 0ad108ad6b4..b9a489e0cc3 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -83,8 +83,6 @@ struct call_data { /* owning element */ grpc_call_element *elem; - gpr_uint8 got_first_op; - call_state state; gpr_timespec deadline; union { @@ -129,55 +127,6 @@ static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) { child_elem->filter->start_transport_op(child_elem, op); } -static void start_rpc(grpc_call_element *elem, grpc_transport_op *op) { - call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - gpr_mu_lock(&chand->mu); - if (calld->state == CALL_CANCELLED) { - gpr_mu_unlock(&chand->mu); - grpc_transport_op_finish_with_failure(op); - return; - } - GPR_ASSERT(calld->state == CALL_CREATED); - calld->state = CALL_WAITING; - if (chand->active_child) { - /* channel is connected - use the connected stack */ - if (prepare_activate(elem, chand->active_child)) { - gpr_mu_unlock(&chand->mu); - /* activate the request (pass it down) outside the lock */ - complete_activate(elem, op); - } else { - gpr_mu_unlock(&chand->mu); - } - } else { - /* check to see if we should initiate a connection (if we're not already), - but don't do so until outside the lock to avoid re-entrancy problems if - the callback is immediate */ - int initiate_transport_setup = 0; - if (!chand->transport_setup_initiated) { - chand->transport_setup_initiated = 1; - initiate_transport_setup = 1; - } - /* add this call to the waiting set to be resumed once we have a child - channel stack, growing the waiting set if needed */ - if (chand->waiting_child_count == chand->waiting_child_capacity) { - chand->waiting_child_capacity = - GPR_MAX(chand->waiting_child_capacity * 2, 8); - chand->waiting_children = - gpr_realloc(chand->waiting_children, - chand->waiting_child_capacity * sizeof(call_data *)); - } - calld->s.waiting_op = *op; - chand->waiting_children[chand->waiting_child_count++] = calld; - gpr_mu_unlock(&chand->mu); - - /* finally initiate transport setup if needed */ - if (initiate_transport_setup) { - grpc_transport_setup_initiate(chand->transport_setup); - } - } -} - static void remove_waiting_child(channel_data *chand, call_data *calld) { size_t new_count; size_t i; @@ -217,11 +166,14 @@ static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport } } -static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { +static void cc_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_call_element *child_elem; grpc_transport_op waiting_op; + GPR_ASSERT(elem->filter == &grpc_client_channel_filter); + GRPC_CALL_LOG_OP(GPR_INFO, elem, op); gpr_mu_lock(&chand->mu); switch (calld->state) { @@ -229,55 +181,82 @@ static void cancel_rpc(grpc_call_element *elem, grpc_transport_op *op) { child_elem = grpc_child_call_get_top_element(calld->s.active.child_call); gpr_mu_unlock(&chand->mu); child_elem->filter->start_transport_op(child_elem, op); - return; /* early out */ - case CALL_WAITING: - waiting_op = calld->s.waiting_op; - remove_waiting_child(chand, calld); - calld->state = CALL_CANCELLED; - gpr_mu_unlock(&chand->mu); - handle_op_after_cancellation(elem, &waiting_op); - handle_op_after_cancellation(elem, op); - return; /* early out */ + break; case CALL_CREATED: - calld->state = CALL_CANCELLED; - gpr_mu_unlock(&chand->mu); - handle_op_after_cancellation(elem, op); - return; /* early out */ + if (op->cancel_with_status != GRPC_STATUS_OK) { + calld->state = CALL_CANCELLED; + gpr_mu_unlock(&chand->mu); + handle_op_after_cancellation(elem, op); + } else { + calld->state = CALL_WAITING; + if (chand->active_child) { + /* channel is connected - use the connected stack */ + if (prepare_activate(elem, chand->active_child)) { + gpr_mu_unlock(&chand->mu); + /* activate the request (pass it down) outside the lock */ + complete_activate(elem, op); + } else { + gpr_mu_unlock(&chand->mu); + } + } else { + /* check to see if we should initiate a connection (if we're not already), + but don't do so until outside the lock to avoid re-entrancy problems if + the callback is immediate */ + int initiate_transport_setup = 0; + if (!chand->transport_setup_initiated) { + chand->transport_setup_initiated = 1; + initiate_transport_setup = 1; + } + /* add this call to the waiting set to be resumed once we have a child + channel stack, growing the waiting set if needed */ + if (chand->waiting_child_count == chand->waiting_child_capacity) { + chand->waiting_child_capacity = + GPR_MAX(chand->waiting_child_capacity * 2, 8); + chand->waiting_children = + gpr_realloc(chand->waiting_children, + chand->waiting_child_capacity * sizeof(call_data *)); + } + calld->s.waiting_op = *op; + chand->waiting_children[chand->waiting_child_count++] = calld; + gpr_mu_unlock(&chand->mu); + + /* finally initiate transport setup if needed */ + if (initiate_transport_setup) { + grpc_transport_setup_initiate(chand->transport_setup); + } + } + } + break; + case CALL_WAITING: + if (op->cancel_with_status != GRPC_STATUS_OK) { + waiting_op = calld->s.waiting_op; + remove_waiting_child(chand, calld); + calld->state = CALL_CANCELLED; + gpr_mu_unlock(&chand->mu); + handle_op_after_cancellation(elem, &waiting_op); + handle_op_after_cancellation(elem, op); + } else { + GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) != (op->send_ops == NULL)); + GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) != (op->recv_ops == NULL)); + if (op->send_ops) { + calld->s.waiting_op.send_ops = op->send_ops; + calld->s.waiting_op.is_last_send = op->is_last_send; + calld->s.waiting_op.on_done_send = op->on_done_send; + calld->s.waiting_op.send_user_data = op->send_user_data; + } + if (op->recv_ops) { + calld->s.waiting_op.recv_ops = op->recv_ops; + calld->s.waiting_op.recv_state = op->recv_state; + calld->s.waiting_op.on_done_recv = op->on_done_recv; + calld->s.waiting_op.recv_user_data = op->recv_user_data; + } + gpr_mu_unlock(&chand->mu); + } + break; case CALL_CANCELLED: gpr_mu_unlock(&chand->mu); handle_op_after_cancellation(elem, op); - return; /* early out */ - } - gpr_log(GPR_ERROR, "should never reach here"); - abort(); -} - -static void cc_start_transport_op(grpc_call_element *elem, - grpc_transport_op *op) { - call_data *calld = elem->call_data; - GPR_ASSERT(elem->filter == &grpc_client_channel_filter); - GRPC_CALL_LOG_OP(GPR_INFO, elem, op); - - if (op->cancel_with_status != GRPC_STATUS_OK) { - GPR_ASSERT(op->send_ops == NULL); - GPR_ASSERT(op->recv_ops == NULL); - - cancel_rpc(elem, op); - return; - } - - if (calld->state == CALL_CANCELLED) { - handle_op_after_cancellation(elem, op); - return; - } - - if (!calld->got_first_op) { - calld->got_first_op = 1; - start_rpc(elem, op); - } else { - grpc_call_element *child_elem = - grpc_child_call_get_top_element(calld->s.active.child_call); - child_elem->filter->start_transport_op(child_elem, op); + break; } } @@ -375,7 +354,6 @@ static void init_call_elem(grpc_call_element *elem, calld->elem = elem; calld->state = CALL_CREATED; calld->deadline = gpr_inf_future; - calld->got_first_op = 0; } /* Destructor for call_data */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 21390b59f00..dbf78f2cfe4 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -302,10 +302,6 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, call->receiving = 1; grpc_call_internal_ref(call); initial_op_ptr = &initial_op; - } else { - /* we clear this when we've sent initial metadata -- this is very much - a hack to avoid two ops ending up in client_channel */ - call->receiving = 2; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, CALL_STACK_FROM_CALL(call)); @@ -599,10 +595,6 @@ static void call_on_done_send(void *pc, int success) { lock(call); if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error); - if (call->is_client) { - GPR_ASSERT(call->receiving == 2); - call->receiving = 0; - } } if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) { finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error); From c1f7560ac27b6db4106115e5308f1a9124378a60 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 11:44:53 -0700 Subject: [PATCH 28/58] Stream mapping fixes --- src/core/surface/call.c | 9 ++++++--- src/core/transport/chttp2_transport.c | 12 ++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index dbf78f2cfe4..2f514465fc7 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -687,7 +687,7 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) { static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; - int unref = 0; + int unref_due_to_connection_close = 0; lock(call); call->receiving = 0; if (success) { @@ -714,7 +714,7 @@ static void call_on_done_recv(void *pc, int success) { if (call->recv_state == GRPC_STREAM_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; - unref = 1; + unref_due_to_connection_close = 1; } finish_read_ops(call); } else { @@ -725,9 +725,11 @@ static void call_on_done_recv(void *pc, int success) { finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_ERROR); finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_ERROR); } + call->recv_ops.nops = 0; unlock(call); - if (unref) { + grpc_call_internal_unref(call, 0); + if (unref_due_to_connection_close) { grpc_call_internal_unref(call, 0); } } @@ -798,6 +800,7 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { op->bind_pollset = grpc_cq_pollset(call->cq); call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA; call->write_state = WRITE_STATE_STARTED; + call->send_initial_metadata_count = 0; /* fall through intended */ case WRITE_STATE_STARTED: if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index a02fb936770..237def41aa6 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -306,7 +306,6 @@ struct stream { gpr_uint8 send_closed; gpr_uint8 read_closed; gpr_uint8 cancelled; - gpr_uint8 published_close; op_closure send_done_closure; op_closure recv_done_closure; @@ -731,6 +730,8 @@ static void stream_list_join(transport *t, stream *s, stream_list_id id) { static void remove_from_stream_map(transport *t, stream *s) { if (s->id == 0) return; + IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Removing stream %d", t->is_client? "CLI" : "SVR", + s->id)); if (grpc_chttp2_stream_map_delete(&t->stream_map, s->id)) { maybe_start_some_streams(t); } @@ -999,6 +1000,8 @@ static void maybe_start_some_streams(transport *t) { stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY); if (!s) break; + IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Allocating new stream %p to id %d", t->is_client? "CLI" : "SVR", s, t->next_stream_id)); + GPR_ASSERT(s->id == 0); s->id = t->next_stream_id; t->next_stream_id += 2; @@ -1018,6 +1021,7 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { s->write_state = WRITE_STATE_QUEUED_CLOSE; } if (s->id == 0) { + IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: New stream %p waiting for concurrency", t->is_client? "CLI" : "SVR", s)); stream_list_join(t, s, WAITING_FOR_CONCURRENCY); maybe_start_some_streams(t); } else if (s->outgoing_window > 0) { @@ -1300,7 +1304,8 @@ static void on_header(void *tp, grpc_mdelem *md) { GPR_ASSERT(s); - IF_TRACING(gpr_log(GPR_INFO, "HTTP:%d:HDR: %s: %s", s->id, + IF_TRACING(gpr_log(GPR_INFO, "HTTP:%d:%s:HDR: %s: %s", s->id, + t->is_client? "CLI" : "SVR", grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); @@ -1872,6 +1877,9 @@ static void finish_reads(transport *t) { if (*s->publish_state != s->published_state) { s->published_state = *s->publish_state; publish = 1; + if (s->published_state == GRPC_STREAM_CLOSED) { + remove_from_stream_map(t, s); + } } if (s->parser.incoming_sopb.nops > 0) { grpc_sopb_swap(s->incoming_sopb, &s->parser.incoming_sopb); From 2ea37fd2ce9046ccf2a0b89ba43c93d8fe80408a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:03:49 -0700 Subject: [PATCH 29/58] Bug fixing --- src/core/channel/channel_stack.h | 3 -- src/core/security/auth.c | 14 ++--- src/core/surface/call.c | 1 - src/core/transport/chttp2_transport.c | 65 +++++++++++++----------- src/core/transport/transport.c | 9 ++++ src/core/transport/transport.h | 3 ++ src/core/transport/transport_op_string.c | 4 ++ 7 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h index 94b12639fc8..de0e4e45184 100644 --- a/src/core/channel/channel_stack.h +++ b/src/core/channel/channel_stack.h @@ -222,9 +222,6 @@ void grpc_call_log_op(char *file, int line, gpr_log_severity severity, grpc_call_element *elem, grpc_transport_op *op); void grpc_call_element_send_cancel(grpc_call_element *cur_elem); -void grpc_call_element_recv_status(grpc_call_element *cur_elem, - grpc_status_code status, - const char *message); extern int grpc_trace_channel; diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 4dbc25675b9..b6a002d43c4 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -67,11 +67,6 @@ typedef struct { grpc_mdstr *status_key; } channel_data; -static void bubbleup_error(grpc_call_element *elem, const char *error_msg) { - grpc_call_element_recv_status(elem, GRPC_STATUS_UNAUTHENTICATED, error_msg); - grpc_call_element_send_cancel(elem); -} - static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, size_t num_md, grpc_credentials_status status) { @@ -141,6 +136,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_transport_op *o static void on_host_checked(void *user_data, grpc_security_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; if (status == GRPC_SECURITY_OK) { send_security_metadata(elem, &calld->op); @@ -148,9 +144,9 @@ static void on_host_checked(void *user_data, grpc_security_status status) { char *error_msg; gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", grpc_mdstr_as_c_string(calld->host)); - bubbleup_error(elem, error_msg); + grpc_transport_op_add_cancellation(&calld->op, GRPC_STATUS_UNAUTHENTICATED, grpc_mdstr_from_string(chand->md_ctx, error_msg)); gpr_free(error_msg); - grpc_transport_op_finish_with_failure(&calld->op); + grpc_call_next_op(elem, &calld->op); } } @@ -199,9 +195,9 @@ static void auth_start_transport_op(grpc_call_element *elem, gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", call_host); - bubbleup_error(elem, error_msg); + grpc_transport_op_add_cancellation(&calld->op, GRPC_STATUS_UNAUTHENTICATED, grpc_mdstr_from_string(channeld->md_ctx, error_msg)); gpr_free(error_msg); - grpc_transport_op_finish_with_failure(&calld->op); + grpc_call_next_op(elem, &calld->op); } return; /* early exit */ } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 2f514465fc7..8eee67bb831 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -424,7 +424,6 @@ static void unlock(grpc_call *call) { memset(&op, 0, sizeof(op)); if (!call->receiving && - (call->write_state >= WRITE_STATE_STARTED || !call->is_client) && need_more_data(call)) { op.recv_ops = &call->recv_ops; op.recv_state = &call->recv_state; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 237def41aa6..7b50e285d0d 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -361,7 +361,8 @@ static void cancel_stream_id(transport *t, gpr_uint32 id, grpc_chttp2_error_code error_code, int send_rst); static void cancel_stream(transport *t, stream *s, grpc_status_code local_status, - grpc_chttp2_error_code error_code, int send_rst); + grpc_chttp2_error_code error_code, + grpc_mdstr *optional_message, int send_rst); static void finalize_cancellations(transport *t); static stream *lookup_stream(transport *t, gpr_uint32 id); static void remove_from_stream_map(transport *t, stream *s); @@ -1011,6 +1012,12 @@ static void maybe_start_some_streams(transport *t) { } static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { + if (op->cancel_with_status != GRPC_STATUS_OK) { + cancel_stream( + t, s, op->cancel_with_status, + grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), op->cancel_message, 1); + } + if (op->send_ops) { GPR_ASSERT(s->outgoing_sopb == NULL); s->send_done_closure.cb = op->on_done_send; @@ -1037,26 +1044,16 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { GPR_ASSERT(s->incoming_sopb == NULL); s->recv_done_closure.cb = op->on_done_recv; s->recv_done_closure.user_data = op->recv_user_data; - if (!s->cancelled) { - s->incoming_sopb = op->recv_ops; - s->incoming_sopb->nops = 0; - s->publish_state = op->recv_state; - maybe_finish_read(t, s); - maybe_join_window_updates(t, s); - } else { - schedule_cb(t, s->recv_done_closure, 0); - } + s->incoming_sopb = op->recv_ops; + s->incoming_sopb->nops = 0; + s->publish_state = op->recv_state; + maybe_finish_read(t, s); + maybe_join_window_updates(t, s); } if (op->bind_pollset) { add_to_pollset_locked(t, op->bind_pollset); } - - if (op->cancel_with_status != GRPC_STATUS_OK) { - cancel_stream( - t, s, op->cancel_with_status, - grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), 1); - } } static void perform_op(grpc_transport *gt, grpc_stream *gs, @@ -1123,6 +1120,7 @@ static void add_incoming_metadata(transport *t, stream *s, grpc_mdelem *elem) { static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, grpc_status_code local_status, grpc_chttp2_error_code error_code, + grpc_mdstr *optional_message, int send_rst) { int had_outgoing; char buffer[GPR_LTOA_MIN_BUFSIZE]; @@ -1147,14 +1145,18 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, add_incoming_metadata( t, s, grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer)); - switch (local_status) { - case GRPC_STATUS_CANCELLED: - add_incoming_metadata( - t, s, grpc_mdelem_from_strings(t->metadata_context, - "grpc-message", "Cancelled")); - break; - default: - break; + if (!optional_message) { + switch (local_status) { + case GRPC_STATUS_CANCELLED: + add_incoming_metadata( + t, s, grpc_mdelem_from_strings(t->metadata_context, + "grpc-message", "Cancelled")); + break; + default: + break; + } + } else { + add_incoming_metadata(t, s, grpc_mdelem_from_metadata_strings(t->metadata_context, grpc_mdstr_from_string(t->metadata_context, "grpc-message"), grpc_mdstr_ref(optional_message))); } add_metadata_batch(t, s); maybe_finish_read(t, s); @@ -1165,24 +1167,27 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_rst_stream_create(id, error_code)); } + if (optional_message) { + grpc_mdstr_unref(optional_message); + } } static void cancel_stream_id(transport *t, gpr_uint32 id, grpc_status_code local_status, grpc_chttp2_error_code error_code, int send_rst) { cancel_stream_inner(t, lookup_stream(t, id), id, local_status, error_code, - send_rst); + NULL, send_rst); } static void cancel_stream(transport *t, stream *s, grpc_status_code local_status, - grpc_chttp2_error_code error_code, int send_rst) { - cancel_stream_inner(t, s, s->id, local_status, error_code, send_rst); + grpc_chttp2_error_code error_code, grpc_mdstr *optional_message, int send_rst) { + cancel_stream_inner(t, s, s->id, local_status, error_code, optional_message, send_rst); } static void cancel_stream_cb(void *user_data, gpr_uint32 id, void *stream) { cancel_stream(user_data, stream, GRPC_STATUS_UNAVAILABLE, - GRPC_CHTTP2_INTERNAL_ERROR, 0); + GRPC_CHTTP2_INTERNAL_ERROR, NULL, 0); } static void end_all_the_calls(transport *t) { @@ -1285,7 +1290,7 @@ static int init_data_frame_parser(transport *t) { case GRPC_CHTTP2_STREAM_ERROR: cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status( GRPC_CHTTP2_INTERNAL_ERROR), - GRPC_CHTTP2_INTERNAL_ERROR, 1); + GRPC_CHTTP2_INTERNAL_ERROR, NULL, 1); return init_skip_frame(t, 0); case GRPC_CHTTP2_CONNECTION_ERROR: drop_connection(t); @@ -1598,7 +1603,7 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { if (!is_window_update_legal(st.window_update, s->outgoing_window)) { cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status( GRPC_CHTTP2_FLOW_CONTROL_ERROR), - GRPC_CHTTP2_FLOW_CONTROL_ERROR, 1); + GRPC_CHTTP2_FLOW_CONTROL_ERROR, NULL, 1); } else { s->outgoing_window += st.window_update; /* if this window update makes outgoing ops writable again, diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index 987dd4c9180..cc9392177fd 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -94,3 +94,12 @@ void grpc_transport_op_finish_with_failure(grpc_transport_op *op) { op->on_done_recv(op->recv_user_data, 0); } } + +void grpc_transport_op_add_cancellation(grpc_transport_op *op, grpc_status_code status, grpc_mdstr *message) { + if (op->cancel_with_status == GRPC_STATUS_OK) { + op->cancel_with_status = status; + op->cancel_message = message; + } else if (message) { + grpc_mdstr_unref(message); + } +} diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 5036dfc2de2..7c4bed1863a 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -75,6 +75,7 @@ typedef struct grpc_transport_op { grpc_pollset *bind_pollset; grpc_status_code cancel_with_status; + grpc_mdstr *cancel_message; } grpc_transport_op; /* Callbacks made from the transport to the upper layers of grpc. */ @@ -134,6 +135,8 @@ void grpc_transport_destroy_stream(grpc_transport *transport, void grpc_transport_op_finish_with_failure(grpc_transport_op *op); +void grpc_transport_op_add_cancellation(grpc_transport_op *op, grpc_status_code status, grpc_mdstr *message); + /* TODO(ctiller): remove this */ void grpc_transport_add_to_pollset(grpc_transport *transport, grpc_pollset *pollset); diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index 54f501f8980..b9283b7abf0 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -139,6 +139,10 @@ char *grpc_transport_op_string(grpc_transport_op *op) { first = 0; gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); gpr_strvec_add(&b, tmp); + if (op->cancel_message) { + gpr_asprintf(&tmp, ";msg='%s'", grpc_mdstr_as_c_string(op->cancel_message)); + gpr_strvec_add(&b, tmp); + } } out = gpr_strvec_flatten(&b, NULL); From 60de66cf7da81585038ad6afa1c857b3f6e3b70c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:14:06 -0700 Subject: [PATCH 30/58] Always wait for all ops to finish --- src/core/surface/call.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 8eee67bb831..2f5bd94cff4 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -529,7 +529,6 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op, master->complete_mask |= 1u << op; if (status != GRPC_OP_OK) { master->status = status; - master->complete_mask = master->need_mask; } if (master->complete_mask == master->need_mask) { for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) { From c52779ff61ca5d79d9ecc5b68976a08933078af4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:19:48 -0700 Subject: [PATCH 31/58] Add missing remove list --- src/core/transport/chttp2_transport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 7b50e285d0d..7c3f40e3b93 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1132,6 +1132,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, if (s->outgoing_sopb) { schedule_nuke_sopb(t, s->outgoing_sopb); s->outgoing_sopb = NULL; + stream_list_remove(t, s, WRITABLE); schedule_cb(t, s->send_done_closure, 0); } if (s->cancelled) { From 1a727fde47d56b42703aedf7e672b1f4e9c7d1c2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:21:22 -0700 Subject: [PATCH 32/58] clang-format --- src/core/channel/client_channel.c | 29 +- src/core/security/auth.c | 26 +- src/core/security/server_secure_chttp2.c | 3 +- src/core/surface/call.c | 3 +- src/core/surface/secure_channel_create.c | 2 +- src/core/transport/chttp2_transport.c | 39 +- src/core/transport/transport.c | 4 +- src/core/transport/transport.h | 4 +- src/core/transport/transport_op_string.c | 3 +- .../Grpc.Core/Internal/CallSafeHandle.cs | 357 ++++++++++-------- .../Grpc.Core/Internal/ServerSafeHandle.cs | 163 ++++---- src/csharp/Grpc.Core/Server.cs | 335 ++++++++-------- .../Grpc.Examples.MathServer/MathServer.cs | 36 +- .../Grpc.IntegrationTesting.csproj | 3 +- src/ruby/ext/grpc/rb_call.c | 122 +++--- test/core/channel/channel_stack_test.c | 11 +- .../chttp2_socket_pair_one_byte_at_a_time.c | 9 +- 17 files changed, 596 insertions(+), 553 deletions(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index b9a489e0cc3..78f8d06d89f 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -139,7 +139,8 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) { chand->waiting_child_count = new_count; } -static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport_op *op) { +static void handle_op_after_cancellation(grpc_call_element *elem, + grpc_transport_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; if (op->send_ops) { @@ -149,10 +150,10 @@ static void handle_op_after_cancellation(grpc_call_element *elem, grpc_transport char status[GPR_LTOA_MIN_BUFSIZE]; grpc_metadata_batch mdb; gpr_ltoa(GRPC_STATUS_CANCELLED, status); - calld->s.cancelled.status.md = grpc_mdelem_from_strings(chand->mdctx, - "grpc-status", status); - calld->s.cancelled.details.md = grpc_mdelem_from_strings(chand->mdctx, - "grpc-message", "Cancelled"); + calld->s.cancelled.status.md = + grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status); + calld->s.cancelled.details.md = + grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled"); calld->s.cancelled.status.prev = calld->s.cancelled.details.next = NULL; calld->s.cancelled.status.next = &calld->s.cancelled.details; calld->s.cancelled.details.prev = &calld->s.cancelled.status; @@ -199,8 +200,10 @@ static void cc_start_transport_op(grpc_call_element *elem, gpr_mu_unlock(&chand->mu); } } else { - /* check to see if we should initiate a connection (if we're not already), - but don't do so until outside the lock to avoid re-entrancy problems if + /* check to see if we should initiate a connection (if we're not + already), + but don't do so until outside the lock to avoid re-entrancy + problems if the callback is immediate */ int initiate_transport_setup = 0; if (!chand->transport_setup_initiated) { @@ -212,9 +215,9 @@ static void cc_start_transport_op(grpc_call_element *elem, if (chand->waiting_child_count == chand->waiting_child_capacity) { chand->waiting_child_capacity = GPR_MAX(chand->waiting_child_capacity * 2, 8); - chand->waiting_children = - gpr_realloc(chand->waiting_children, - chand->waiting_child_capacity * sizeof(call_data *)); + chand->waiting_children = gpr_realloc( + chand->waiting_children, + chand->waiting_child_capacity * sizeof(call_data *)); } calld->s.waiting_op = *op; chand->waiting_children[chand->waiting_child_count++] = calld; @@ -236,8 +239,10 @@ static void cc_start_transport_op(grpc_call_element *elem, handle_op_after_cancellation(elem, &waiting_op); handle_op_after_cancellation(elem, op); } else { - GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) != (op->send_ops == NULL)); - GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) != (op->recv_ops == NULL)); + GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) != + (op->send_ops == NULL)); + GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) != + (op->recv_ops == NULL)); if (op->send_ops) { calld->s.waiting_op.send_ops = op->send_ops; calld->s.waiting_op.is_last_send = op->is_last_send; diff --git a/src/core/security/auth.c b/src/core/security/auth.c index b6a002d43c4..2322c12aa54 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -76,7 +76,8 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, grpc_metadata_batch *mdb; size_t i; GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); - GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx && op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); + GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx && + op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata; for (i = 0; i < num_md; i++) { grpc_metadata_batch_add_tail(mdb, &calld->md_links[i], @@ -105,7 +106,8 @@ static char *build_service_url(const char *url_scheme, call_data *calld) { return service_url; } -static void send_security_metadata(grpc_call_element *elem, grpc_transport_op *op) { +static void send_security_metadata(grpc_call_element *elem, + grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -144,7 +146,9 @@ static void on_host_checked(void *user_data, grpc_security_status status) { char *error_msg; gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", grpc_mdstr_as_c_string(calld->host)); - grpc_transport_op_add_cancellation(&calld->op, GRPC_STATUS_UNAUTHENTICATED, grpc_mdstr_from_string(chand->md_ctx, error_msg)); + grpc_transport_op_add_cancellation( + &calld->op, GRPC_STATUS_UNAUTHENTICATED, + grpc_mdstr_from_string(chand->md_ctx, error_msg)); gpr_free(error_msg); grpc_call_next_op(elem, &calld->op); } @@ -155,8 +159,8 @@ static void on_host_checked(void *user_data, grpc_security_status status) { - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ -static void auth_start_transport_op(grpc_call_element *elem, - grpc_transport_op *op) { +static void auth_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; @@ -195,7 +199,9 @@ static void auth_start_transport_op(grpc_call_element *elem, gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.", call_host); - grpc_transport_op_add_cancellation(&calld->op, GRPC_STATUS_UNAUTHENTICATED, grpc_mdstr_from_string(channeld->md_ctx, error_msg)); + grpc_transport_op_add_cancellation( + &calld->op, GRPC_STATUS_UNAUTHENTICATED, + grpc_mdstr_from_string(channeld->md_ctx, error_msg)); gpr_free(error_msg); grpc_call_next_op(elem, &calld->op); } @@ -220,7 +226,8 @@ static void channel_op(grpc_channel_element *elem, /* Constructor for call_data */ static void init_call_elem(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { /* TODO(jboeuf): Find a way to pass-in the credentials from the caller here. */ call_data *calld = elem->call_data; @@ -297,5 +304,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { } const grpc_channel_filter grpc_client_auth_filter = { - auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, - sizeof(channel_data), init_channel_elem, destroy_channel_elem, "auth"}; + auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "auth"}; diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 0698161b6d6..db9d545c0e6 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -72,7 +72,8 @@ static void state_unref(grpc_server_secure_state *state) { static grpc_transport_setup_result setup_transport(void *server, grpc_transport *transport, grpc_mdctx *mdctx) { - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; + static grpc_channel_filter const *extra_filters[] = { + &grpc_http_server_filter}; return grpc_server_setup_transport(server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 2f5bd94cff4..7c91ca917c3 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -423,8 +423,7 @@ static void unlock(grpc_call *call) { memset(&op, 0, sizeof(op)); - if (!call->receiving && - need_more_data(call)) { + if (!call->receiving && need_more_data(call)) { op.recv_ops = &call->recv_ops; op.recv_state = &call->recv_state; op.on_done_recv = call_on_done_recv; diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index 0bcbe38131b..3e331293b5d 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -210,7 +210,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, grpc_arg connector_arg; grpc_channel_args *args_copy; grpc_channel_args *new_args_from_connector; - grpc_channel_security_connector* connector; + grpc_channel_security_connector *connector; grpc_mdctx *mdctx; #define MAX_FILTERS 3 const grpc_channel_filter *filters[MAX_FILTERS]; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 7c3f40e3b93..52de8c218f0 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -361,7 +361,7 @@ static void cancel_stream_id(transport *t, gpr_uint32 id, grpc_chttp2_error_code error_code, int send_rst); static void cancel_stream(transport *t, stream *s, grpc_status_code local_status, - grpc_chttp2_error_code error_code, + grpc_chttp2_error_code error_code, grpc_mdstr *optional_message, int send_rst); static void finalize_cancellations(transport *t); static stream *lookup_stream(transport *t, gpr_uint32 id); @@ -731,8 +731,8 @@ static void stream_list_join(transport *t, stream *s, stream_list_id id) { static void remove_from_stream_map(transport *t, stream *s) { if (s->id == 0) return; - IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Removing stream %d", t->is_client? "CLI" : "SVR", - s->id)); + IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Removing stream %d", + t->is_client ? "CLI" : "SVR", s->id)); if (grpc_chttp2_stream_map_delete(&t->stream_map, s->id)) { maybe_start_some_streams(t); } @@ -1001,7 +1001,8 @@ static void maybe_start_some_streams(transport *t) { stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY); if (!s) break; - IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Allocating new stream %p to id %d", t->is_client? "CLI" : "SVR", s, t->next_stream_id)); + IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Allocating new stream %p to id %d", + t->is_client ? "CLI" : "SVR", s, t->next_stream_id)); GPR_ASSERT(s->id == 0); s->id = t->next_stream_id; @@ -1015,7 +1016,8 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { if (op->cancel_with_status != GRPC_STATUS_OK) { cancel_stream( t, s, op->cancel_with_status, - grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), op->cancel_message, 1); + grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status), + op->cancel_message, 1); } if (op->send_ops) { @@ -1028,7 +1030,9 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { s->write_state = WRITE_STATE_QUEUED_CLOSE; } if (s->id == 0) { - IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: New stream %p waiting for concurrency", t->is_client? "CLI" : "SVR", s)); + IF_TRACING(gpr_log(GPR_DEBUG, + "HTTP:%s: New stream %p waiting for concurrency", + t->is_client ? "CLI" : "SVR", s)); stream_list_join(t, s, WAITING_FOR_CONCURRENCY); maybe_start_some_streams(t); } else if (s->outgoing_window > 0) { @@ -1120,8 +1124,7 @@ static void add_incoming_metadata(transport *t, stream *s, grpc_mdelem *elem) { static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, grpc_status_code local_status, grpc_chttp2_error_code error_code, - grpc_mdstr *optional_message, - int send_rst) { + grpc_mdstr *optional_message, int send_rst) { int had_outgoing; char buffer[GPR_LTOA_MIN_BUFSIZE]; @@ -1157,7 +1160,12 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id, break; } } else { - add_incoming_metadata(t, s, grpc_mdelem_from_metadata_strings(t->metadata_context, grpc_mdstr_from_string(t->metadata_context, "grpc-message"), grpc_mdstr_ref(optional_message))); + add_incoming_metadata( + t, s, + grpc_mdelem_from_metadata_strings( + t->metadata_context, + grpc_mdstr_from_string(t->metadata_context, "grpc-message"), + grpc_mdstr_ref(optional_message))); } add_metadata_batch(t, s); maybe_finish_read(t, s); @@ -1182,8 +1190,10 @@ static void cancel_stream_id(transport *t, gpr_uint32 id, static void cancel_stream(transport *t, stream *s, grpc_status_code local_status, - grpc_chttp2_error_code error_code, grpc_mdstr *optional_message, int send_rst) { - cancel_stream_inner(t, s, s->id, local_status, error_code, optional_message, send_rst); + grpc_chttp2_error_code error_code, + grpc_mdstr *optional_message, int send_rst) { + cancel_stream_inner(t, s, s->id, local_status, error_code, optional_message, + send_rst); } static void cancel_stream_cb(void *user_data, gpr_uint32 id, void *stream) { @@ -1310,10 +1320,9 @@ static void on_header(void *tp, grpc_mdelem *md) { GPR_ASSERT(s); - IF_TRACING(gpr_log(GPR_INFO, "HTTP:%d:%s:HDR: %s: %s", s->id, - t->is_client? "CLI" : "SVR", - grpc_mdstr_as_c_string(md->key), - grpc_mdstr_as_c_string(md->value))); + IF_TRACING(gpr_log( + GPR_INFO, "HTTP:%d:%s:HDR: %s: %s", s->id, t->is_client ? "CLI" : "SVR", + grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); if (md->key == t->str_grpc_timeout) { gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout); diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c index cc9392177fd..d9a1319c42f 100644 --- a/src/core/transport/transport.c +++ b/src/core/transport/transport.c @@ -95,7 +95,9 @@ void grpc_transport_op_finish_with_failure(grpc_transport_op *op) { } } -void grpc_transport_op_add_cancellation(grpc_transport_op *op, grpc_status_code status, grpc_mdstr *message) { +void grpc_transport_op_add_cancellation(grpc_transport_op *op, + grpc_status_code status, + grpc_mdstr *message) { if (op->cancel_with_status == GRPC_STATUS_OK) { op->cancel_with_status = status; op->cancel_message = message; diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 7c4bed1863a..cdea0b9a0b9 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -135,7 +135,9 @@ void grpc_transport_destroy_stream(grpc_transport *transport, void grpc_transport_op_finish_with_failure(grpc_transport_op *op); -void grpc_transport_op_add_cancellation(grpc_transport_op *op, grpc_status_code status, grpc_mdstr *message); +void grpc_transport_op_add_cancellation(grpc_transport_op *op, + grpc_status_code status, + grpc_mdstr *message); /* TODO(ctiller): remove this */ void grpc_transport_add_to_pollset(grpc_transport *transport, diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index b9283b7abf0..a2157109699 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -140,7 +140,8 @@ char *grpc_transport_op_string(grpc_transport_op *op) { gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status); gpr_strvec_add(&b, tmp); if (op->cancel_message) { - gpr_asprintf(&tmp, ";msg='%s'", grpc_mdstr_as_c_string(op->cancel_message)); + gpr_asprintf(&tmp, ";msg='%s'", + grpc_mdstr_as_c_string(op->cancel_message)); gpr_strvec_add(&b, tmp); } } diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 14add60c728..19d3f57abbb 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -1,11 +1,11 @@ #region Copyright notice and license // Copyright 2015, 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 @@ -15,7 +15,7 @@ // * 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 @@ -34,158 +34,203 @@ using System.Diagnostics; using System.Runtime.InteropServices; using Grpc.Core; -namespace Grpc.Core.Internal -{ - internal delegate void CompletionCallbackDelegate(GRPCOpError error, IntPtr batchContextPtr); - - /// - /// grpc_call from - /// - internal class CallSafeHandle : SafeHandleZeroIsInvalid - { - const uint GRPC_WRITE_BUFFER_HINT = 1; - - [DllImport("grpc_csharp_ext.dll")] - static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_call_blocking_unary(CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - byte[] send_buffer, UIntPtr send_buffer_len, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, - byte[] send_buffer, UIntPtr send_buffer_len); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, StatusCode statusCode, string statusMessage); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); - - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); - - [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_call_destroy(IntPtr call); - - private CallSafeHandle() - { - } - - public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) - { - return grpcsharp_channel_create_call(channel, cq, method, host, deadline); - } - - public void StartUnary(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) - { - AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray)); - } - - public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) - { - grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray); - } - - public void StartClientStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) - { - AssertCallOk(grpcsharp_call_start_client_streaming(this, callback, metadataArray)); - } - - public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) - { - AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray)); - } - - public void StartDuplexStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) - { - AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback, metadataArray)); - } - - public void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback) - { - AssertCallOk(grpcsharp_call_send_message(this, callback, payload, new UIntPtr((ulong)payload.Length))); - } - - public void StartSendCloseFromClient(CompletionCallbackDelegate callback) - { - AssertCallOk(grpcsharp_call_send_close_from_client(this, callback)); - } - - public void StartSendStatusFromServer(Status status, CompletionCallbackDelegate callback) - { - AssertCallOk(grpcsharp_call_send_status_from_server(this, callback, status.StatusCode, status.Detail)); - } - - public void StartReceiveMessage(CompletionCallbackDelegate callback) - { - AssertCallOk(grpcsharp_call_recv_message(this, callback)); - } - - public void StartServerSide(CompletionCallbackDelegate callback) - { - AssertCallOk(grpcsharp_call_start_serverside(this, callback)); - } - - public void Cancel() - { - AssertCallOk(grpcsharp_call_cancel(this)); - } - - public void CancelWithStatus(Status status) - { - AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail)); - } - - protected override bool ReleaseHandle() - { - grpcsharp_call_destroy(handle); - return true; - } - - private static void AssertCallOk(GRPCCallError callError) - { - Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK"); - } - - private static uint GetFlags(bool buffered) - { - return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; - } +namespace Grpc.Core.Internal { + internal delegate void CompletionCallbackDelegate(GRPCOpError error, + IntPtr batchContextPtr); + + /// + /// grpc_call from + /// + internal class CallSafeHandle : SafeHandleZeroIsInvalid { + const uint GRPC_WRITE_BUFFER_HINT = 1; + + [DllImport("grpc_csharp_ext.dll")] static extern CallSafeHandle + grpcsharp_channel_create_call(ChannelSafeHandle channel, + CompletionQueueSafeHandle cq, string method, + string host, Timespec deadline); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_cancel(CallSafeHandle call); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, + string description); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_start_unary( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + byte[] send_buffer, UIntPtr send_buffer_len, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] static extern void + grpcsharp_call_blocking_unary( + CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + byte[] send_buffer, UIntPtr send_buffer_len, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_start_client_streaming( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_start_server_streaming( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + byte[] send_buffer, UIntPtr send_buffer_len, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_start_duplex_streaming( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_send_message( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + byte[] send_buffer, UIntPtr send_buffer_len); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_send_close_from_client( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_send_status_from_server( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback, + StatusCode statusCode, string statusMessage); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_recv_message( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback); + + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_call_start_serverside( + CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback); + + [DllImport("grpc_csharp_ext.dll")] static extern void + grpcsharp_call_destroy(IntPtr call); + + private + CallSafeHandle() {} + + public + static CallSafeHandle Create(ChannelSafeHandle channel, + CompletionQueueSafeHandle cq, string method, + string host, Timespec deadline) { + return grpcsharp_channel_create_call(channel, cq, method, host, deadline); } + + public + void StartUnary(byte[] payload, CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray) { + AssertCallOk(grpcsharp_call_start_unary( + this, callback, payload, new UIntPtr((ulong)payload.Length), + metadataArray)); + } + + public + void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, + CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray) { + grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, + new UIntPtr((ulong)payload.Length), + metadataArray); + } + + public + void StartClientStreaming(CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray) { + AssertCallOk( + grpcsharp_call_start_client_streaming(this, callback, metadataArray)); + } + + public + void StartServerStreaming(byte[] payload, + CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray) { + AssertCallOk(grpcsharp_call_start_server_streaming( + this, callback, payload, new UIntPtr((ulong)payload.Length), + metadataArray)); + } + + public + void StartDuplexStreaming(CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray) { + AssertCallOk( + grpcsharp_call_start_duplex_streaming(this, callback, metadataArray)); + } + + public + void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback) { + AssertCallOk(grpcsharp_call_send_message( + this, callback, payload, new UIntPtr((ulong)payload.Length))); + } + + public + void StartSendCloseFromClient(CompletionCallbackDelegate callback) { + AssertCallOk(grpcsharp_call_send_close_from_client(this, callback)); + } + + public + void StartSendStatusFromServer(Status status, + CompletionCallbackDelegate callback) { + AssertCallOk(grpcsharp_call_send_status_from_server( + this, callback, status.StatusCode, status.Detail)); + } + + public + void StartReceiveMessage(CompletionCallbackDelegate callback) { + AssertCallOk(grpcsharp_call_recv_message(this, callback)); + } + + public + void StartServerSide(CompletionCallbackDelegate callback) { + AssertCallOk(grpcsharp_call_start_serverside(this, callback)); + } + + public + void Cancel() { AssertCallOk(grpcsharp_call_cancel(this)); } + + public + void CancelWithStatus(Status status) { + AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, + status.Detail)); + } + + protected + override bool ReleaseHandle() { + grpcsharp_call_destroy(handle); + return true; + } + + private + static void AssertCallOk(GRPCCallError callError) { + Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, + "Status not GRPC_CALL_OK"); + } + + private + static uint GetFlags(bool buffered) { + return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; + } + } } \ No newline at end of file diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs index a59da098221..b56e8d98019 100644 --- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs @@ -36,84 +36,89 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Grpc.Core.Internal -{ - // TODO: we need to make sure that the delegates are not collected before invoked. - internal delegate void ServerShutdownCallbackDelegate(IntPtr eventPtr); - - /// - /// grpc_server from grpc/grpc.h - /// - internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid - { - [DllImport("grpc_csharp_ext.dll")] - static extern GRPCCallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); - - [DllImport("grpc_csharp_ext.dll")] - static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args); - - [DllImport("grpc_csharp_ext.dll")] - static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr); - - [DllImport("grpc_csharp_ext.dll")] - static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds); - - [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_server_start(ServerSafeHandle server); - - [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_server_shutdown(ServerSafeHandle server); - - // TODO: get rid of the old callback style - [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_server_shutdown_and_notify")] - static extern void grpcsharp_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] ServerShutdownCallbackDelegate callback); - - [DllImport("grpc_csharp_ext.dll")] - static extern void grpcsharp_server_destroy(IntPtr server); - - private ServerSafeHandle() - { - } - - public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args) - { - return grpcsharp_server_create(cq, args); - } - - public int AddListeningPort(string addr) - { - return grpcsharp_server_add_http2_port(this, addr); - } - - public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials) - { - return grpcsharp_server_add_secure_http2_port(this, addr, credentials); - } - - public void Start() - { - grpcsharp_server_start(this); - } - - public void Shutdown() - { - grpcsharp_server_shutdown(this); - } - - public void ShutdownAndNotify(ServerShutdownCallbackDelegate callback) - { - grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback); - } - - public GRPCCallError RequestCall(CompletionQueueSafeHandle cq, CompletionCallbackDelegate callback) - { - return grpcsharp_server_request_call(this, cq, callback); - } - - protected override bool ReleaseHandle() - { - grpcsharp_server_destroy(handle); - return true; - } +namespace Grpc.Core.Internal { + // TODO: we need to make sure that the delegates are not collected before + // invoked. + internal delegate void ServerShutdownCallbackDelegate(IntPtr eventPtr); + + /// + /// grpc_server from grpc/grpc.h + /// + internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid { + [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError + grpcsharp_server_request_call( + ServerSafeHandle server, CompletionQueueSafeHandle cq, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate + callback); + + [DllImport("grpc_csharp_ext.dll")] static extern ServerSafeHandle + grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args); + + [DllImport("grpc_csharp_ext.dll")] static extern int + grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr); + + [DllImport("grpc_csharp_ext.dll")] static extern int + grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, + ServerCredentialsSafeHandle creds); + + [DllImport("grpc_csharp_ext.dll")] static extern void + grpcsharp_server_start(ServerSafeHandle server); + + [DllImport("grpc_csharp_ext.dll")] static extern void + grpcsharp_server_shutdown(ServerSafeHandle server); + + // TODO: get rid of the old callback style + [DllImport( + "grpc_csharp_ext.dll", + EntryPoint = "grpcsharp_server_shutdown_and_notify")] static extern void + grpcsharp_server_shutdown_and_notify_CALLBACK( + ServerSafeHandle server, + [MarshalAs(UnmanagedType.FunctionPtr)] ServerShutdownCallbackDelegate + callback); + + [DllImport("grpc_csharp_ext.dll")] static extern void + grpcsharp_server_destroy(IntPtr server); + + private + ServerSafeHandle() {} + + public + static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, + IntPtr args) { + return grpcsharp_server_create(cq, args); } + + public + int AddListeningPort(string addr) { + return grpcsharp_server_add_http2_port(this, addr); + } + + public + int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials) { + return grpcsharp_server_add_secure_http2_port(this, addr, credentials); + } + + public + void Start() { grpcsharp_server_start(this); } + + public + void Shutdown() { grpcsharp_server_shutdown(this); } + + public + void ShutdownAndNotify(ServerShutdownCallbackDelegate callback) { + grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback); + } + + public + GRPCCallError RequestCall(CompletionQueueSafeHandle cq, + CompletionCallbackDelegate callback) { + return grpcsharp_server_request_call(this, cq, callback); + } + + protected + override bool ReleaseHandle() { + grpcsharp_server_destroy(handle); + return true; + } + } } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index f086fa8beb9..308fbfb71c8 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -39,205 +39,186 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; -namespace Grpc.Core -{ - /// - /// Server is implemented only to be able to do - /// in-process testing. - /// - public class Server - { - // TODO: make sure the delegate doesn't get garbage collected while - // native callbacks are in the completion queue. - readonly ServerShutdownCallbackDelegate serverShutdownHandler; - readonly CompletionCallbackDelegate newServerRpcHandler; +namespace Grpc.Core { + /// + /// Server is implemented only to be able to do + /// in-process testing. + /// + public + class Server { + // TODO: make sure the delegate doesn't get garbage collected while + // native callbacks are in the completion queue. + readonly ServerShutdownCallbackDelegate serverShutdownHandler; + readonly CompletionCallbackDelegate newServerRpcHandler; + + readonly BlockingCollection newRpcQueue = + new BlockingCollection(); + readonly ServerSafeHandle handle; + + readonly Dictionary callHandlers = + new Dictionary(); + + readonly TaskCompletionSource shutdownTcs = + new TaskCompletionSource(); + + public + Server() { + this.handle = + ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero); + this.newServerRpcHandler = HandleNewServerRpc; + this.serverShutdownHandler = HandleServerShutdown; + } - readonly BlockingCollection newRpcQueue = new BlockingCollection(); - readonly ServerSafeHandle handle; + // only call this before Start() + public + void AddServiceDefinition(ServerServiceDefinition serviceDefinition) { + foreach (var entry in serviceDefinition.CallHandlers) { + callHandlers.Add(entry.Key, entry.Value); + } + } - readonly Dictionary callHandlers = new Dictionary(); + // only call before Start() + public + int AddListeningPort(string addr) { return handle.AddListeningPort(addr); } - readonly TaskCompletionSource shutdownTcs = new TaskCompletionSource(); + // only call before Start() + public + int AddListeningPort(string addr, ServerCredentials credentials) { + using(var nativeCredentials = credentials.ToNativeCredentials()) { + return handle.AddListeningPort(addr, nativeCredentials); + } + } - public Server() - { - this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero); - this.newServerRpcHandler = HandleNewServerRpc; - this.serverShutdownHandler = HandleServerShutdown; - } + public + void Start() { + handle.Start(); - // only call this before Start() - public void AddServiceDefinition(ServerServiceDefinition serviceDefinition) - { - foreach (var entry in serviceDefinition.CallHandlers) - { - callHandlers.Add(entry.Key, entry.Value); - } - } + // TODO: this basically means the server is single threaded.... + StartHandlingRpcs(); + } - // only call before Start() - public int AddListeningPort(string addr) - { - return handle.AddListeningPort(addr); - } + /// + /// Requests and handles single RPC call. + /// + internal void RunRpc() { + AllowOneRpc(); - // only call before Start() - public int AddListeningPort(string addr, ServerCredentials credentials) - { - using (var nativeCredentials = credentials.ToNativeCredentials()) - { - return handle.AddListeningPort(addr, nativeCredentials); - } - } + try { + var rpcInfo = newRpcQueue.Take(); - public void Start() - { - handle.Start(); + // Console.WriteLine("Server received RPC " + rpcInfo.Method); - // TODO: this basically means the server is single threaded.... - StartHandlingRpcs(); + IServerCallHandler callHandler; + if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler)) { + callHandler = new NoSuchMethodCallHandler(); } + callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, + GetCompletionQueue()); + } catch (Exception e) { + Console.WriteLine("Exception while handling RPC: " + e); + } + } - /// - /// Requests and handles single RPC call. - /// - internal void RunRpc() - { - AllowOneRpc(); - - try - { - var rpcInfo = newRpcQueue.Take(); - - // Console.WriteLine("Server received RPC " + rpcInfo.Method); - - IServerCallHandler callHandler; - if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler)) - { - callHandler = new NoSuchMethodCallHandler(); - } - callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, GetCompletionQueue()); - } - catch (Exception e) - { - Console.WriteLine("Exception while handling RPC: " + e); - } - } + /// + /// Requests server shutdown and when there are no more calls being + /// serviced, + /// cleans up used resources. + /// + /// The async. + public + async Task ShutdownAsync() { + handle.ShutdownAndNotify(serverShutdownHandler); + await shutdownTcs.Task; + handle.Dispose(); + } - /// - /// Requests server shutdown and when there are no more calls being serviced, - /// cleans up used resources. - /// - /// The async. - public async Task ShutdownAsync() - { - handle.ShutdownAndNotify(serverShutdownHandler); - await shutdownTcs.Task; - handle.Dispose(); - } + /// + /// To allow awaiting termination of the server. + /// + public + Task ShutdownTask { + get { return shutdownTcs.Task; } + } - /// - /// To allow awaiting termination of the server. - /// - public Task ShutdownTask - { - get - { - return shutdownTcs.Task; - } - } + public + void Kill() { handle.Dispose(); } - public void Kill() - { - handle.Dispose(); - } + private + async Task StartHandlingRpcs() { + while (true) { + await Task.Factory.StartNew(RunRpc); + } + } - private async Task StartHandlingRpcs() - { - while (true) - { - await Task.Factory.StartNew(RunRpc); - } - } + private + void AllowOneRpc() { + AssertCallOk( + handle.RequestCall(GetCompletionQueue(), newServerRpcHandler)); + } - private void AllowOneRpc() - { - AssertCallOk(handle.RequestCall(GetCompletionQueue(), newServerRpcHandler)); - } + private + void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr) { + try { + var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr); - private void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr) - { - try - { - var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr); - - if (error != GRPCOpError.GRPC_OP_OK) - { - // TODO: handle error - } - - var rpcInfo = new NewRpcInfo(ctx.GetServerRpcNewCall(), ctx.GetServerRpcNewMethod()); - - // after server shutdown, the callback returns with null call - if (!rpcInfo.Call.IsInvalid) - { - newRpcQueue.Add(rpcInfo); - } - } - catch (Exception e) - { - Console.WriteLine("Caught exception in a native handler: " + e); - } + if (error != GRPCOpError.GRPC_OP_OK) { + // TODO: handle error } - private void HandleServerShutdown(IntPtr eventPtr) - { - try - { - shutdownTcs.SetResult(null); - } - catch (Exception e) - { - Console.WriteLine("Caught exception in a native handler: " + e); - } - } + var rpcInfo = new NewRpcInfo(ctx.GetServerRpcNewCall(), + ctx.GetServerRpcNewMethod()); - private static void AssertCallOk(GRPCCallError callError) - { - Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK"); + // after server shutdown, the callback returns with null call + if (!rpcInfo.Call.IsInvalid) { + newRpcQueue.Add(rpcInfo); } + } catch (Exception e) { + Console.WriteLine("Caught exception in a native handler: " + e); + } + } - private static CompletionQueueSafeHandle GetCompletionQueue() - { - return GrpcEnvironment.ThreadPool.CompletionQueue; - } + private + void HandleServerShutdown(IntPtr eventPtr) { + try { + shutdownTcs.SetResult(null); + } catch (Exception e) { + Console.WriteLine("Caught exception in a native handler: " + e); + } + } - private struct NewRpcInfo - { - private CallSafeHandle call; - private string method; - - public NewRpcInfo(CallSafeHandle call, string method) - { - this.call = call; - this.method = method; - } - - public CallSafeHandle Call - { - get - { - return this.call; - } - } - - public string Method - { - get - { - return this.method; - } - } - } + private + static void AssertCallOk(GRPCCallError callError) { + Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, + "Status not GRPC_CALL_OK"); + } + + private + static CompletionQueueSafeHandle GetCompletionQueue() { + return GrpcEnvironment.ThreadPool.CompletionQueue; + } + + private + struct NewRpcInfo { + private + CallSafeHandle call; + private + string method; + + public + NewRpcInfo(CallSafeHandle call, string method) { + this.call = call; + this.method = method; + } + + public + CallSafeHandle Call { + get { return this.call; } + } + + public + string Method { + get { return this.method; } + } } + } } diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index f7429fb43f8..f9a28f4d0d6 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -34,28 +34,26 @@ using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; -namespace math -{ - class MainClass - { - public static void Main(string[] args) - { - String host = "0.0.0.0"; +namespace math { +class MainClass { + public + static void Main(string[] args) { + String host = "0.0.0.0"; - GrpcEnvironment.Initialize(); + GrpcEnvironment.Initialize(); - Server server = new Server(); - server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host + ":23456"); - server.Start(); + Server server = new Server(); + server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); + int port = server.AddListeningPort(host + ":23456"); + server.Start(); - Console.WriteLine("MathServer listening on port " + port); + Console.WriteLine("MathServer listening on port " + port); - Console.WriteLine("Press any key to stop the server..."); - Console.ReadKey(); + Console.WriteLine("Press any key to stop the server..."); + Console.ReadKey(); - server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); - } - } + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } +} } diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 584bf1068de..088c4355859 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -16,7 +16,8 @@ full false bin\Debug - DEBUG; + DEBUG; + prompt 4 true diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 6da7d3c8305..d4e255d2fa7 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -118,35 +118,36 @@ static void grpc_rb_call_destroy(void *p) { } static size_t md_ary_datasize(const void *p) { - const grpc_metadata_array* const ary = (grpc_metadata_array*)p; - size_t i, datasize = sizeof(grpc_metadata_array); - for (i = 0; i < ary->count; ++i) { - const grpc_metadata* const md = &ary->metadata[i]; - datasize += strlen(md->key); - datasize += md->value_length; - } - datasize += ary->capacity * sizeof(grpc_metadata); - return datasize; + const grpc_metadata_array *const ary = (grpc_metadata_array *)p; + size_t i, datasize = sizeof(grpc_metadata_array); + for (i = 0; i < ary->count; ++i) { + const grpc_metadata *const md = &ary->metadata[i]; + datasize += strlen(md->key); + datasize += md->value_length; + } + datasize += ary->capacity * sizeof(grpc_metadata); + return datasize; } static const rb_data_type_t grpc_rb_md_ary_data_type = { "grpc_metadata_array", {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize}, - NULL, NULL, - 0 -}; + NULL, + NULL, + 0}; /* Describes grpc_call struct for RTypedData */ static const rb_data_type_t grpc_call_data_type = { "grpc_call", {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE}, - NULL, NULL, - /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because grpc_rb_call_destroy + NULL, + NULL, + /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because + * grpc_rb_call_destroy * touches a hash object. * TODO(yugui) Directly use st_table and call the free function earlier? */ - 0 -}; + 0}; /* Error code details is a hash containing text strings describing errors */ VALUE rb_error_code_details; @@ -250,7 +251,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { } md_ary->metadata[md_ary->count].value = RSTRING_PTR(rb_ary_entry(val, i)); md_ary->metadata[md_ary->count].value_length = - RSTRING_LEN(rb_ary_entry(val, i)); + RSTRING_LEN(rb_ary_entry(val, i)); md_ary->count += 1; } } else { @@ -290,10 +291,11 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, /* grpc_rb_md_ary_convert converts a ruby metadata hash into a grpc_metadata_array. */ -static void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) { +static void grpc_rb_md_ary_convert(VALUE md_ary_hash, + grpc_metadata_array *md_ary) { VALUE md_ary_obj = Qnil; if (md_ary_hash == Qnil) { - return; /* Do nothing if the expected has value is nil */ + return; /* Do nothing if the expected has value is nil */ } if (TYPE(md_ary_hash) != T_HASH) { rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want ", @@ -303,8 +305,8 @@ static void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ar /* Initialize the array, compute it's capacity, then fill it. */ grpc_metadata_array_init(md_ary); - md_ary_obj = TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, - md_ary); + md_ary_obj = + TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj); md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata)); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj); @@ -327,16 +329,14 @@ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) { rb_hash_aset(result, key, value); } else if (TYPE(value) == T_ARRAY) { /* Add the string to the returned array */ - rb_ary_push(value, - rb_str_new(md_ary->metadata[i].value, - md_ary->metadata[i].value_length)); + rb_ary_push(value, rb_str_new(md_ary->metadata[i].value, + md_ary->metadata[i].value_length)); } else { /* Add the current value with this key and the new one to an array */ new_ary = rb_ary_new(); rb_ary_push(new_ary, value); - rb_ary_push(new_ary, - rb_str_new(md_ary->metadata[i].value, - md_ary->metadata[i].value_length)); + rb_ary_push(new_ary, rb_str_new(md_ary->metadata[i].value, + md_ary->metadata[i].value_length)); rb_hash_aset(result, key, new_ary); } } @@ -355,7 +355,7 @@ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, rb_obj_classname(key)); return ST_STOP; } - switch(NUM2INT(key)) { + switch (NUM2INT(key)) { case GRPC_OP_SEND_INITIAL_METADATA: case GRPC_OP_SEND_MESSAGE: case GRPC_OP_SEND_CLOSE_FROM_CLIENT: @@ -367,8 +367,7 @@ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, rb_ary_push(ops_ary, key); return ST_CONTINUE; default: - rb_raise(rb_eTypeError, "invalid operation : bad value %d", - NUM2INT(key)); + rb_raise(rb_eTypeError, "invalid operation : bad value %d", NUM2INT(key)); }; return ST_STOP; } @@ -377,8 +376,8 @@ static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, struct to the 'send_status_from_server' portion of an op. */ static void grpc_rb_op_update_status_from_server(grpc_op *op, - grpc_metadata_array* md_ary, - VALUE status) { + grpc_metadata_array *md_ary, + VALUE status) { VALUE code = rb_struct_aref(status, sym_code); VALUE details = rb_struct_aref(status, sym_details); VALUE metadata_hash = rb_struct_aref(status, sym_metadata); @@ -405,8 +404,8 @@ static void grpc_rb_op_update_status_from_server(grpc_op *op, * grpc_rb_call_run_batch function */ typedef struct run_batch_stack { /* The batch ops */ - grpc_op ops[8]; /* 8 is the maximum number of operations */ - size_t op_num; /* tracks the last added operation */ + grpc_op ops[8]; /* 8 is the maximum number of operations */ + size_t op_num; /* tracks the last added operation */ /* Data being sent */ grpc_metadata_array send_metadata; @@ -424,7 +423,7 @@ typedef struct run_batch_stack { /* grpc_run_batch_stack_init ensures the run_batch_stack is properly * initialized */ -static void grpc_run_batch_stack_init(run_batch_stack* st) { +static void grpc_run_batch_stack_init(run_batch_stack *st) { MEMZERO(st, run_batch_stack, 1); grpc_metadata_array_init(&st->send_metadata); grpc_metadata_array_init(&st->send_trailing_metadata); @@ -435,7 +434,7 @@ static void grpc_run_batch_stack_init(run_batch_stack* st) { /* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly * cleaned up */ -static void grpc_run_batch_stack_cleanup(run_batch_stack* st) { +static void grpc_run_batch_stack_cleanup(run_batch_stack *st) { grpc_metadata_array_destroy(&st->send_metadata); grpc_metadata_array_destroy(&st->send_trailing_metadata); grpc_metadata_array_destroy(&st->recv_metadata); @@ -447,7 +446,7 @@ static void grpc_run_batch_stack_cleanup(run_batch_stack* st) { /* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from * ops_hash */ -static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) { +static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) { VALUE this_op = Qnil; VALUE this_value = Qnil; VALUE ops_ary = rb_ary_new(); @@ -460,7 +459,7 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) { for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) { this_op = rb_ary_entry(ops_ary, i); this_value = rb_hash_aref(ops_hash, this_op); - switch(NUM2INT(this_op)) { + switch (NUM2INT(this_op)) { case GRPC_OP_SEND_INITIAL_METADATA: /* N.B. later there is no need to explicitly delete the metadata keys * and values, they are references to data in ruby objects. */ @@ -471,18 +470,16 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) { st->send_metadata.metadata; break; case GRPC_OP_SEND_MESSAGE: - st->ops[st->op_num].data.send_message = - grpc_rb_s_to_byte_buffer(RSTRING_PTR(this_value), - RSTRING_LEN(this_value)); + st->ops[st->op_num].data.send_message = grpc_rb_s_to_byte_buffer( + RSTRING_PTR(this_value), RSTRING_LEN(this_value)); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: break; case GRPC_OP_SEND_STATUS_FROM_SERVER: /* N.B. later there is no need to explicitly delete the metadata keys * and values, they are references to data in ruby objects. */ - grpc_rb_op_update_status_from_server(&st->ops[st->op_num], - &st->send_trailing_metadata, - this_value); + grpc_rb_op_update_status_from_server( + &st->ops[st->op_num], &st->send_trailing_metadata, this_value); break; case GRPC_OP_RECV_INITIAL_METADATA: st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata; @@ -516,12 +513,12 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) { /* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct after the results have run */ -static VALUE grpc_run_batch_stack_build_result(run_batch_stack* st) { +static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) { size_t i = 0; VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, NULL); for (i = 0; i < st->op_num; i++) { - switch(st->ops[i].op) { + switch (st->ops[i].op) { case GRPC_OP_SEND_INITIAL_METADATA: rb_struct_aset(result, sym_send_metadata, Qtrue); break; @@ -544,13 +541,11 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack* st) { break; case GRPC_OP_RECV_STATUS_ON_CLIENT: rb_struct_aset( - result, - sym_status, - rb_struct_new(grpc_rb_sStatus, - UINT2NUM(st->recv_status), + result, sym_status, + rb_struct_new(grpc_rb_sStatus, UINT2NUM(st->recv_status), (st->recv_status_details == NULL - ? Qnil - : rb_str_new2(st->recv_status_details)), + ? Qnil + : rb_str_new2(st->recv_status_details)), grpc_rb_md_ary_to_h(&st->recv_trailing_metadata), NULL)); break; @@ -682,8 +677,7 @@ static void Init_grpc_error_codes() { static void Init_grpc_op_codes() { /* Constants representing operation type codes in grpc.h */ - VALUE grpc_rb_mCallOps = - rb_define_module_under(grpc_rb_mGrpcCore, "CallOps"); + VALUE grpc_rb_mCallOps = rb_define_module_under(grpc_rb_mGrpcCore, "CallOps"); rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA", UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA)); rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE", @@ -709,14 +703,14 @@ void Init_grpc_call() { grpc_rb_eOutOfTime = rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException); grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject); - grpc_rb_cMdAry = rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", - rb_cObject); + grpc_rb_cMdAry = + rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", rb_cObject); /* Prevent allocation or inialization of the Call class */ rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc); rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0); - rb_define_method(grpc_rb_cCall, "initialize_copy", - grpc_rb_cannot_init_copy, 1); + rb_define_method(grpc_rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy, + 1); /* Add ruby analogues of the Call methods. */ rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4); @@ -746,16 +740,8 @@ void Init_grpc_call() { /* The Struct used to return the run_batch result. */ grpc_rb_sBatchResult = rb_struct_define( - "BatchResult", - "send_message", - "send_metadata", - "send_close", - "send_status", - "message", - "metadata", - "status", - "cancelled", - NULL); + "BatchResult", "send_message", "send_metadata", "send_close", + "send_status", "message", "metadata", "status", "cancelled", NULL); /* The hash for reference counting calls, to ensure they can't be destroyed * more than once */ diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c index 1d1331eb9f2..957dee1aa7e 100644 --- a/test/core/channel/channel_stack_test.c +++ b/test/core/channel/channel_stack_test.c @@ -55,7 +55,8 @@ static void channel_init_func(grpc_channel_element *elem, } static void call_init_func(grpc_call_element *elem, - const void *server_transport_data, grpc_transport_op *initial_op) { + const void *server_transport_data, + grpc_transport_op *initial_op) { ++*(int *)(elem->channel_data); *(int *)(elem->call_data) = 0; } @@ -66,8 +67,7 @@ static void call_destroy_func(grpc_call_element *elem) { ++*(int *)(elem->channel_data); } -static void call_func(grpc_call_element *elem, - grpc_transport_op *op) { +static void call_func(grpc_call_element *elem, grpc_transport_op *op) { ++*(int *)(elem->call_data); } @@ -78,9 +78,8 @@ static void channel_func(grpc_channel_element *elem, static void test_create_channel_stack(void) { const grpc_channel_filter filter = { - call_func, channel_func, sizeof(int), - call_init_func, call_destroy_func, sizeof(int), - channel_init_func, channel_destroy_func, "some_test_filter"}; + call_func, channel_func, sizeof(int), call_init_func, call_destroy_func, + sizeof(int), channel_init_func, channel_destroy_func, "some_test_filter"}; const grpc_channel_filter *filters = &filter; grpc_channel_stack *channel_stack; grpc_call_stack *call_stack; diff --git a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c index d861034f8f8..ddde585b839 100644 --- a/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c +++ b/test/core/end2end/fixtures/chttp2_socket_pair_one_byte_at_a_time.c @@ -59,7 +59,8 @@ static grpc_transport_setup_result server_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { grpc_end2end_test_fixture *f = ts; - static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter}; + static grpc_channel_filter const *extra_filters[] = { + &grpc_http_server_filter}; return grpc_server_setup_transport(f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx); } @@ -73,9 +74,9 @@ static grpc_transport_setup_result client_setup_transport( void *ts, grpc_transport *transport, grpc_mdctx *mdctx) { sp_client_setup *cs = ts; - const grpc_channel_filter *filters[] = { - &grpc_client_surface_filter, &grpc_http_client_filter, - &grpc_connected_channel_filter}; + const grpc_channel_filter *filters[] = {&grpc_client_surface_filter, + &grpc_http_client_filter, + &grpc_connected_channel_filter}; size_t nfilters = sizeof(filters) / sizeof(*filters); grpc_channel *channel = grpc_channel_create_from_filters( filters, nfilters, cs->client_args, mdctx, 1); From 6f7030b9d7971f9671bba4aec4ad65516e57d6c4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:22:05 -0700 Subject: [PATCH 33/58] revert accidental change --- .../Grpc.Core/Internal/CallSafeHandle.cs | 360 ++++++++---------- .../Grpc.Core/Internal/ServerSafeHandle.cs | 171 ++++----- src/csharp/Grpc.Core/Server.cs | 357 +++++++++-------- .../Grpc.Examples.MathServer/MathServer.cs | 36 +- .../Grpc.IntegrationTesting.csproj | 7 +- 5 files changed, 460 insertions(+), 471 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 19d3f57abbb..c97a3bc2b16 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -1,11 +1,11 @@ #region Copyright notice and license // Copyright 2015, 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 @@ -15,7 +15,7 @@ // * 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 @@ -33,204 +33,160 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; using Grpc.Core; - -namespace Grpc.Core.Internal { - internal delegate void CompletionCallbackDelegate(GRPCOpError error, - IntPtr batchContextPtr); - - /// - /// grpc_call from - /// - internal class CallSafeHandle : SafeHandleZeroIsInvalid { - const uint GRPC_WRITE_BUFFER_HINT = 1; - - [DllImport("grpc_csharp_ext.dll")] static extern CallSafeHandle - grpcsharp_channel_create_call(ChannelSafeHandle channel, - CompletionQueueSafeHandle cq, string method, - string host, Timespec deadline); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_cancel(CallSafeHandle call); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, - string description); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_start_unary( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - byte[] send_buffer, UIntPtr send_buffer_len, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] static extern void - grpcsharp_call_blocking_unary( - CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - byte[] send_buffer, UIntPtr send_buffer_len, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_start_client_streaming( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_start_server_streaming( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - byte[] send_buffer, UIntPtr send_buffer_len, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_start_duplex_streaming( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - MetadataArraySafeHandle metadataArray); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_send_message( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - byte[] send_buffer, UIntPtr send_buffer_len); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_send_close_from_client( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_send_status_from_server( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback, - StatusCode statusCode, string statusMessage); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_recv_message( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback); - - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_call_start_serverside( - CallSafeHandle call, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback); - - [DllImport("grpc_csharp_ext.dll")] static extern void - grpcsharp_call_destroy(IntPtr call); - - private - CallSafeHandle() {} - - public - static CallSafeHandle Create(ChannelSafeHandle channel, - CompletionQueueSafeHandle cq, string method, - string host, Timespec deadline) { - return grpcsharp_channel_create_call(channel, cq, method, host, deadline); - } - - public - void StartUnary(byte[] payload, CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray) { - AssertCallOk(grpcsharp_call_start_unary( - this, callback, payload, new UIntPtr((ulong)payload.Length), - metadataArray)); - } - - public - void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, - CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray) { - grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, - new UIntPtr((ulong)payload.Length), - metadataArray); - } - - public - void StartClientStreaming(CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray) { - AssertCallOk( - grpcsharp_call_start_client_streaming(this, callback, metadataArray)); - } - - public - void StartServerStreaming(byte[] payload, - CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray) { - AssertCallOk(grpcsharp_call_start_server_streaming( - this, callback, payload, new UIntPtr((ulong)payload.Length), - metadataArray)); - } - - public - void StartDuplexStreaming(CompletionCallbackDelegate callback, - MetadataArraySafeHandle metadataArray) { - AssertCallOk( - grpcsharp_call_start_duplex_streaming(this, callback, metadataArray)); - } - - public - void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback) { - AssertCallOk(grpcsharp_call_send_message( - this, callback, payload, new UIntPtr((ulong)payload.Length))); - } - - public - void StartSendCloseFromClient(CompletionCallbackDelegate callback) { - AssertCallOk(grpcsharp_call_send_close_from_client(this, callback)); - } - - public - void StartSendStatusFromServer(Status status, - CompletionCallbackDelegate callback) { - AssertCallOk(grpcsharp_call_send_status_from_server( - this, callback, status.StatusCode, status.Detail)); - } - - public - void StartReceiveMessage(CompletionCallbackDelegate callback) { - AssertCallOk(grpcsharp_call_recv_message(this, callback)); - } - - public - void StartServerSide(CompletionCallbackDelegate callback) { - AssertCallOk(grpcsharp_call_start_serverside(this, callback)); - } - - public - void Cancel() { AssertCallOk(grpcsharp_call_cancel(this)); } - - public - void CancelWithStatus(Status status) { - AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, - status.Detail)); - } - - protected - override bool ReleaseHandle() { - grpcsharp_call_destroy(handle); - return true; - } - - private - static void AssertCallOk(GRPCCallError callError) { - Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, - "Status not GRPC_CALL_OK"); - } - - private - static uint GetFlags(bool buffered) { - return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal +{ + internal delegate void CompletionCallbackDelegate(GRPCOpError error, IntPtr batchContextPtr); + + /// + /// grpc_call from + /// + internal class CallSafeHandle : SafeHandleZeroIsInvalid + { + const uint GRPC_WRITE_BUFFER_HINT = 1; + + [DllImport("grpc_csharp_ext.dll")] + static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_call_blocking_unary(CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + byte[] send_buffer, UIntPtr send_buffer_len, MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + byte[] send_buffer, UIntPtr send_buffer_len, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + MetadataArraySafeHandle metadataArray); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, + byte[] send_buffer, UIntPtr send_buffer_len); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, StatusCode statusCode, string statusMessage); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); + + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call, + [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_call_destroy(IntPtr call); + + private CallSafeHandle() + { + } + + public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) + { + return grpcsharp_channel_create_call(channel, cq, method, host, deadline); + } + + public void StartUnary(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) + { + AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray)); + } + + public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) + { + grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray); + } + + public void StartClientStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) + { + AssertCallOk(grpcsharp_call_start_client_streaming(this, callback, metadataArray)); + } + + public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) + { + AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length), metadataArray)); + } + + public void StartDuplexStreaming(CompletionCallbackDelegate callback, MetadataArraySafeHandle metadataArray) + { + AssertCallOk(grpcsharp_call_start_duplex_streaming(this, callback, metadataArray)); + } + + public void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_call_send_message(this, callback, payload, new UIntPtr((ulong)payload.Length))); + } + + public void StartSendCloseFromClient(CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_call_send_close_from_client(this, callback)); + } + + public void StartSendStatusFromServer(Status status, CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_call_send_status_from_server(this, callback, status.StatusCode, status.Detail)); + } + + public void StartReceiveMessage(CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_call_recv_message(this, callback)); + } + + public void StartServerSide(CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_call_start_serverside(this, callback)); + } + + public void Cancel() + { + AssertCallOk(grpcsharp_call_cancel(this)); + } + + public void CancelWithStatus(Status status) + { + AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail)); + } + + protected override bool ReleaseHandle() + { + grpcsharp_call_destroy(handle); + return true; + } + + private static void AssertCallOk(GRPCCallError callError) + { + Preconditions.CheckState(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK"); + } + + private static uint GetFlags(bool buffered) + { + return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; + } } - } } \ No newline at end of file diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs index b56e8d98019..8080643d8c1 100644 --- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs @@ -35,90 +35,91 @@ using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.InteropServices; - -namespace Grpc.Core.Internal { - // TODO: we need to make sure that the delegates are not collected before - // invoked. - internal delegate void ServerShutdownCallbackDelegate(IntPtr eventPtr); - - /// - /// grpc_server from grpc/grpc.h - /// - internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid { - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError - grpcsharp_server_request_call( - ServerSafeHandle server, CompletionQueueSafeHandle cq, - [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate - callback); - - [DllImport("grpc_csharp_ext.dll")] static extern ServerSafeHandle - grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args); - - [DllImport("grpc_csharp_ext.dll")] static extern int - grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr); - - [DllImport("grpc_csharp_ext.dll")] static extern int - grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, - ServerCredentialsSafeHandle creds); - - [DllImport("grpc_csharp_ext.dll")] static extern void - grpcsharp_server_start(ServerSafeHandle server); - - [DllImport("grpc_csharp_ext.dll")] static extern void - grpcsharp_server_shutdown(ServerSafeHandle server); - - // TODO: get rid of the old callback style - [DllImport( - "grpc_csharp_ext.dll", - EntryPoint = "grpcsharp_server_shutdown_and_notify")] static extern void - grpcsharp_server_shutdown_and_notify_CALLBACK( - ServerSafeHandle server, - [MarshalAs(UnmanagedType.FunctionPtr)] ServerShutdownCallbackDelegate - callback); - - [DllImport("grpc_csharp_ext.dll")] static extern void - grpcsharp_server_destroy(IntPtr server); - - private - ServerSafeHandle() {} - - public - static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, - IntPtr args) { - return grpcsharp_server_create(cq, args); - } - - public - int AddListeningPort(string addr) { - return grpcsharp_server_add_http2_port(this, addr); - } - - public - int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials) { - return grpcsharp_server_add_secure_http2_port(this, addr, credentials); - } - - public - void Start() { grpcsharp_server_start(this); } - - public - void Shutdown() { grpcsharp_server_shutdown(this); } - - public - void ShutdownAndNotify(ServerShutdownCallbackDelegate callback) { - grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback); - } - - public - GRPCCallError RequestCall(CompletionQueueSafeHandle cq, - CompletionCallbackDelegate callback) { - return grpcsharp_server_request_call(this, cq, callback); - } - - protected - override bool ReleaseHandle() { - grpcsharp_server_destroy(handle); - return true; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal +{ + // TODO: we need to make sure that the delegates are not collected before invoked. + internal delegate void ServerShutdownCallbackDelegate(IntPtr eventPtr); + + /// + /// grpc_server from grpc/grpc.h + /// + internal sealed class ServerSafeHandle : SafeHandleZeroIsInvalid + { + [DllImport("grpc_csharp_ext.dll")] + static extern GRPCCallError grpcsharp_server_request_call(ServerSafeHandle server, CompletionQueueSafeHandle cq, [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback); + + [DllImport("grpc_csharp_ext.dll")] + static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, IntPtr args); + + [DllImport("grpc_csharp_ext.dll")] + static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr); + + [DllImport("grpc_csharp_ext.dll")] + static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_server_start(ServerSafeHandle server); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_server_shutdown(ServerSafeHandle server); + + // TODO: get rid of the old callback style + [DllImport("grpc_csharp_ext.dll", EntryPoint = "grpcsharp_server_shutdown_and_notify")] + static extern void grpcsharp_server_shutdown_and_notify_CALLBACK(ServerSafeHandle server, [MarshalAs(UnmanagedType.FunctionPtr)] ServerShutdownCallbackDelegate callback); + + [DllImport("grpc_csharp_ext.dll")] + static extern void grpcsharp_server_destroy(IntPtr server); + + private ServerSafeHandle() + { + } + + public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args) + { + return grpcsharp_server_create(cq, args); + } + + public int AddListeningPort(string addr) + { + return grpcsharp_server_add_http2_port(this, addr); + } + + public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials) + { + return grpcsharp_server_add_secure_http2_port(this, addr, credentials); + } + + public void Start() + { + grpcsharp_server_start(this); + } + + public void Shutdown() + { + grpcsharp_server_shutdown(this); + } + + public void ShutdownAndNotify(ServerShutdownCallbackDelegate callback) + { + grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback); + } + + public void RequestCall(CompletionQueueSafeHandle cq, CompletionCallbackDelegate callback) + { + AssertCallOk(grpcsharp_server_request_call(this, cq, callback)); + } + + protected override bool ReleaseHandle() + { + grpcsharp_server_destroy(handle); + return true; + } + + private static void AssertCallOk(GRPCCallError callError) + { + Preconditions.CheckState(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK"); + } } - } } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index 308fbfb71c8..e686cdddef7 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -38,187 +38,216 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Utils; -namespace Grpc.Core { - /// - /// Server is implemented only to be able to do - /// in-process testing. - /// - public - class Server { - // TODO: make sure the delegate doesn't get garbage collected while - // native callbacks are in the completion queue. - readonly ServerShutdownCallbackDelegate serverShutdownHandler; - readonly CompletionCallbackDelegate newServerRpcHandler; - - readonly BlockingCollection newRpcQueue = - new BlockingCollection(); - readonly ServerSafeHandle handle; - - readonly Dictionary callHandlers = - new Dictionary(); - - readonly TaskCompletionSource shutdownTcs = - new TaskCompletionSource(); - - public - Server() { - this.handle = - ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero); - this.newServerRpcHandler = HandleNewServerRpc; - this.serverShutdownHandler = HandleServerShutdown; - } - - // only call this before Start() - public - void AddServiceDefinition(ServerServiceDefinition serviceDefinition) { - foreach (var entry in serviceDefinition.CallHandlers) { - callHandlers.Add(entry.Key, entry.Value); - } - } - - // only call before Start() - public - int AddListeningPort(string addr) { return handle.AddListeningPort(addr); } - - // only call before Start() - public - int AddListeningPort(string addr, ServerCredentials credentials) { - using(var nativeCredentials = credentials.ToNativeCredentials()) { - return handle.AddListeningPort(addr, nativeCredentials); - } - } - - public - void Start() { - handle.Start(); - - // TODO: this basically means the server is single threaded.... - StartHandlingRpcs(); - } - +namespace Grpc.Core +{ /// - /// Requests and handles single RPC call. + /// A gRPC server. /// - internal void RunRpc() { - AllowOneRpc(); - - try { - var rpcInfo = newRpcQueue.Take(); - - // Console.WriteLine("Server received RPC " + rpcInfo.Method); - - IServerCallHandler callHandler; - if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler)) { - callHandler = new NoSuchMethodCallHandler(); + public class Server + { + // TODO(jtattermusch) : make sure the delegate doesn't get garbage collected while + // native callbacks are in the completion queue. + readonly ServerShutdownCallbackDelegate serverShutdownHandler; + readonly CompletionCallbackDelegate newServerRpcHandler; + + readonly ServerSafeHandle handle; + readonly object myLock = new object(); + + readonly Dictionary callHandlers = new Dictionary(); + readonly TaskCompletionSource shutdownTcs = new TaskCompletionSource(); + + bool startRequested; + bool shutdownRequested; + + public Server() + { + this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero); + this.newServerRpcHandler = HandleNewServerRpc; + this.serverShutdownHandler = HandleServerShutdown; } - callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, - GetCompletionQueue()); - } catch (Exception e) { - Console.WriteLine("Exception while handling RPC: " + e); - } - } - /// - /// Requests server shutdown and when there are no more calls being - /// serviced, - /// cleans up used resources. - /// - /// The async. - public - async Task ShutdownAsync() { - handle.ShutdownAndNotify(serverShutdownHandler); - await shutdownTcs.Task; - handle.Dispose(); - } - - /// - /// To allow awaiting termination of the server. - /// - public - Task ShutdownTask { - get { return shutdownTcs.Task; } - } + /// + /// Adds a service definition to the server. This is how you register + /// handlers for a service with the server. + /// Only call this before Start(). + /// + public void AddServiceDefinition(ServerServiceDefinition serviceDefinition) + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + foreach (var entry in serviceDefinition.CallHandlers) + { + callHandlers.Add(entry.Key, entry.Value); + } + } + } - public - void Kill() { handle.Dispose(); } + /// + /// Add a non-secure port on which server should listen. + /// Only call this before Start(). + /// + public int AddListeningPort(string addr) + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + return handle.AddListeningPort(addr); + } + } - private - async Task StartHandlingRpcs() { - while (true) { - await Task.Factory.StartNew(RunRpc); - } - } + /// + /// Add a secure port on which server should listen. + /// Only call this before Start(). + /// + public int AddListeningPort(string addr, ServerCredentials credentials) + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + using (var nativeCredentials = credentials.ToNativeCredentials()) + { + return handle.AddListeningPort(addr, nativeCredentials); + } + } + } - private - void AllowOneRpc() { - AssertCallOk( - handle.RequestCall(GetCompletionQueue(), newServerRpcHandler)); - } + /// + /// Starts the server. + /// + public void Start() + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + startRequested = true; + + handle.Start(); + AllowOneRpc(); + } + } - private - void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr) { - try { - var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr); + /// + /// Requests server shutdown and when there are no more calls being serviced, + /// cleans up used resources. The returned task finishes when shutdown procedure + /// is complete. + /// + public async Task ShutdownAsync() + { + lock (myLock) + { + Preconditions.CheckState(startRequested); + Preconditions.CheckState(!shutdownRequested); + shutdownRequested = true; + } + + handle.ShutdownAndNotify(serverShutdownHandler); + await shutdownTcs.Task; + handle.Dispose(); + } - if (error != GRPCOpError.GRPC_OP_OK) { - // TODO: handle error + /// + /// To allow awaiting termination of the server. + /// + public Task ShutdownTask + { + get + { + return shutdownTcs.Task; + } } - var rpcInfo = new NewRpcInfo(ctx.GetServerRpcNewCall(), - ctx.GetServerRpcNewMethod()); + public void Kill() + { + handle.Dispose(); + } - // after server shutdown, the callback returns with null call - if (!rpcInfo.Call.IsInvalid) { - newRpcQueue.Add(rpcInfo); + /// + /// Allows one new RPC call to be received by server. + /// + private void AllowOneRpc() + { + lock (myLock) + { + if (!shutdownRequested) + { + handle.RequestCall(GetCompletionQueue(), newServerRpcHandler); + } + } } - } catch (Exception e) { - Console.WriteLine("Caught exception in a native handler: " + e); - } - } - private - void HandleServerShutdown(IntPtr eventPtr) { - try { - shutdownTcs.SetResult(null); - } catch (Exception e) { - Console.WriteLine("Caught exception in a native handler: " + e); - } - } + /// + /// Selects corresponding handler for given call and handles the call. + /// + private void InvokeCallHandler(CallSafeHandle call, string method) + { + try + { + IServerCallHandler callHandler; + if (!callHandlers.TryGetValue(method, out callHandler)) + { + callHandler = new NoSuchMethodCallHandler(); + } + callHandler.StartCall(method, call, GetCompletionQueue()); + } + catch (Exception e) + { + Console.WriteLine("Exception while handling RPC: " + e); + } + } - private - static void AssertCallOk(GRPCCallError callError) { - Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, - "Status not GRPC_CALL_OK"); - } + /// + /// Handles the native callback. + /// + private void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr) + { + try + { + var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr); + + if (error != GRPCOpError.GRPC_OP_OK) + { + // TODO: handle error + } + + CallSafeHandle call = ctx.GetServerRpcNewCall(); + string method = ctx.GetServerRpcNewMethod(); + + // after server shutdown, the callback returns with null call + if (!call.IsInvalid) + { + Task.Run(() => InvokeCallHandler(call, method)); + } + + AllowOneRpc(); + } + catch (Exception e) + { + Console.WriteLine("Caught exception in a native handler: " + e); + } + } - private - static CompletionQueueSafeHandle GetCompletionQueue() { - return GrpcEnvironment.ThreadPool.CompletionQueue; - } + /// + /// Handles native callback. + /// + /// + private void HandleServerShutdown(IntPtr eventPtr) + { + try + { + shutdownTcs.SetResult(null); + } + catch (Exception e) + { + Console.WriteLine("Caught exception in a native handler: " + e); + } + } - private - struct NewRpcInfo { - private - CallSafeHandle call; - private - string method; - - public - NewRpcInfo(CallSafeHandle call, string method) { - this.call = call; - this.method = method; - } - - public - CallSafeHandle Call { - get { return this.call; } - } - - public - string Method { - get { return this.method; } - } + private static CompletionQueueSafeHandle GetCompletionQueue() + { + return GrpcEnvironment.ThreadPool.CompletionQueue; + } } - } } diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index f9a28f4d0d6..abc7ef05e4b 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -34,26 +34,28 @@ using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; -namespace math { -class MainClass { - public - static void Main(string[] args) { - String host = "0.0.0.0"; +namespace math +{ + class MainClass + { + public static void Main(string[] args) + { + string host = "0.0.0.0"; - GrpcEnvironment.Initialize(); + GrpcEnvironment.Initialize(); - Server server = new Server(); - server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host + ":23456"); - server.Start(); + Server server = new Server(); + server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); + int port = server.AddListeningPort(host + ":23456"); + server.Start(); - Console.WriteLine("MathServer listening on port " + port); + Console.WriteLine("MathServer listening on port " + port); - Console.WriteLine("Press any key to stop the server..."); - Console.ReadKey(); + Console.WriteLine("Press any key to stop the server..."); + Console.ReadKey(); - server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); - } -} + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } + } } diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 088c4355859..6ae8041fb7c 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -16,8 +16,7 @@ full false bin\Debug - DEBUG; - + DEBUG; prompt 4 true @@ -81,5 +80,7 @@ PreserveNewest - + + + \ No newline at end of file From 4df5caea068914474c3a1596dd1d195ebfdfaff1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 13:46:12 -0700 Subject: [PATCH 34/58] Fix memory leak --- src/core/transport/chttp2_transport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 52de8c218f0..49cd87f80fc 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -420,6 +420,9 @@ static void destruct_transport(transport *t) { } gpr_free(t->pings); + gpr_free(t->pending_callbacks.callbacks); + gpr_free(t->executing_callbacks.callbacks); + for (i = 0; i < t->num_pending_goaways; i++) { gpr_slice_unref(t->pending_goaways[i].debug); } From 48bfcdcfcc42ccefdf711b509cce61d4299655ce Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 14:24:27 -0700 Subject: [PATCH 35/58] Fix memory leak --- src/core/transport/chttp2_transport.c | 60 +++++++++++++++++++-------- src/core/transport/stream_op.c | 24 ----------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 49cd87f80fc..0640c848d79 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -661,9 +661,12 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { gpr_mu_unlock(&t->mu); GPR_ASSERT(s->outgoing_sopb == NULL); + GPR_ASSERT(s->incoming_sopb == NULL); grpc_sopb_destroy(&s->writing_sopb); grpc_sopb_destroy(&s->callback_sopb); grpc_chttp2_data_parser_destroy(&s->parser); + GPR_ASSERT(s->incoming_metadata_count == 0); + gpr_free(s->incoming_metadata); unref_transport(t); } @@ -1522,28 +1525,18 @@ static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) { static void add_metadata_batch(transport *t, stream *s) { grpc_metadata_batch b; - size_t i; - b.list.head = &s->incoming_metadata[0]; - b.list.tail = &s->incoming_metadata[s->incoming_metadata_count - 1]; + b.list.head = NULL; + /* Store away the last element of the list, so that in patch_metadata_ops + we can reconstitute the list. + We can't do list building here as later incoming metadata may reallocate + the underlying array. */ + b.list.tail = (void*)(gpr_intptr)s->incoming_metadata_count; b.garbage.head = b.garbage.tail = NULL; b.deadline = s->incoming_deadline; - - for (i = 1; i < s->incoming_metadata_count; i++) { - s->incoming_metadata[i].prev = &s->incoming_metadata[i - 1]; - s->incoming_metadata[i - 1].next = &s->incoming_metadata[i]; - } - s->incoming_metadata[0].prev = NULL; - s->incoming_metadata[s->incoming_metadata_count - 1].next = NULL; + s->incoming_deadline = gpr_inf_future; grpc_sopb_add_metadata(&s->parser.incoming_sopb, b); - /* TODO(ctiller): don't leak incoming_metadata */ - - /* reset */ - s->incoming_deadline = gpr_inf_future; - s->incoming_metadata = NULL; - s->incoming_metadata_count = 0; - s->incoming_metadata_capacity = 0; } static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { @@ -1884,6 +1877,35 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed, return GRPC_STREAM_OPEN; } +static void patch_metadata_ops(stream *s) { + grpc_stream_op *ops = s->incoming_sopb->ops; + size_t nops = s->incoming_sopb->nops; + size_t i; + size_t j; + size_t mdidx = 0; + size_t last_mdidx; + + for (i = 0; i < nops; i++) { + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA) continue; + last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail); + GPR_ASSERT(last_mdidx > mdidx); + GPR_ASSERT(last_mdidx <= s->incoming_metadata_count); + op->data.metadata.list.head = &s->incoming_metadata[mdidx]; + op->data.metadata.list.tail = &s->incoming_metadata[last_mdidx - 1]; + for (j = mdidx + 1; j < last_mdidx; j++) { + s->incoming_metadata[j].prev = &s->incoming_metadata[j-1]; + s->incoming_metadata[j-1].next = &s->incoming_metadata[j]; + } + s->incoming_metadata[mdidx].prev = NULL; + s->incoming_metadata[last_mdidx-1].next = NULL; + mdidx = last_mdidx; + } + GPR_ASSERT(mdidx == s->incoming_metadata_count); + + s->incoming_metadata_count = 0; +} + static void finish_reads(transport *t) { stream *s; @@ -1904,10 +1926,14 @@ static void finish_reads(transport *t) { publish = 1; } if (publish) { + if (s->incoming_metadata_count > 0) { + patch_metadata_ops(s); + } s->incoming_sopb = NULL; schedule_cb(t, s->recv_done_closure, 1); } } + } static void schedule_cb(transport *t, op_closure closure, int success) { diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c index ea22b0e1c82..e1a75adcb6e 100644 --- a/src/core/transport/stream_op.c +++ b/src/core/transport/stream_op.c @@ -88,34 +88,19 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) { } } -static void assert_contained_metadata_ok(grpc_stream_op *ops, size_t nops) { -#ifndef NDEBUG - size_t i; - for (i = 0; i < nops; i++) { - if (ops[i].type == GRPC_OP_METADATA) { - grpc_metadata_batch_assert_ok(&ops[i].data.metadata); - } - } -#endif /* NDEBUG */ -} - static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) { sopb->capacity = new_capacity; - assert_contained_metadata_ok(sopb->ops, sopb->nops); if (sopb->ops == sopb->inlined_ops) { sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * new_capacity); memcpy(sopb->ops, sopb->inlined_ops, sopb->nops * sizeof(grpc_stream_op)); } else { sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity); } - assert_contained_metadata_ok(sopb->ops, sopb->nops); } static grpc_stream_op *add(grpc_stream_op_buffer *sopb) { grpc_stream_op *out; - assert_contained_metadata_ok(sopb->ops, sopb->nops); - GPR_ASSERT(sopb->nops <= sopb->capacity); if (sopb->nops == sopb->capacity) { expandto(sopb, GROW(sopb->capacity)); @@ -127,7 +112,6 @@ static grpc_stream_op *add(grpc_stream_op_buffer *sopb) { void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb) { add(sopb)->type = GRPC_NO_OP; - assert_contained_metadata_ok(sopb->ops, sopb->nops); } void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, @@ -136,24 +120,19 @@ void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length, op->type = GRPC_OP_BEGIN_MESSAGE; op->data.begin_message.length = length; op->data.begin_message.flags = flags; - assert_contained_metadata_ok(sopb->ops, sopb->nops); } void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_metadata_batch b) { grpc_stream_op *op = add(sopb); - grpc_metadata_batch_assert_ok(&b); op->type = GRPC_OP_METADATA; op->data.metadata = b; - grpc_metadata_batch_assert_ok(&op->data.metadata); - assert_contained_metadata_ok(sopb->ops, sopb->nops); } void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) { grpc_stream_op *op = add(sopb); op->type = GRPC_OP_SLICE; op->data.slice = slice; - assert_contained_metadata_ok(sopb->ops, sopb->nops); } void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, @@ -161,15 +140,12 @@ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops, size_t orig_nops = sopb->nops; size_t new_nops = orig_nops + nops; - assert_contained_metadata_ok(ops, nops); - assert_contained_metadata_ok(sopb->ops, sopb->nops); if (new_nops > sopb->capacity) { expandto(sopb, GPR_MAX(GROW(sopb->capacity), new_nops)); } memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops); sopb->nops = new_nops; - assert_contained_metadata_ok(sopb->ops, sopb->nops); } static void assert_valid_list(grpc_mdelem_list *list) { From 872af0281eb14dc69493155e47e89fd42350c9ef Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 15:57:52 -0700 Subject: [PATCH 36/58] Fix memory leak --- src/core/surface/call.c | 4 +++- src/core/surface/server.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 7c91ca917c3..7a9fe30732f 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -411,7 +411,9 @@ static int need_more_data(grpc_call *call) { is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_STATUS) || is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || - is_op_live(call, GRPC_IOREQ_RECV_CLOSE); + is_op_live(call, GRPC_IOREQ_RECV_CLOSE) || + (call->write_state == WRITE_STATE_INITIAL && !call->is_client && + call->read_state != READ_STATE_STREAM_CLOSED); } static void unlock(grpc_call *call) { diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 28f42f0fc3c..2f00ad0bc6c 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -925,6 +925,8 @@ void grpc_server_destroy(grpc_server *server) { channel_data *c; listener *l; size_t i; + call_data *calld; + gpr_mu_lock(&server->mu); if (!server->shutdown) { gpr_mu_unlock(&server->mu); @@ -949,6 +951,15 @@ void grpc_server_destroy(grpc_server *server) { gpr_free(l); } + while ((calld = call_list_remove_head(&server->lists[PENDING_START], + PENDING_START)) != NULL) { + gpr_log(GPR_DEBUG, "server destroys call %p", calld->call); + calld->state = ZOMBIED; + grpc_iomgr_add_callback( + kill_zombie, + grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0)); + } + for (c = server->root_channel_data.next; c != &server->root_channel_data; c = c->next) { shutdown_channel(c); From 916b152184d28e449efa5ab455dcb8c0b90407a6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 16:00:06 -0700 Subject: [PATCH 37/58] annotations - revert later --- src/core/surface/call.c | 33 ++++++++++++++++------------- src/core/surface/call.h | 4 ++-- src/core/surface/completion_queue.c | 4 ++-- src/core/surface/server.c | 2 +- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 7a9fe30732f..e80cf9e2939 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -300,7 +300,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, initial_op.on_done_recv = call_on_done_recv; initial_op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call); + grpc_call_internal_ref(call, "receiving-0"); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, @@ -320,7 +320,9 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) { return call->cq; } -void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); } +void grpc_call_internal_ref(grpc_call *c, const char *reason) { +gpr_log(GPR_DEBUG, "grpc_call_internal_ref: %p %s %d -> %d", c, reason, c->internal_refcount.count, c->internal_refcount.count+1); + gpr_ref(&c->internal_refcount); } static void destroy_call(void *call, int ignored_success) { size_t i; @@ -353,7 +355,8 @@ static void destroy_call(void *call, int ignored_success) { gpr_free(c); } -void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) { +void grpc_call_internal_unref(grpc_call *c, const char *reason, int allow_immediate_deletion) { +gpr_log(GPR_DEBUG, "grpc_call_internal_unref: %p %s %d -> %d", c, reason, c->internal_refcount.count, c->internal_refcount.count-1); if (gpr_unref(&c->internal_refcount)) { if (allow_immediate_deletion) { destroy_call(c, 1); @@ -412,8 +415,7 @@ static int need_more_data(grpc_call *call) { is_op_live(call, GRPC_IOREQ_RECV_STATUS) || is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || is_op_live(call, GRPC_IOREQ_RECV_CLOSE) || - (call->write_state == WRITE_STATE_INITIAL && !call->is_client && - call->read_state != READ_STATE_STREAM_CLOSED); + (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED); } static void unlock(grpc_call *call) { @@ -431,14 +433,14 @@ static void unlock(grpc_call *call) { op.on_done_recv = call_on_done_recv; op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call); + grpc_call_internal_ref(call, "receiving"); start_op = 1; } if (!call->sending) { if (fill_send_ops(call, &op)) { call->sending = 1; - grpc_call_internal_ref(call); + grpc_call_internal_ref(call, "sending"); start_op = 1; } } @@ -449,7 +451,7 @@ static void unlock(grpc_call *call) { sizeof(completed_requests)); call->num_completed_requests = 0; call->completing = 1; - grpc_call_internal_ref(call); + grpc_call_internal_ref(call, "completing"); } gpr_mu_unlock(&call->mu); @@ -466,7 +468,7 @@ static void unlock(grpc_call *call) { lock(call); call->completing = 0; unlock(call); - grpc_call_internal_unref(call, 0); + grpc_call_internal_unref(call, "completing", 0); } } @@ -606,7 +608,7 @@ static void call_on_done_send(void *pc, int success) { call->last_send_contains = 0; call->sending = 0; unlock(call); - grpc_call_internal_unref(call, 0); + grpc_call_internal_unref(call, "sending", 0); } static void finish_message(grpc_call *call) { @@ -687,6 +689,7 @@ static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; int unref_due_to_connection_close = 0; + gpr_log(GPR_DEBUG, "%s %p", __FUNCTION__, call); lock(call); call->receiving = 0; if (success) { @@ -727,9 +730,9 @@ static void call_on_done_recv(void *pc, int success) { call->recv_ops.nops = 0; unlock(call); - grpc_call_internal_unref(call, 0); + grpc_call_internal_unref(call, "receiving", 0); if (unref_due_to_connection_close) { - grpc_call_internal_unref(call, 0); + grpc_call_internal_unref(call, "live", 0); } } @@ -988,7 +991,7 @@ void grpc_call_destroy(grpc_call *c) { cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c); - grpc_call_internal_unref(c, 1); + grpc_call_internal_unref(c, "destroy", 1); } grpc_call_error grpc_call_cancel(grpc_call *call) { @@ -1035,7 +1038,7 @@ static void call_alarm(void *arg, int success) { grpc_call_cancel(call); } } - grpc_call_internal_unref(call, 1); + grpc_call_internal_unref(call, "alarm", 1); } static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { @@ -1044,7 +1047,7 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { assert(0); return; } - grpc_call_internal_ref(call); + grpc_call_internal_ref(call, "alarm"); call->have_alarm = 1; grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now()); } diff --git a/src/core/surface/call.h b/src/core/surface/call.h index 199beb17386..f0c31e3a0d0 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -93,8 +93,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq); grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call); -void grpc_call_internal_ref(grpc_call *call); -void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion); +void grpc_call_internal_ref(grpc_call *call, const char *reason); +void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion); grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index 24f4a05071a..4398c43f5ef 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -135,7 +135,7 @@ static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type, void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call, grpc_completion_type type) { gpr_ref(&cc->refs); - if (call) grpc_call_internal_ref(call); + if (call) grpc_call_internal_ref(call, "cq"); #ifndef NDEBUG gpr_atm_no_barrier_fetch_add(&cc->pending_op_count[type], 1); #endif @@ -409,7 +409,7 @@ void grpc_event_finish(grpc_event *base) { event *ev = (event *)base; ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK); if (ev->base.call) { - grpc_call_internal_unref(ev->base.call, 1); + grpc_call_internal_unref(ev->base.call, "cq", 1); } gpr_free(ev); } diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 2f00ad0bc6c..254a1a64bd2 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -1131,7 +1131,7 @@ static void begin_call(grpc_server *server, call_data *calld, break; } - grpc_call_internal_ref(calld->call); + grpc_call_internal_ref(calld->call, "server"); grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc->tag); } From 9c71b6f5b670098667cd6cba93ad96018b975e44 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 16:02:00 -0700 Subject: [PATCH 38/58] Fix memory leak --- src/core/surface/call.c | 10 ++-------- src/core/transport/chttp2_transport.c | 4 +++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index e80cf9e2939..134759e0c11 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -288,9 +288,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, grpc_sopb_init(&call->send_ops); grpc_sopb_init(&call->recv_ops); gpr_slice_buffer_init(&call->incoming_message); - /* one ref is dropped in response to destroy, the other in - stream_closed */ - gpr_ref_init(&call->internal_refcount, 2); + /* dropped in destroy */ + gpr_ref_init(&call->internal_refcount, 1); /* server hack: start reads immediately so we can get initial metadata. TODO(ctiller): figure out a cleaner solution */ if (!call->is_client) { @@ -688,7 +687,6 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) { static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; - int unref_due_to_connection_close = 0; gpr_log(GPR_DEBUG, "%s %p", __FUNCTION__, call); lock(call); call->receiving = 0; @@ -716,7 +714,6 @@ static void call_on_done_recv(void *pc, int success) { if (call->recv_state == GRPC_STREAM_CLOSED) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; - unref_due_to_connection_close = 1; } finish_read_ops(call); } else { @@ -731,9 +728,6 @@ static void call_on_done_recv(void *pc, int success) { unlock(call); grpc_call_internal_unref(call, "receiving", 0); - if (unref_due_to_connection_close) { - grpc_call_internal_unref(call, "live", 0); - } } static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 0640c848d79..238bcacfaa9 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -665,7 +665,9 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { grpc_sopb_destroy(&s->writing_sopb); grpc_sopb_destroy(&s->callback_sopb); grpc_chttp2_data_parser_destroy(&s->parser); - GPR_ASSERT(s->incoming_metadata_count == 0); + for (i = 0; i < s->incoming_metadata_count; i++) { + grpc_mdelem_unref(s->incoming_metadata[i].md); + } gpr_free(s->incoming_metadata); unref_transport(t); From 65f9f81afbb4d78496f3032246e97970720191cd Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 16:53:20 -0700 Subject: [PATCH 39/58] Fix memory leak --- src/core/surface/call.c | 10 ++++++---- src/core/transport/chttp2_transport.c | 3 ++- src/core/transport/transport_op_string.c | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 134759e0c11..995e2dab7eb 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -320,7 +320,7 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) { } void grpc_call_internal_ref(grpc_call *c, const char *reason) { -gpr_log(GPR_DEBUG, "grpc_call_internal_ref: %p %s %d -> %d", c, reason, c->internal_refcount.count, c->internal_refcount.count+1); +gpr_log(GPR_DEBUG, "grpc_call_internal_ref: %p %d %s %d -> %d", c, c->is_client, reason, c->internal_refcount.count, c->internal_refcount.count+1); gpr_ref(&c->internal_refcount); } static void destroy_call(void *call, int ignored_success) { @@ -355,7 +355,7 @@ static void destroy_call(void *call, int ignored_success) { } void grpc_call_internal_unref(grpc_call *c, const char *reason, int allow_immediate_deletion) { -gpr_log(GPR_DEBUG, "grpc_call_internal_unref: %p %s %d -> %d", c, reason, c->internal_refcount.count, c->internal_refcount.count-1); +gpr_log(GPR_DEBUG, "grpc_call_internal_unref: %p %d %s %d -> %d", c, c->is_client, reason, c->internal_refcount.count, c->internal_refcount.count-1); if (gpr_unref(&c->internal_refcount)) { if (allow_immediate_deletion) { destroy_call(c, 1); @@ -408,12 +408,13 @@ static int is_op_live(grpc_call *call, grpc_ioreq_op op) { static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); } static int need_more_data(grpc_call *call) { + gpr_log(GPR_DEBUG, "st: %d%d%d%d%d%d%d", is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA), is_op_live(call, GRPC_IOREQ_RECV_MESSAGE), is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA), is_op_live(call, GRPC_IOREQ_RECV_STATUS), is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS), is_op_live(call, GRPC_IOREQ_RECV_CLOSE), (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED)); return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) || is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_STATUS) || is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || - is_op_live(call, GRPC_IOREQ_RECV_CLOSE) || + (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) && grpc_bbq_empty(&call->incoming_queue)) || (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED); } @@ -687,7 +688,7 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) { static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; - gpr_log(GPR_DEBUG, "%s %p", __FUNCTION__, call); + gpr_log(GPR_DEBUG, "%s %p succ=%d rcvs=%d rds0=%d", __FUNCTION__, call, success, call->recv_state, call->read_state); lock(call); call->receiving = 0; if (success) { @@ -715,6 +716,7 @@ static void call_on_done_recv(void *pc, int success) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; } + gpr_log(GPR_DEBUG, "%p rds1=%d", call, call->read_state); finish_read_ops(call); } else { finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_ERROR); diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 238bcacfaa9..545d9ef78ef 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -957,7 +957,7 @@ static void finish_write_common(transport *t, int success) { } while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) { s->write_state = WRITE_STATE_SENT_CLOSE; - if (!s->cancelled) { + if (1||!s->cancelled) { maybe_finish_read(t, s); } } @@ -1916,6 +1916,7 @@ static void finish_reads(transport *t) { GPR_ASSERT(s->incoming_sopb); *s->publish_state = compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, s->read_closed); + gpr_log(GPR_DEBUG, "FR: %p pub=%d known=%d ws=%d rc=%d", s, *s->publish_state, s->published_state, s->write_state, s->read_closed); if (*s->publish_state != s->published_state) { s->published_state = *s->publish_state; publish = 1; diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index a2157109699..04c1d790226 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -87,6 +87,7 @@ char *grpc_sopb_string(grpc_stream_op_buffer *sopb) { break; case GRPC_OP_SLICE: gpr_asprintf(&tmp, "SLICE:%d", GPR_SLICE_LENGTH(op->data.slice)); + gpr_strvec_add(&b, tmp); break; case GRPC_OP_METADATA: gpr_strvec_add(&b, gpr_strdup("METADATA{")); From 64bc3fdaaaae22bab48d1ebda27c9791ea160590 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 17:07:12 -0700 Subject: [PATCH 40/58] remove annotations --- src/core/surface/call.c | 29 +++++++++++---------------- src/core/surface/call.h | 4 ++-- src/core/surface/completion_queue.c | 4 ++-- src/core/surface/server.c | 2 +- src/core/transport/chttp2_transport.c | 1 - 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 995e2dab7eb..a65bfb89039 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -299,7 +299,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, initial_op.on_done_recv = call_on_done_recv; initial_op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call, "receiving-0"); + grpc_call_internal_ref(call); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, @@ -319,8 +319,7 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) { return call->cq; } -void grpc_call_internal_ref(grpc_call *c, const char *reason) { -gpr_log(GPR_DEBUG, "grpc_call_internal_ref: %p %d %s %d -> %d", c, c->is_client, reason, c->internal_refcount.count, c->internal_refcount.count+1); +void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); } static void destroy_call(void *call, int ignored_success) { @@ -354,8 +353,7 @@ static void destroy_call(void *call, int ignored_success) { gpr_free(c); } -void grpc_call_internal_unref(grpc_call *c, const char *reason, int allow_immediate_deletion) { -gpr_log(GPR_DEBUG, "grpc_call_internal_unref: %p %d %s %d -> %d", c, c->is_client, reason, c->internal_refcount.count, c->internal_refcount.count-1); +void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) { if (gpr_unref(&c->internal_refcount)) { if (allow_immediate_deletion) { destroy_call(c, 1); @@ -408,7 +406,6 @@ static int is_op_live(grpc_call *call, grpc_ioreq_op op) { static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); } static int need_more_data(grpc_call *call) { - gpr_log(GPR_DEBUG, "st: %d%d%d%d%d%d%d", is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA), is_op_live(call, GRPC_IOREQ_RECV_MESSAGE), is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA), is_op_live(call, GRPC_IOREQ_RECV_STATUS), is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS), is_op_live(call, GRPC_IOREQ_RECV_CLOSE), (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED)); return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) || is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || @@ -433,14 +430,14 @@ static void unlock(grpc_call *call) { op.on_done_recv = call_on_done_recv; op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call, "receiving"); + grpc_call_internal_ref(call); start_op = 1; } if (!call->sending) { if (fill_send_ops(call, &op)) { call->sending = 1; - grpc_call_internal_ref(call, "sending"); + grpc_call_internal_ref(call); start_op = 1; } } @@ -451,7 +448,7 @@ static void unlock(grpc_call *call) { sizeof(completed_requests)); call->num_completed_requests = 0; call->completing = 1; - grpc_call_internal_ref(call, "completing"); + grpc_call_internal_ref(call); } gpr_mu_unlock(&call->mu); @@ -468,7 +465,7 @@ static void unlock(grpc_call *call) { lock(call); call->completing = 0; unlock(call); - grpc_call_internal_unref(call, "completing", 0); + grpc_call_internal_unref(call, 0); } } @@ -608,7 +605,7 @@ static void call_on_done_send(void *pc, int success) { call->last_send_contains = 0; call->sending = 0; unlock(call); - grpc_call_internal_unref(call, "sending", 0); + grpc_call_internal_unref(call, 0); } static void finish_message(grpc_call *call) { @@ -688,7 +685,6 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) { static void call_on_done_recv(void *pc, int success) { grpc_call *call = pc; size_t i; - gpr_log(GPR_DEBUG, "%s %p succ=%d rcvs=%d rds0=%d", __FUNCTION__, call, success, call->recv_state, call->read_state); lock(call); call->receiving = 0; if (success) { @@ -716,7 +712,6 @@ static void call_on_done_recv(void *pc, int success) { GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED); call->read_state = READ_STATE_STREAM_CLOSED; } - gpr_log(GPR_DEBUG, "%p rds1=%d", call, call->read_state); finish_read_ops(call); } else { finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_ERROR); @@ -729,7 +724,7 @@ static void call_on_done_recv(void *pc, int success) { call->recv_ops.nops = 0; unlock(call); - grpc_call_internal_unref(call, "receiving", 0); + grpc_call_internal_unref(call, 0); } static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, @@ -987,7 +982,7 @@ void grpc_call_destroy(grpc_call *c) { cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c); - grpc_call_internal_unref(c, "destroy", 1); + grpc_call_internal_unref(c, 1); } grpc_call_error grpc_call_cancel(grpc_call *call) { @@ -1034,7 +1029,7 @@ static void call_alarm(void *arg, int success) { grpc_call_cancel(call); } } - grpc_call_internal_unref(call, "alarm", 1); + grpc_call_internal_unref(call, 1); } static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { @@ -1043,7 +1038,7 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { assert(0); return; } - grpc_call_internal_ref(call, "alarm"); + grpc_call_internal_ref(call); call->have_alarm = 1; grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now()); } diff --git a/src/core/surface/call.h b/src/core/surface/call.h index f0c31e3a0d0..199beb17386 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -93,8 +93,8 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq); grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call); -void grpc_call_internal_ref(grpc_call *call, const char *reason); -void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion); +void grpc_call_internal_ref(grpc_call *call); +void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion); grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index 4398c43f5ef..24f4a05071a 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -135,7 +135,7 @@ static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type, void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call, grpc_completion_type type) { gpr_ref(&cc->refs); - if (call) grpc_call_internal_ref(call, "cq"); + if (call) grpc_call_internal_ref(call); #ifndef NDEBUG gpr_atm_no_barrier_fetch_add(&cc->pending_op_count[type], 1); #endif @@ -409,7 +409,7 @@ void grpc_event_finish(grpc_event *base) { event *ev = (event *)base; ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK); if (ev->base.call) { - grpc_call_internal_unref(ev->base.call, "cq", 1); + grpc_call_internal_unref(ev->base.call, 1); } gpr_free(ev); } diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 254a1a64bd2..2f00ad0bc6c 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -1131,7 +1131,7 @@ static void begin_call(grpc_server *server, call_data *calld, break; } - grpc_call_internal_ref(calld->call, "server"); + grpc_call_internal_ref(calld->call); grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc->tag); } diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 545d9ef78ef..6dd8f0cde11 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1916,7 +1916,6 @@ static void finish_reads(transport *t) { GPR_ASSERT(s->incoming_sopb); *s->publish_state = compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, s->read_closed); - gpr_log(GPR_DEBUG, "FR: %p pub=%d known=%d ws=%d rc=%d", s, *s->publish_state, s->published_state, s->write_state, s->read_closed); if (*s->publish_state != s->published_state) { s->published_state = *s->publish_state; publish = 1; From b56ca8d555fc6517e274637c7996c051eab99f24 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 17:16:22 -0700 Subject: [PATCH 41/58] Fix use-after-free in lame client test --- src/core/surface/call.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index a65bfb89039..8f1dfa75b81 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -343,12 +343,12 @@ static void destroy_call(void *call, int ignored_success) { for (i = 0; i < c->send_initial_metadata_count; i++) { grpc_mdelem_unref(c->send_initial_metadata[i].md); } + grpc_sopb_destroy(&c->send_ops); + grpc_sopb_destroy(&c->recv_ops); if (c->legacy_state) { destroy_legacy_state(c->legacy_state); } grpc_bbq_destroy(&c->incoming_queue); - grpc_sopb_destroy(&c->send_ops); - grpc_sopb_destroy(&c->recv_ops); gpr_slice_buffer_destroy(&c->incoming_message); gpr_free(c); } From 2b0f7c5b1eb50f2d62e7fad757c1be6f007de28b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 24 Apr 2015 17:23:17 -0700 Subject: [PATCH 42/58] Thread safety fix --- src/core/transport/chttp2_transport.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 6dd8f0cde11..9f9005691b7 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -317,6 +317,7 @@ struct stream { grpc_linked_mdelem *incoming_metadata; size_t incoming_metadata_count; size_t incoming_metadata_capacity; + grpc_linked_mdelem *old_incoming_metadata; gpr_timespec incoming_deadline; /* sops from application */ @@ -669,6 +670,7 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { grpc_mdelem_unref(s->incoming_metadata[i].md); } gpr_free(s->incoming_metadata); + gpr_free(s->old_incoming_metadata); unref_transport(t); } @@ -1059,6 +1061,8 @@ static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) { s->incoming_sopb = op->recv_ops; s->incoming_sopb->nops = 0; s->publish_state = op->recv_state; + gpr_free(s->old_incoming_metadata); + s->old_incoming_metadata = NULL; maybe_finish_read(t, s); maybe_join_window_updates(t, s); } @@ -1904,8 +1908,10 @@ static void patch_metadata_ops(stream *s) { mdidx = last_mdidx; } GPR_ASSERT(mdidx == s->incoming_metadata_count); - + s->old_incoming_metadata = s->incoming_metadata; + s->incoming_metadata = NULL; s->incoming_metadata_count = 0; + s->incoming_metadata_capacity = 0; } static void finish_reads(transport *t) { From d5e2e296bf9e897589f2bbf55f580c4ba0f9af8d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 07:54:37 -0700 Subject: [PATCH 43/58] Fix comment --- include/grpc/support/tls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grpc/support/tls.h b/include/grpc/support/tls.h index 1077fdec295..8dffd522559 100644 --- a/include/grpc/support/tls.h +++ b/include/grpc/support/tls.h @@ -44,7 +44,7 @@ Thread locals have type gpr_intptr. Declaring a thread local variable 'foo': - GPR_TLS_DECL(foo, initial_value); + GPR_TLS_DECL(foo); Thread locals always have static scope. Initializing a thread local (must be done at library initialization From ea9fbb15b861f71c6fa0c7d78f786c74ce1698fb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 07:58:16 -0700 Subject: [PATCH 44/58] Stop kicking ourselves --- .../pollset_multipoller_with_poll_posix.c | 2 +- src/core/iomgr/pollset_posix.c | 28 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c index bcef7c35b5d..25b7cfda1a1 100644 --- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c +++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c @@ -203,7 +203,7 @@ static int multipoll_with_poll_pollset_maybe_work( } static void multipoll_with_poll_pollset_kick(grpc_pollset *p) { - grpc_pollset_kick_kick(&p->kick_state); + grpc_pollset_force_kick(p); } static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) { diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c index 03fd94f1364..60d0dad6d87 100644 --- a/src/core/iomgr/pollset_posix.c +++ b/src/core/iomgr/pollset_posix.c @@ -47,9 +47,11 @@ #include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/socket_utils_posix.h" +#include "src/core/profiling/timers.h" #include #include #include +#include #include static grpc_pollset g_backup_pollset; @@ -57,6 +59,8 @@ static int g_shutdown_backup_poller; static gpr_event g_backup_poller_done; static gpr_event g_backup_pollset_shutdown_done; +GPR_TLS_DECL(g_current_thread_poller); + static void backup_poller(void *p) { gpr_timespec delta = gpr_time_from_millis(100); gpr_timespec last_poll = gpr_now(); @@ -76,17 +80,21 @@ static void backup_poller(void *p) { } void grpc_pollset_kick(grpc_pollset *p) { - if (p->counter) { + if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p && p->counter) { p->vtable->kick(p); } } void grpc_pollset_force_kick(grpc_pollset *p) { - grpc_pollset_kick_kick(&p->kick_state); + if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) { + grpc_pollset_kick_kick(&p->kick_state); + } } static void kick_using_pollset_kick(grpc_pollset *p) { - grpc_pollset_kick_kick(&p->kick_state); + if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) { + grpc_pollset_kick_kick(&p->kick_state); + } } /* global state management */ @@ -96,6 +104,8 @@ grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; } void grpc_pollset_global_init(void) { gpr_thd_id id; + gpr_tls_init(&g_current_thread_poller); + /* Initialize kick fd state */ grpc_pollset_kick_global_init(); @@ -129,6 +139,8 @@ void grpc_pollset_global_shutdown(void) { /* destroy the kick pipes */ grpc_pollset_kick_global_destroy(); + + gpr_tls_destroy(&g_current_thread_poller); } /* main interface */ @@ -161,8 +173,8 @@ void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) { int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { /* pollset->mu already held */ - gpr_timespec now; - now = gpr_now(); + gpr_timespec now = gpr_now(); + int r; if (gpr_time_cmp(now, deadline) > 0) { return 0; } @@ -172,7 +184,10 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) { if (grpc_alarm_check(&pollset->mu, now, &deadline)) { return 1; } - return pollset->vtable->maybe_work(pollset, deadline, now, 1); + gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset); + r = pollset->vtable->maybe_work(pollset, deadline, now, 1); + gpr_tls_set(&g_current_thread_poller, 0); + return r; } void grpc_pollset_shutdown(grpc_pollset *pollset, @@ -396,6 +411,7 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset, pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher); r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout); + GRPC_TIMER_MARK(POLL_FINISHED, r); grpc_fd_end_poll(&fd_watcher); From a2b32f1133e3c4e0157d1c5d040fece7582f2270 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 08:55:08 -0700 Subject: [PATCH 45/58] Fix early shutdown: await client context deletion before channel deletion --- include/grpc++/client_context.h | 5 ++++- src/cpp/client/channel.cc | 2 +- src/cpp/client/channel.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h index 19630c9b544..a58e9872e60 100644 --- a/include/grpc++/client_context.h +++ b/include/grpc++/client_context.h @@ -35,6 +35,7 @@ #define GRPCXX_CLIENT_CONTEXT_H #include +#include #include #include @@ -126,9 +127,10 @@ class ClientContext { friend class ::grpc::ClientAsyncResponseReader; grpc_call* call() { return call_; } - void set_call(grpc_call* call) { + void set_call(grpc_call* call, const std::shared_ptr& channel) { GPR_ASSERT(call_ == nullptr); call_ = call; + channel_ = channel; } grpc_completion_queue* cq() { return cq_; } @@ -137,6 +139,7 @@ class ClientContext { grpc::string authority() { return authority_; } bool initial_metadata_received_; + std::shared_ptr channel_; grpc_call* call_; grpc_completion_queue* cq_; gpr_timespec deadline_; diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc index ba8882278f5..c541ddfb487 100644 --- a/src/cpp/client/channel.cc +++ b/src/cpp/client/channel.cc @@ -71,7 +71,7 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, : context->authority().c_str(), context->raw_deadline()); GRPC_TIMER_MARK(CALL_CREATED, c_call); - context->set_call(c_call); + context->set_call(c_call, shared_from_this()); return Call(c_call, this, cq); } diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index cd239247c82..46009d20bad 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -51,6 +51,7 @@ class Credentials; class StreamContextInterface; class Channel GRPC_FINAL : public GrpcLibrary, + public std::enable_shared_from_this, public ChannelInterface { public: Channel(const grpc::string& target, grpc_channel* c_channel); From 59abfc234b666c9e5e667cf6dfb7fb786888d40a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 09:29:35 -0700 Subject: [PATCH 46/58] Properly handle non-full metadata batches --- src/core/transport/chttp2_transport.c | 31 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 9f9005691b7..26c550c1f17 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1890,13 +1890,22 @@ static void patch_metadata_ops(stream *s) { size_t j; size_t mdidx = 0; size_t last_mdidx; + int found_metadata = 0; + /* rework the array of metadata into a linked list, making use + of the breadcrumbs we left in metadata batches during + add_metadata_batch */ for (i = 0; i < nops; i++) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; + found_metadata = 1; + /* we left a breadcrumb indicating where the end of this list is, + and since we add sequentially, we know from the end of the last + segment where this segment begins */ last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail); GPR_ASSERT(last_mdidx > mdidx); GPR_ASSERT(last_mdidx <= s->incoming_metadata_count); + /* turn the array into a doubly linked list */ op->data.metadata.list.head = &s->incoming_metadata[mdidx]; op->data.metadata.list.tail = &s->incoming_metadata[last_mdidx - 1]; for (j = mdidx + 1; j < last_mdidx; j++) { @@ -1905,13 +1914,25 @@ static void patch_metadata_ops(stream *s) { } s->incoming_metadata[mdidx].prev = NULL; s->incoming_metadata[last_mdidx-1].next = NULL; + /* track where we're up to */ mdidx = last_mdidx; } - GPR_ASSERT(mdidx == s->incoming_metadata_count); - s->old_incoming_metadata = s->incoming_metadata; - s->incoming_metadata = NULL; - s->incoming_metadata_count = 0; - s->incoming_metadata_capacity = 0; + if (found_metadata) { + s->old_incoming_metadata = s->incoming_metadata; + if (mdidx != s->incoming_metadata_count) { + /* we have a partially read metadata batch still in incoming_metadata */ + size_t new_count = s->incoming_metadata_count - mdidx; + size_t copy_bytes = sizeof(*s->incoming_metadata) * new_count; + GPR_ASSERT(mdidx < s->incoming_metadata_count); + s->incoming_metadata = gpr_malloc(copy_bytes); + memcpy(s->old_incoming_metadata + mdidx, s->incoming_metadata, copy_bytes); + s->incoming_metadata_count = s->incoming_metadata_capacity = new_count; + } else { + s->incoming_metadata = NULL; + s->incoming_metadata_count = 0; + s->incoming_metadata_capacity = 0; + } + } } static void finish_reads(transport *t) { From 75cfb1f9f15dbb515b5b761a83e697f302e7b9ef Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 09:33:05 -0700 Subject: [PATCH 47/58] Update test definition --- test/core/end2end/dualstack_socket_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c index 29097661bce..7b3500233bd 100644 --- a/test/core/end2end/dualstack_socket_test.c +++ b/test/core/end2end/dualstack_socket_test.c @@ -158,7 +158,7 @@ void test_connect(const char *server_host, const char *client_host, int port, cq_expect_finished_with_status(v_client, tag(3), GRPC_STATUS_DEADLINE_EXCEEDED, "Deadline Exceeded", NULL); - cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_ERROR); + cq_expect_finish_accepted(v_client, tag(4), GRPC_OP_OK); cq_verify(v_client); grpc_call_destroy(c); From 4d8f268028546de32d1bce40f6e1a82c868f1758 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 10:40:08 -0700 Subject: [PATCH 48/58] Add a lock that seems to help --- src/core/surface/completion_queue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index 24f4a05071a..f3c2453b5e7 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -401,7 +401,9 @@ static void on_pollset_destroy_done(void *arg) { } void grpc_completion_queue_destroy(grpc_completion_queue *cc) { + gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); GPR_ASSERT(cc->queue == NULL); + gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc); } From 00e5b2a82cbbb5127c29a9241393a501dcba8094 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 18:27:04 -0700 Subject: [PATCH 49/58] Mac C++ compile fix --- include/grpc++/channel_interface.h | 6 +++++- src/cpp/client/channel.h | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/grpc++/channel_interface.h b/include/grpc++/channel_interface.h index 4d48974e691..e86a83bc45b 100644 --- a/include/grpc++/channel_interface.h +++ b/include/grpc++/channel_interface.h @@ -34,6 +34,8 @@ #ifndef GRPCXX_CHANNEL_INTERFACE_H #define GRPCXX_CHANNEL_INTERFACE_H +#include + #include #include @@ -47,7 +49,9 @@ class CompletionQueue; class RpcMethod; class CallInterface; -class ChannelInterface : public CallHook { +class ChannelInterface + : public CallHook, + public std::enable_shared_from_this { public: virtual ~ChannelInterface() {} diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h index 46009d20bad..cd239247c82 100644 --- a/src/cpp/client/channel.h +++ b/src/cpp/client/channel.h @@ -51,7 +51,6 @@ class Credentials; class StreamContextInterface; class Channel GRPC_FINAL : public GrpcLibrary, - public std::enable_shared_from_this, public ChannelInterface { public: Channel(const grpc::string& target, grpc_channel* c_channel); From bec41a298bf71ebdebcbe522c1622467132020e9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 27 Apr 2015 18:47:40 -0700 Subject: [PATCH 50/58] Return correct status message for lame client --- src/core/surface/lame_client.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index c93222344d0..209bdc5d248 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -42,13 +42,40 @@ #include #include -typedef struct { void *unused; } call_data; +typedef struct { + grpc_linked_mdelem status; + grpc_linked_mdelem details; +} call_data; -typedef struct { void *unused; } channel_data; +typedef struct { grpc_mdctx *mdctx; } channel_data; static void lame_start_transport_op(grpc_call_element *elem, grpc_transport_op *op) { + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); + if (op->send_ops) { + op->on_done_send(op->send_user_data, 0); + } + if (op->recv_ops) { + char tmp[GPR_LTOA_MIN_BUFSIZE]; + grpc_metadata_batch mdb; + gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp); + calld->status.md = + grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp); + calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message", + "Rpc sent on a lame channel."); + calld->status.prev = calld->details.next = NULL; + calld->status.next = &calld->details; + calld->details.prev = &calld->status; + mdb.list.head = &calld->status; + mdb.list.tail = &calld->details; + mdb.garbage.head = mdb.garbage.tail = NULL; + mdb.deadline = gpr_inf_future; + grpc_sopb_add_metadata(op->recv_ops, mdb); + *op->recv_state = GRPC_STREAM_CLOSED; + op->on_done_recv(op->recv_user_data, 1); + } grpc_transport_op_finish_with_failure(op); } @@ -79,8 +106,10 @@ static void destroy_call_elem(grpc_call_element *elem) {} static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { + channel_data *chand = elem->channel_data; GPR_ASSERT(is_first); GPR_ASSERT(is_last); + chand->mdctx = mdctx; } static void destroy_channel_elem(grpc_channel_element *elem) {} From 333ee250b2857f2889266dfe7c9059ed0207505b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 28 Apr 2015 07:56:59 -0700 Subject: [PATCH 51/58] Remove errant double finish --- src/core/surface/lame_client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c index 209bdc5d248..3186292a02b 100644 --- a/src/core/surface/lame_client.c +++ b/src/core/surface/lame_client.c @@ -76,7 +76,6 @@ static void lame_start_transport_op(grpc_call_element *elem, *op->recv_state = GRPC_STREAM_CLOSED; op->on_done_recv(op->recv_user_data, 1); } - grpc_transport_op_finish_with_failure(op); } static void channel_op(grpc_channel_element *elem, From 4df412b471a3e739dda559a197873f6ce09cf33b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 28 Apr 2015 07:57:54 -0700 Subject: [PATCH 52/58] Add some infrastructure for call refcount debugging --- src/core/surface/call.c | 44 ++++++++++++++++++++--------- src/core/surface/call.h | 9 ++++++ src/core/surface/completion_queue.c | 4 +-- src/core/surface/server.c | 2 +- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 8f1dfa75b81..6ca1b4e9a13 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -299,7 +299,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, initial_op.on_done_recv = call_on_done_recv; initial_op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call); + GRPC_CALL_INTERNAL_REF(call, "receiving"); initial_op_ptr = &initial_op; } grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr, @@ -319,8 +319,15 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) { return call->cq; } -void grpc_call_internal_ref(grpc_call *c) { - gpr_ref(&c->internal_refcount); } +#ifdef GRPC_CALL_REF_COUNT_DEBUG +void grpc_call_internal_ref(grpc_call *c, const char *reason) { + gpr_log(GPR_DEBUG, "CALL: ref %p %d -> %d [%s]", c, + c->internal_refcount.count, c->internal_refcount.count + 1, reason); +#else +void grpc_call_internal_ref(grpc_call *c) { +#endif + gpr_ref(&c->internal_refcount); +} static void destroy_call(void *call, int ignored_success) { size_t i; @@ -353,7 +360,14 @@ static void destroy_call(void *call, int ignored_success) { gpr_free(c); } +#ifdef GRPC_CALL_REF_COUNT_DEBUG +void grpc_call_internal_unref(grpc_call *c, const char *reason, + int allow_immediate_deletion) { + gpr_log(GPR_DEBUG, "CALL: unref %p %d -> %d [%s]", c, + c->internal_refcount.count, c->internal_refcount.count - 1, reason); +#else void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) { +#endif if (gpr_unref(&c->internal_refcount)) { if (allow_immediate_deletion) { destroy_call(c, 1); @@ -411,8 +425,10 @@ static int need_more_data(grpc_call *call) { is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) || is_op_live(call, GRPC_IOREQ_RECV_STATUS) || is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) || - (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) && grpc_bbq_empty(&call->incoming_queue)) || - (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED); + (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) && + grpc_bbq_empty(&call->incoming_queue)) || + (call->write_state == WRITE_STATE_INITIAL && !call->is_client && + call->read_state != READ_STATE_STREAM_CLOSED); } static void unlock(grpc_call *call) { @@ -430,14 +446,14 @@ static void unlock(grpc_call *call) { op.on_done_recv = call_on_done_recv; op.recv_user_data = call; call->receiving = 1; - grpc_call_internal_ref(call); + GRPC_CALL_INTERNAL_REF(call, "receiving"); start_op = 1; } if (!call->sending) { if (fill_send_ops(call, &op)) { call->sending = 1; - grpc_call_internal_ref(call); + GRPC_CALL_INTERNAL_REF(call, "sending"); start_op = 1; } } @@ -448,7 +464,7 @@ static void unlock(grpc_call *call) { sizeof(completed_requests)); call->num_completed_requests = 0; call->completing = 1; - grpc_call_internal_ref(call); + GRPC_CALL_INTERNAL_REF(call, "completing"); } gpr_mu_unlock(&call->mu); @@ -465,7 +481,7 @@ static void unlock(grpc_call *call) { lock(call); call->completing = 0; unlock(call); - grpc_call_internal_unref(call, 0); + GRPC_CALL_INTERNAL_UNREF(call, "completing", 0); } } @@ -605,7 +621,7 @@ static void call_on_done_send(void *pc, int success) { call->last_send_contains = 0; call->sending = 0; unlock(call); - grpc_call_internal_unref(call, 0); + GRPC_CALL_INTERNAL_UNREF(call, "sending", 0); } static void finish_message(grpc_call *call) { @@ -724,7 +740,7 @@ static void call_on_done_recv(void *pc, int success) { call->recv_ops.nops = 0; unlock(call); - grpc_call_internal_unref(call, 0); + GRPC_CALL_INTERNAL_UNREF(call, "receiving", 0); } static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, @@ -982,7 +998,7 @@ void grpc_call_destroy(grpc_call *c) { cancel = c->read_state != READ_STATE_STREAM_CLOSED; unlock(c); if (cancel) grpc_call_cancel(c); - grpc_call_internal_unref(c, 1); + GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1); } grpc_call_error grpc_call_cancel(grpc_call *call) { @@ -1029,7 +1045,7 @@ static void call_alarm(void *arg, int success) { grpc_call_cancel(call); } } - grpc_call_internal_unref(call, 1); + GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1); } static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { @@ -1038,7 +1054,7 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) { assert(0); return; } - grpc_call_internal_ref(call); + GRPC_CALL_INTERNAL_REF(call, "alarm"); call->have_alarm = 1; grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now()); } diff --git a/src/core/surface/call.h b/src/core/surface/call.h index 199beb17386..2d4c7f61e3f 100644 --- a/src/core/surface/call.h +++ b/src/core/surface/call.h @@ -93,8 +93,17 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq, void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq); grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call); +#ifdef GRPC_CALL_REF_COUNT_DEBUG +void grpc_call_internal_ref(grpc_call *call, const char *reason); +void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion); +#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call, reason) +#define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) grpc_call_internal_unref(call, reason, allow_immediate_deletion) +#else void grpc_call_internal_ref(grpc_call *call); void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion); +#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call) +#define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) grpc_call_internal_unref(call, allow_immediate_deletion) +#endif grpc_call_error grpc_call_start_ioreq_and_call_back( grpc_call *call, const grpc_ioreq *reqs, size_t nreqs, diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c index f3c2453b5e7..fe5334bdeb5 100644 --- a/src/core/surface/completion_queue.c +++ b/src/core/surface/completion_queue.c @@ -135,7 +135,7 @@ static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type, void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call, grpc_completion_type type) { gpr_ref(&cc->refs); - if (call) grpc_call_internal_ref(call); + if (call) GRPC_CALL_INTERNAL_REF(call, "cq"); #ifndef NDEBUG gpr_atm_no_barrier_fetch_add(&cc->pending_op_count[type], 1); #endif @@ -411,7 +411,7 @@ void grpc_event_finish(grpc_event *base) { event *ev = (event *)base; ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK); if (ev->base.call) { - grpc_call_internal_unref(ev->base.call, 1); + GRPC_CALL_INTERNAL_UNREF(ev->base.call, "cq", 1); } gpr_free(ev); } diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 3cc8f9cbb94..0120cb90c23 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -1132,7 +1132,7 @@ static void begin_call(grpc_server *server, call_data *calld, break; } - grpc_call_internal_ref(calld->call); + GRPC_CALL_INTERNAL_REF(calld->call, "server"); grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc->tag); } From 816791ca72a9978aa763babe320b5e8b4c41ff0a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 28 Apr 2015 16:55:08 -0700 Subject: [PATCH 53/58] Add comment --- src/core/transport/transport_op_string.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index 04c1d790226..7bbe8276c38 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -41,6 +41,9 @@ #include #include +/* These routines are here to facilitate debugging - they produce string + representations of various transport data structures */ + static void put_metadata(gpr_strvec *b, grpc_mdelem *md) { gpr_strvec_add(b, gpr_strdup("key=")); gpr_strvec_add( From 87ab19f8131a54a07590b365e8ae9303ace4c1c1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 28 Apr 2015 17:05:09 -0700 Subject: [PATCH 54/58] Capure thread id with default timer implementation --- src/core/profiling/timers.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/profiling/timers.c b/src/core/profiling/timers.c index 7cc79bd22bc..bd1700ffd8c 100644 --- a/src/core/profiling/timers.c +++ b/src/core/profiling/timers.c @@ -40,10 +40,12 @@ #include #include #include +#include #include typedef struct grpc_timer_entry { grpc_precise_clock tm; + gpr_thd_id thd; const char* tag; void* id; const char* file; @@ -85,7 +87,7 @@ static void log_report_locked(grpc_timers_log* log) { grpc_timer_entry* entry = &(log->log[i]); fprintf(fp, "GRPC_LAT_PROF "); grpc_precise_clock_print(&entry->tm, fp); - fprintf(fp, " %s %p %s %d\n", entry->tag, entry->id, entry->file, + fprintf(fp, " %p %s %p %s %d\n", (void*)(gpr_intptr)entry->thd, entry->tag, entry->id, entry->file, entry->line); } @@ -121,6 +123,7 @@ void grpc_timers_log_add(grpc_timers_log* log, const char* tag, void* id, entry->id = id; entry->file = file; entry->line = line; + entry->thd = gpr_thd_currentid(); gpr_mu_unlock(&log->mu); } From 8a5bce35419abd3d0b51498afcdd091b39683930 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 29 Apr 2015 07:49:47 -0700 Subject: [PATCH 55/58] Incoming stream id validation fixes - correct log message on an invalid stream id - add an additional check that the low bit indicates a client stream id on the server --- src/core/transport/chttp2_transport.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index e32ee284e09..1bb6e7f9608 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -1327,7 +1327,10 @@ static int init_header_frame_parser(transport *t, int is_continuation) { gpr_log(GPR_ERROR, "ignoring out of order new stream request on server; last stream " "id=%d, new stream id=%d", - t->last_incoming_stream_id, t->incoming_stream); + t->last_incoming_stream_id, t->incoming_stream_id); + return init_skip_frame(t, 1); + } else if ((t->incoming_stream_id & 1) == 0) { + gpr_log(GPR_ERROR, "ignoring stream with non-client generated index %d", t->incoming_stream_id); return init_skip_frame(t, 1); } t->incoming_stream = NULL; From 07b2fe6f964fce0574d7593bc8347e60cac40a94 Mon Sep 17 00:00:00 2001 From: vjpai Date: Wed, 29 Apr 2015 10:40:26 -0700 Subject: [PATCH 56/58] Move end_threads to subclass since some subclass-specific fields will still be alive at this time --- test/cpp/qps/client_sync.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc index 5dd64d0b134..0809eb5b6c7 100644 --- a/test/cpp/qps/client_sync.cc +++ b/test/cpp/qps/client_sync.cc @@ -70,7 +70,7 @@ class SynchronousClient : public Client { responses_.resize(num_threads_); } - virtual ~SynchronousClient() { EndThreads(); } + virtual ~SynchronousClient() {}; protected: size_t num_threads_; @@ -81,7 +81,7 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient { public: SynchronousUnaryClient(const ClientConfig& config): SynchronousClient(config) {StartThreads(num_threads_);} - ~SynchronousUnaryClient() {} + ~SynchronousUnaryClient() {EndThreads();} bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE { auto* stub = channels_[thread_idx % channels_.size()].get_stub(); From 1cb8bbcf0a44682eb59ee31b34fb7cd6a437797b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Apr 2015 11:11:07 -0700 Subject: [PATCH 57/58] Fix thread local storage error in iOS build --- include/grpc/support/port_platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h index 864d669eda0..671648a976b 100644 --- a/include/grpc/support/port_platform.h +++ b/include/grpc/support/port_platform.h @@ -136,11 +136,12 @@ #endif #if TARGET_OS_IPHONE #define GPR_CPU_IPHONE 1 +#define GPR_PTHREAD_TLS 1 #else /* TARGET_OS_IPHONE */ #define GPR_CPU_POSIX 1 +#define GPR_GCC_TLS 1 #endif #define GPR_GCC_ATOMIC 1 -#define GPR_GCC_TLS 1 #define GPR_POSIX_LOG 1 #define GPR_POSIX_MULTIPOLL_WITH_POLL 1 #define GPR_POSIX_WAKEUP_FD 1 From f3764292f0ffa00713063c852384f57300b4064b Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Wed, 29 Apr 2015 11:35:07 -0700 Subject: [PATCH 58/58] Ref the cache default creds so that we do not crash next time we use it... --- src/core/security/google_default_credentials.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index d2f46ddd07f..0e4b9fc9d32 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -163,7 +163,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) { gpr_mu_lock(&g_mu); if (default_credentials != NULL) { - result = default_credentials; + result = grpc_credentials_ref(default_credentials); serving_cached_credentials = 1; goto end; }