From 5842a5b0895e8ee713991625d3066fa8e948a52a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 12:38:57 -0700 Subject: Initial sketch of async execution lock --- src/core/lib/iomgr/async_execution_lock.c | 71 +++++++++++++++++++++++++++++++ src/core/lib/iomgr/async_execution_lock.h | 58 +++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/core/lib/iomgr/async_execution_lock.c create mode 100644 src/core/lib/iomgr/async_execution_lock.h (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c new file mode 100644 index 0000000000..20bdf3f9a9 --- /dev/null +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -0,0 +1,71 @@ +#include "src/core/lib/iomgr/async_execution_lock.h" + +#define NO_CONSUMER ((gpr_atm)1) + +void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue) { + lock->optional_workqueue = optional_workqueue; + gpr_atm_no_barrier_store(&lock->head, NO_CONSUMER); + lock->tail = &lock->stub; + gpr_atm_no_barrier_store(&lock->next, 0); +} + +void grpc_aelock_destroy(grpc_aelock *lock) { + GPR_ASSERT(gpr_atm_no_barrier_load(&lock->head) == NO_CONSUMER); +} + +static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { + for (;;) { + grpc_aelock_qnode *tail = lock->tail; + grpc_aelock_qnode *next = + (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); + if (next == NULL) { + if (gpr_atm_rel_cas(&lock->head, (gpr_atm)&lock->stub, NO_CONSUMER)) { + return; + } + } else { + lock->tail = next; + + next->action(exec_ctx, next->arg); + gpr_free(next); + } + } +} + +void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, + grpc_aelock_action action, void *arg, + size_t sizeof_arg) { +retry_top: + gpr_atm cur = gpr_atm_acq_load(&lock->head); + if (cur == NO_CONSUMER) { + if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->stub)) { + goto retry_top; + } + action(exec_ctx, arg); + finish(exec_ctx, lock); + return; // early out + } + + grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); + n->action = action; + gpr_atm_no_barrier_store(&n->next, 0); + if (sizeof_arg > 0) { + memcpy(n + 1, arg, sizeof_arg); + n->arg = n + 1; + } else { + n->arg = arg; + } + while (!gpr_atm_rel_cas(&lock->head, cur, (gpr_atm)n)) { + retry_queue_load: + cur = gpr_atm_acq_load(&lock->head); + if (cur == NO_CONSUMER) { + if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->stub)) { + goto retry_queue_load; + } + gpr_free(n); + action(exec_ctx, arg); + finish(exec_ctx, lock); + return; // early out + } + } + gpr_atm_no_barrier_store(&((grpc_aelock_qnode *)cur)->next, (gpr_atm)n); +} diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h new file mode 100644 index 0000000000..258e06db95 --- /dev/null +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -0,0 +1,58 @@ +/* + * + * 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 AEL_H +#define AEL_H + +typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); + +typedef struct grpc_aelock_qnode { + grpc_aelock_action action; + void *arg; + gpr_atm next; +} grpc_aelock_qnode; + +typedef struct grpc_aelock { + grpc_workqueue *optional_workqueue; + gpr_atm head; + struct grpc_aelock *tail; + grpc_aelock_qnode stub; +}; + +void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); +void grpc_aelock_destroy(grpc_aelock *lock); +void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, + grpc_aelock_action action, void *arg, + size_t sizeof_arg); + +#endif -- cgit v1.2.3 From a26637fdca19a6981cf8ea7e1bb0193c6addd2a4 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 13:36:36 -0700 Subject: Add a test and make things compile --- BUILD | 6 + Makefile | 38 ++++ binding.gyp | 1 + build.yaml | 12 ++ config.m4 | 1 + gRPC.podspec | 3 + grpc.gemspec | 2 + package.xml | 2 + src/core/lib/iomgr/async_execution_lock.c | 43 ++++- src/core/lib/iomgr/async_execution_lock.h | 10 +- src/python/grpcio/grpc_core_dependencies.py | 1 + test/core/iomgr/async_execution_lock_test.c | 116 ++++++++++++ tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/sources_and_headers.json | 19 ++ tools/run_tests/tests.json | 21 +++ vsprojects/buildtests_c.sln | 27 +++ vsprojects/vcxproj/grpc/grpc.vcxproj | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 6 + .../vcxproj/grpc_unsecure/grpc_unsecure.vcxproj | 3 + .../grpc_unsecure/grpc_unsecure.vcxproj.filters | 6 + .../async_execution_lock_test.vcxproj | 199 +++++++++++++++++++++ .../async_execution_lock_test.vcxproj.filters | 21 +++ 22 files changed, 538 insertions(+), 4 deletions(-) create mode 100644 test/core/iomgr/async_execution_lock_test.c create mode 100644 vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj create mode 100644 vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters (limited to 'src/core/lib') diff --git a/BUILD b/BUILD index b4b10b535e..ca152583a7 100644 --- a/BUILD +++ b/BUILD @@ -175,6 +175,7 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", + "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", @@ -307,6 +308,7 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", + "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", @@ -520,6 +522,7 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", + "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", @@ -639,6 +642,7 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", + "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", @@ -1324,6 +1328,7 @@ objc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", + "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", @@ -1516,6 +1521,7 @@ objc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", + "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", diff --git a/Makefile b/Makefile index 922e0b0568..52c27c97d6 100644 --- a/Makefile +++ b/Makefile @@ -882,6 +882,7 @@ algorithm_test: $(BINDIR)/$(CONFIG)/algorithm_test alloc_test: $(BINDIR)/$(CONFIG)/alloc_test alpn_test: $(BINDIR)/$(CONFIG)/alpn_test api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer +async_execution_lock_test: $(BINDIR)/$(CONFIG)/async_execution_lock_test bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test census_context_test: $(BINDIR)/$(CONFIG)/census_context_test channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test @@ -1218,6 +1219,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/algorithm_test \ $(BINDIR)/$(CONFIG)/alloc_test \ $(BINDIR)/$(CONFIG)/alpn_test \ + $(BINDIR)/$(CONFIG)/async_execution_lock_test \ $(BINDIR)/$(CONFIG)/bin_encoder_test \ $(BINDIR)/$(CONFIG)/census_context_test \ $(BINDIR)/$(CONFIG)/channel_create_test \ @@ -1472,6 +1474,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/alloc_test || ( echo test alloc_test failed ; exit 1 ) $(E) "[RUN] Testing alpn_test" $(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 ) + $(E) "[RUN] Testing async_execution_lock_test" + $(Q) $(BINDIR)/$(CONFIG)/async_execution_lock_test || ( echo test async_execution_lock_test failed ; exit 1 ) $(E) "[RUN] Testing bin_encoder_test" $(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 ) $(E) "[RUN] Testing census_context_test" @@ -2491,6 +2495,7 @@ LIBGRPC_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ + src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ @@ -2832,6 +2837,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ + src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ @@ -6114,6 +6120,38 @@ endif endif +ASYNC_EXECUTION_LOCK_TEST_SRC = \ + test/core/iomgr/async_execution_lock_test.c \ + +ASYNC_EXECUTION_LOCK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_EXECUTION_LOCK_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/async_execution_lock_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/async_execution_lock_test: $(ASYNC_EXECUTION_LOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(ASYNC_EXECUTION_LOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/async_execution_lock_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/iomgr/async_execution_lock_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_async_execution_lock_test: $(ASYNC_EXECUTION_LOCK_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(ASYNC_EXECUTION_LOCK_TEST_OBJS:.o=.dep) +endif +endif + + BIN_ENCODER_TEST_SRC = \ test/core/transport/chttp2/bin_encoder_test.c \ diff --git a/binding.gyp b/binding.gyp index 4314ab7243..fbec804f7a 100644 --- a/binding.gyp +++ b/binding.gyp @@ -577,6 +577,7 @@ 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', diff --git a/build.yaml b/build.yaml index 441752dc3d..aae3e5a242 100644 --- a/build.yaml +++ b/build.yaml @@ -162,6 +162,7 @@ filegroups: - src/core/lib/http/format_request.h - src/core/lib/http/httpcli.h - src/core/lib/http/parser.h + - src/core/lib/iomgr/async_execution_lock.h - src/core/lib/iomgr/closure.h - src/core/lib/iomgr/endpoint.h - src/core/lib/iomgr/endpoint_pair.h @@ -235,6 +236,7 @@ filegroups: - src/core/lib/http/format_request.c - src/core/lib/http/httpcli.c - src/core/lib/http/parser.c + - src/core/lib/iomgr/async_execution_lock.c - src/core/lib/iomgr/closure.c - src/core/lib/iomgr/endpoint.c - src/core/lib/iomgr/endpoint_pair_posix.c @@ -1137,6 +1139,16 @@ targets: - test/core/end2end/fuzzers/api_fuzzer_corpus dict: test/core/end2end/fuzzers/api_fuzzer.dictionary maxlen: 2048 +- name: async_execution_lock_test + build: test + language: c + src: + - test/core/iomgr/async_execution_lock_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr - name: bin_encoder_test build: test language: c diff --git a/config.m4 b/config.m4 index 74f9ad242a..30573cf920 100644 --- a/config.m4 +++ b/config.m4 @@ -96,6 +96,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ + src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ diff --git a/gRPC.podspec b/gRPC.podspec index 77d35bd2c7..a8744c8c70 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -177,6 +177,7 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', 'src/core/lib/http/parser.h', + 'src/core/lib/iomgr/async_execution_lock.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint_pair.h', @@ -341,6 +342,7 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', @@ -519,6 +521,7 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', 'src/core/lib/http/parser.h', + 'src/core/lib/iomgr/async_execution_lock.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint_pair.h', diff --git a/grpc.gemspec b/grpc.gemspec index e68cd81da7..fca828ad10 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -185,6 +185,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/format_request.h ) s.files += %w( src/core/lib/http/httpcli.h ) s.files += %w( src/core/lib/http/parser.h ) + s.files += %w( src/core/lib/iomgr/async_execution_lock.h ) s.files += %w( src/core/lib/iomgr/closure.h ) s.files += %w( src/core/lib/iomgr/endpoint.h ) s.files += %w( src/core/lib/iomgr/endpoint_pair.h ) @@ -321,6 +322,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/format_request.c ) s.files += %w( src/core/lib/http/httpcli.c ) s.files += %w( src/core/lib/http/parser.c ) + s.files += %w( src/core/lib/iomgr/async_execution_lock.c ) s.files += %w( src/core/lib/iomgr/closure.c ) s.files += %w( src/core/lib/iomgr/endpoint.c ) s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c ) diff --git a/package.xml b/package.xml index ffb1c56ed6..d259dd043f 100644 --- a/package.xml +++ b/package.xml @@ -192,6 +192,7 @@ + @@ -328,6 +329,7 @@ + diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 20bdf3f9a9..62ece4cc8c 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -1,12 +1,50 @@ +/* + * + * 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/lib/iomgr/async_execution_lock.h" +#include + +#include +#include + #define NO_CONSUMER ((gpr_atm)1) void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue) { lock->optional_workqueue = optional_workqueue; gpr_atm_no_barrier_store(&lock->head, NO_CONSUMER); lock->tail = &lock->stub; - gpr_atm_no_barrier_store(&lock->next, 0); + gpr_atm_no_barrier_store(&lock->stub.next, 0); } void grpc_aelock_destroy(grpc_aelock *lock) { @@ -34,8 +72,9 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { + gpr_atm cur; retry_top: - gpr_atm cur = gpr_atm_acq_load(&lock->head); + cur = gpr_atm_acq_load(&lock->head); if (cur == NO_CONSUMER) { if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->stub)) { goto retry_top; diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index 258e06db95..cb4de61349 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -34,6 +34,11 @@ #ifndef AEL_H #define AEL_H +#include + +#include +#include "src/core/lib/iomgr/exec_ctx.h" + typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); typedef struct grpc_aelock_qnode { @@ -44,10 +49,11 @@ typedef struct grpc_aelock_qnode { typedef struct grpc_aelock { grpc_workqueue *optional_workqueue; + // grpc_aelock_qnode* gpr_atm head; - struct grpc_aelock *tail; + grpc_aelock_qnode *tail; grpc_aelock_qnode stub; -}; +} grpc_aelock; void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); void grpc_aelock_destroy(grpc_aelock *lock); diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index dab62530aa..88db62abb4 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -90,6 +90,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', + 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c new file mode 100644 index 0000000000..405f89362c --- /dev/null +++ b/test/core/iomgr/async_execution_lock_test.c @@ -0,0 +1,116 @@ +/* + * + * 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/lib/iomgr/async_execution_lock.h" + +#include +#include +#include +#include + +#include "test/core/util/test_config.h" + +static void test_no_op(void) { + gpr_log(GPR_DEBUG, "test_no_op"); + + grpc_aelock lock; + grpc_aelock_init(&lock, NULL); + grpc_aelock_destroy(&lock); +} + +static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { + *(bool *)value = true; +} + +static void test_execute_one(void) { + gpr_log(GPR_DEBUG, "test_execute_one"); + + grpc_aelock lock; + grpc_aelock_init(&lock, NULL); + bool done = false; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_aelock_execute(&exec_ctx, &lock, set_bool_to_true, &done, 0); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(done); + grpc_aelock_destroy(&lock); +} + +typedef struct { + size_t *ctr; + size_t value; +} ex_args; + +static void check_one(grpc_exec_ctx *exec_ctx, void *a) { + ex_args *args = a; + GPR_ASSERT(*args->ctr == args->value - 1); + *args->ctr = args->value; +} + +static void execute_many_loop(void *lock) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + for (size_t i = 0; i < 100; i++) { + size_t ctr = 0; + for (size_t j = 1; j <= 1000; j++) { + ex_args args = {&ctr, j}; + grpc_aelock_execute(&exec_ctx, lock, check_one, &args, sizeof(args)); + grpc_exec_ctx_flush(&exec_ctx); + } + gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(1)); + } +} + +static void test_execute_many(void) { + grpc_aelock lock; + gpr_thd_id thds[100]; + grpc_aelock_init(&lock, NULL); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &lock, &options)); + } + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + grpc_aelock_destroy(&lock); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_init(); + test_no_op(); + test_execute_one(); + test_execute_many(); + grpc_shutdown(); + + return 0; +} diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 1b1453f7ea..5caaa5a867 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -802,6 +802,7 @@ src/core/lib/debug/trace.h \ src/core/lib/http/format_request.h \ src/core/lib/http/httpcli.h \ src/core/lib/http/parser.h \ +src/core/lib/iomgr/async_execution_lock.h \ src/core/lib/iomgr/closure.h \ src/core/lib/iomgr/endpoint.h \ src/core/lib/iomgr/endpoint_pair.h \ @@ -938,6 +939,7 @@ src/core/lib/debug/trace.c \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ +src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index f546f3b995..74c8cce127 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -79,6 +79,22 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "language": "c", + "name": "async_execution_lock_test", + "src": [ + "test/core/iomgr/async_execution_lock_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "grpc", @@ -5606,6 +5622,7 @@ "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", + "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", @@ -5701,6 +5718,8 @@ "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.c", "src/core/lib/http/parser.h", + "src/core/lib/iomgr/async_execution_lock.c", + "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.c", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/endpoint.c", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 0fd77854d2..a07082d996 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -85,6 +85,27 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "async_execution_lock_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index bdae447545..9c44e0a217 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -160,6 +160,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alpn_test", "vcxproj\test\a {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "async_execution_lock_test", "vcxproj\test\async_execution_lock_test\async_execution_lock_test.vcxproj", "{5FC080AE-1FE8-2849-6481-E52ADBBC205C}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin_encoder_test", "vcxproj\test\bin_encoder_test\bin_encoder_test.vcxproj", "{D5C70922-D68E-0E9D-9988-995E0F9A79AE}" ProjectSection(myProperties) = preProject lib = "False" @@ -1663,6 +1674,22 @@ Global {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|Win32.Build.0 = Release|Win32 {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|x64.ActiveCfg = Release|x64 {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|x64.Build.0 = Release|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|Win32.ActiveCfg = Debug|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|x64.ActiveCfg = Debug|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|Win32.ActiveCfg = Release|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|x64.ActiveCfg = Release|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|Win32.Build.0 = Debug|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|x64.Build.0 = Debug|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|Win32.Build.0 = Release|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|x64.Build.0 = Release|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|x64.Build.0 = Debug|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|Win32.Build.0 = Release|Win32 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|x64.ActiveCfg = Release|x64 + {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|x64.Build.0 = Release|x64 {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Debug|Win32.ActiveCfg = Debug|Win32 {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Debug|x64.ActiveCfg = Debug|x64 {D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 4eec05a3b1..b977a7fc5f 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -311,6 +311,7 @@ + @@ -463,6 +464,8 @@ + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 17c88c4805..c1f2bd9a16 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -43,6 +43,9 @@ src\core\lib\http + + src\core\lib\iomgr + src\core\lib\iomgr @@ -626,6 +629,9 @@ src\core\lib\http + + src\core\lib\iomgr + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 26050dcf74..93a2327841 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -300,6 +300,7 @@ + @@ -440,6 +441,8 @@ + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index a4acf513bc..f18700ca58 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -46,6 +46,9 @@ src\core\lib\http + + src\core\lib\iomgr + src\core\lib\iomgr @@ -560,6 +563,9 @@ src\core\lib\http + + src\core\lib\iomgr + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj new file mode 100644 index 0000000000..92b277801e --- /dev/null +++ b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5FC080AE-1FE8-2849-6481-E52ADBBC205C} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + async_execution_lock_test + static + Debug + static + Debug + + + async_execution_lock_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters new file mode 100644 index 0000000000..ff116cb9b0 --- /dev/null +++ b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\iomgr + + + + + + {1553c040-57a4-1c71-539f-06be026b4844} + + + {112c4757-8861-21ed-d535-83c90a22e14b} + + + {341d4313-1479-2a6a-8ba4-a44c4c15e0d7} + + + + -- cgit v1.2.3 From 2743ba94f978aacb0db4bf900bd048479a8806ac Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 16:44:20 -0700 Subject: Almost working... --- src/core/lib/iomgr/async_execution_lock.c | 64 ++++++++++++++++++++--------- src/core/lib/iomgr/async_execution_lock.h | 2 +- test/core/iomgr/async_execution_lock_test.c | 29 +++++++++---- 3 files changed, 67 insertions(+), 28 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 62ece4cc8c..71608b2bfe 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -40,11 +40,16 @@ #define NO_CONSUMER ((gpr_atm)1) +static void bad_action(grpc_exec_ctx *exec_ctx, void *arg) { + GPR_UNREACHABLE_CODE(return ); +} + void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue) { lock->optional_workqueue = optional_workqueue; gpr_atm_no_barrier_store(&lock->head, NO_CONSUMER); - lock->tail = &lock->stub; - gpr_atm_no_barrier_store(&lock->stub.next, 0); + gpr_atm_no_barrier_store(&lock->tombstone.next, 0); + lock->tombstone.action = bad_action; + lock->tail = &lock->tombstone; } void grpc_aelock_destroy(grpc_aelock *lock) { @@ -56,15 +61,35 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { grpc_aelock_qnode *tail = lock->tail; grpc_aelock_qnode *next = (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); - if (next == NULL) { - if (gpr_atm_rel_cas(&lock->head, (gpr_atm)&lock->stub, NO_CONSUMER)) { - return; + if (tail == &lock->tombstone) { + if (next == NULL) { + if (gpr_atm_rel_cas(&lock->head, (gpr_atm)&lock->tombstone, + NO_CONSUMER)) { + return; + } + } else { + lock->tail = next; + tail = next; + next = (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); } - } else { + } + if (next != NULL) { lock->tail = next; - - next->action(exec_ctx, next->arg); - gpr_free(next); + tail->action(exec_ctx, tail->arg); + gpr_free(tail); + } else { + grpc_aelock_qnode *head = + (grpc_aelock_qnode *)gpr_atm_acq_load(&lock->head); + if (head != tail) { + // TODO(ctiller): consider sleeping? + continue; + } + gpr_atm_no_barrier_store(&lock->tombstone.next, 0); + while (!gpr_atm_rel_cas(&lock->head, (gpr_atm)head, + (gpr_atm)&lock->tombstone)) { + head = (grpc_aelock_qnode *)gpr_atm_acq_load(&lock->head); + } + gpr_atm_rel_store(&head->next, (gpr_atm)&lock->tombstone); } } } @@ -72,11 +97,11 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { - gpr_atm cur; + gpr_atm head; retry_top: - cur = gpr_atm_acq_load(&lock->head); - if (cur == NO_CONSUMER) { - if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->stub)) { + head = gpr_atm_acq_load(&lock->head); + if (head == NO_CONSUMER) { + if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->tombstone)) { goto retry_top; } action(exec_ctx, arg); @@ -86,18 +111,19 @@ retry_top: grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); n->action = action; - gpr_atm_no_barrier_store(&n->next, 0); if (sizeof_arg > 0) { memcpy(n + 1, arg, sizeof_arg); n->arg = n + 1; } else { n->arg = arg; } - while (!gpr_atm_rel_cas(&lock->head, cur, (gpr_atm)n)) { + gpr_atm_no_barrier_store(&n->next, 0); + while (!gpr_atm_rel_cas(&lock->head, head, (gpr_atm)n)) { retry_queue_load: - cur = gpr_atm_acq_load(&lock->head); - if (cur == NO_CONSUMER) { - if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->stub)) { + head = gpr_atm_acq_load(&lock->head); + if (head == NO_CONSUMER) { + if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, + (gpr_atm)&lock->tombstone)) { goto retry_queue_load; } gpr_free(n); @@ -106,5 +132,5 @@ retry_top: return; // early out } } - gpr_atm_no_barrier_store(&((grpc_aelock_qnode *)cur)->next, (gpr_atm)n); + gpr_atm_rel_store(&((grpc_aelock_qnode *)head)->next, (gpr_atm)n); } diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index cb4de61349..cd1c4811fe 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -52,7 +52,7 @@ typedef struct grpc_aelock { // grpc_aelock_qnode* gpr_atm head; grpc_aelock_qnode *tail; - grpc_aelock_qnode stub; + grpc_aelock_qnode tombstone; } grpc_aelock; void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c index 405f89362c..d7f1823412 100644 --- a/test/core/iomgr/async_execution_lock_test.c +++ b/test/core/iomgr/async_execution_lock_test.c @@ -65,6 +65,11 @@ static void test_execute_one(void) { grpc_aelock_destroy(&lock); } +typedef struct { + size_t ctr; + grpc_aelock *lock; +} thd_args; + typedef struct { size_t *ctr; size_t value; @@ -72,31 +77,39 @@ typedef struct { static void check_one(grpc_exec_ctx *exec_ctx, void *a) { ex_args *args = a; + // gpr_log(GPR_DEBUG, "*%p=%d; step %d", args->ctr, *args->ctr, args->value); GPR_ASSERT(*args->ctr == args->value - 1); *args->ctr = args->value; } -static void execute_many_loop(void *lock) { +static void execute_many_loop(void *a) { + thd_args *args = a; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - for (size_t i = 0; i < 100; i++) { - size_t ctr = 0; - for (size_t j = 1; j <= 1000; j++) { - ex_args args = {&ctr, j}; - grpc_aelock_execute(&exec_ctx, lock, check_one, &args, sizeof(args)); + size_t n = 1; + for (size_t i = 0; i < 10; i++) { + for (size_t j = 0; j < 1000; j++) { + ex_args c = {&args->ctr, n++}; + grpc_aelock_execute(&exec_ctx, args->lock, check_one, &c, sizeof(c)); grpc_exec_ctx_flush(&exec_ctx); } - gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(1)); + gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); } + grpc_exec_ctx_finish(&exec_ctx); } static void test_execute_many(void) { + gpr_log(GPR_DEBUG, "test_execute_many"); + grpc_aelock lock; gpr_thd_id thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; grpc_aelock_init(&lock, NULL); for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_options options = gpr_thd_options_default(); gpr_thd_options_set_joinable(&options); - GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &lock, &options)); + ta[i].ctr = 0; + ta[i].lock = &lock; + GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options)); } for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_join(thds[i]); -- cgit v1.2.3 From dfbb1c080aa22e1f39cd934e1dc731ee4c74100b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 20:48:46 -0700 Subject: Almost working...... --- src/core/lib/iomgr/async_execution_lock.c | 12 ++++++++++-- test/core/iomgr/async_execution_lock_test.c | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 71608b2bfe..00cd27504b 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -67,23 +67,30 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { NO_CONSUMER)) { return; } + // TODO(ctiller): consider sleeping + continue; } else { + // skip the tombstone: we'll re-add it later lock->tail = next; tail = next; next = (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); } } if (next != NULL) { + // found a node lock->tail = next; tail->action(exec_ctx, tail->arg); gpr_free(tail); } else { + // nothing there: might be in an incosistant state grpc_aelock_qnode *head = (grpc_aelock_qnode *)gpr_atm_acq_load(&lock->head); if (head != tail) { + // non-empty list: spin for a bit // TODO(ctiller): consider sleeping? continue; } + // must have swallowed tombstone above: re-add it gpr_atm_no_barrier_store(&lock->tombstone.next, 0); while (!gpr_atm_rel_cas(&lock->head, (gpr_atm)head, (gpr_atm)&lock->tombstone)) { @@ -117,7 +124,7 @@ retry_top: } else { n->arg = arg; } - gpr_atm_no_barrier_store(&n->next, 0); + gpr_atm_rel_store(&n->next, 0); while (!gpr_atm_rel_cas(&lock->head, head, (gpr_atm)n)) { retry_queue_load: head = gpr_atm_acq_load(&lock->head); @@ -132,5 +139,6 @@ retry_top: return; // early out } } - gpr_atm_rel_store(&((grpc_aelock_qnode *)head)->next, (gpr_atm)n); + GPR_ASSERT(gpr_atm_rel_cas(&((grpc_aelock_qnode *)head)->next, 0, (gpr_atm)n)); +// gpr_atm_rel_store(&((grpc_aelock_qnode *)head)->next, (gpr_atm)n); } diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c index d7f1823412..8c9665a458 100644 --- a/test/core/iomgr/async_execution_lock_test.c +++ b/test/core/iomgr/async_execution_lock_test.c @@ -87,7 +87,7 @@ static void execute_many_loop(void *a) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; size_t n = 1; for (size_t i = 0; i < 10; i++) { - for (size_t j = 0; j < 1000; j++) { + for (size_t j = 0; j < 10000; j++) { ex_args c = {&args->ctr, n++}; grpc_aelock_execute(&exec_ctx, args->lock, check_one, &c, sizeof(c)); grpc_exec_ctx_flush(&exec_ctx); -- cgit v1.2.3 From 0bc11711b7f2f33bd4e399bda46e4c20ac4bc6ca Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 21:22:46 -0700 Subject: Direct translation of http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue --- BUILD | 6 ++- Makefile | 2 +- binding.gyp | 2 +- build.yaml | 3 +- config.m4 | 2 +- gRPC.podspec | 4 +- grpc.gemspec | 3 +- include/grpc/impl/codegen/atm.h | 3 ++ include/grpc/impl/codegen/atm_gcc_atomic.h | 2 + include/grpc/impl/codegen/atm_gcc_sync.h | 7 +++ include/grpc/impl/codegen/atm_win32.h | 4 ++ package.xml | 3 +- src/core/lib/support/mpscq.c | 80 +++++++++++++++++++++++++++++ src/core/lib/support/mpscq.h | 55 ++++++++++++++++++++ src/python/grpcio/grpc_core_dependencies.py | 2 +- tools/doxygen/Doxyfile.core.internal | 3 +- tools/run_tests/sources_and_headers.json | 4 +- vsprojects/vcxproj/gpr/gpr.vcxproj | 5 +- vsprojects/vcxproj/gpr/gpr.vcxproj.filters | 9 ++-- 19 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 src/core/lib/support/mpscq.c create mode 100644 src/core/lib/support/mpscq.h (limited to 'src/core/lib') diff --git a/BUILD b/BUILD index ca152583a7..bd00ff670f 100644 --- a/BUILD +++ b/BUILD @@ -50,6 +50,7 @@ cc_library( "src/core/lib/support/block_annotate.h", "src/core/lib/support/env.h", "src/core/lib/support/load_file.h", + "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.h", @@ -78,10 +79,10 @@ cc_library( "src/core/lib/support/log_linux.c", "src/core/lib/support/log_posix.c", "src/core/lib/support/log_win32.c", + "src/core/lib/support/mpscq.c", "src/core/lib/support/murmur_hash.c", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", - "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/string.c", "src/core/lib/support/string_posix.c", "src/core/lib/support/string_util_win32.c", @@ -1219,10 +1220,10 @@ objc_library( "src/core/lib/support/log_linux.c", "src/core/lib/support/log_posix.c", "src/core/lib/support/log_win32.c", + "src/core/lib/support/mpscq.c", "src/core/lib/support/murmur_hash.c", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", - "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/string.c", "src/core/lib/support/string_posix.c", "src/core/lib/support/string_util_win32.c", @@ -1293,6 +1294,7 @@ objc_library( "src/core/lib/support/block_annotate.h", "src/core/lib/support/env.h", "src/core/lib/support/load_file.h", + "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.h", diff --git a/Makefile b/Makefile index 52c27c97d6..50efcf349f 100644 --- a/Makefile +++ b/Makefile @@ -2348,10 +2348,10 @@ LIBGPR_SRC = \ src/core/lib/support/log_linux.c \ src/core/lib/support/log_posix.c \ src/core/lib/support/log_win32.c \ + src/core/lib/support/mpscq.c \ src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ - src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/binding.gyp b/binding.gyp index fbec804f7a..ccd811a30b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -516,10 +516,10 @@ 'src/core/lib/support/log_linux.c', 'src/core/lib/support/log_posix.c', 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/mpscq.c', 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', - 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', diff --git a/build.yaml b/build.yaml index aae3e5a242..e6f263aef7 100644 --- a/build.yaml +++ b/build.yaml @@ -68,6 +68,7 @@ filegroups: - src/core/lib/support/block_annotate.h - src/core/lib/support/env.h - src/core/lib/support/load_file.h + - src/core/lib/support/mpscq.h - src/core/lib/support/murmur_hash.h - src/core/lib/support/stack_lockfree.h - src/core/lib/support/string.h @@ -97,10 +98,10 @@ filegroups: - src/core/lib/support/log_linux.c - src/core/lib/support/log_posix.c - src/core/lib/support/log_win32.c + - src/core/lib/support/mpscq.c - src/core/lib/support/murmur_hash.c - src/core/lib/support/slice.c - src/core/lib/support/slice_buffer.c - - src/core/lib/support/stack_lockfree.c - src/core/lib/support/string.c - src/core/lib/support/string_posix.c - src/core/lib/support/string_util_win32.c diff --git a/config.m4 b/config.m4 index 30573cf920..9ec7f493da 100644 --- a/config.m4 +++ b/config.m4 @@ -57,10 +57,10 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/support/log_linux.c \ src/core/lib/support/log_posix.c \ src/core/lib/support/log_win32.c \ + src/core/lib/support/mpscq.c \ src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ - src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/gRPC.podspec b/gRPC.podspec index a8744c8c70..3df13f9f42 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -68,6 +68,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/block_annotate.h', 'src/core/lib/support/env.h', 'src/core/lib/support/load_file.h', + 'src/core/lib/support/mpscq.h', 'src/core/lib/support/murmur_hash.h', 'src/core/lib/support/stack_lockfree.h', 'src/core/lib/support/string.h', @@ -138,10 +139,10 @@ Pod::Spec.new do |s| 'src/core/lib/support/log_linux.c', 'src/core/lib/support/log_posix.c', 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/mpscq.c', 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', - 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', @@ -500,6 +501,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/block_annotate.h', 'src/core/lib/support/env.h', 'src/core/lib/support/load_file.h', + 'src/core/lib/support/mpscq.h', 'src/core/lib/support/murmur_hash.h', 'src/core/lib/support/stack_lockfree.h', 'src/core/lib/support/string.h', diff --git a/grpc.gemspec b/grpc.gemspec index fca828ad10..2aad578a26 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -90,6 +90,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/support/block_annotate.h ) s.files += %w( src/core/lib/support/env.h ) s.files += %w( src/core/lib/support/load_file.h ) + s.files += %w( src/core/lib/support/mpscq.h ) s.files += %w( src/core/lib/support/murmur_hash.h ) s.files += %w( src/core/lib/support/stack_lockfree.h ) s.files += %w( src/core/lib/support/string.h ) @@ -118,10 +119,10 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/support/log_linux.c ) s.files += %w( src/core/lib/support/log_posix.c ) s.files += %w( src/core/lib/support/log_win32.c ) + s.files += %w( src/core/lib/support/mpscq.c ) s.files += %w( src/core/lib/support/murmur_hash.c ) s.files += %w( src/core/lib/support/slice.c ) s.files += %w( src/core/lib/support/slice_buffer.c ) - s.files += %w( src/core/lib/support/stack_lockfree.c ) s.files += %w( src/core/lib/support/string.c ) s.files += %w( src/core/lib/support/string_posix.c ) s.files += %w( src/core/lib/support/string_util_win32.c ) diff --git a/include/grpc/impl/codegen/atm.h b/include/grpc/impl/codegen/atm.h index 5376026dde..6f7618b800 100644 --- a/include/grpc/impl/codegen/atm.h +++ b/include/grpc/impl/codegen/atm.h @@ -75,6 +75,9 @@ int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n); int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n); + + // Atomically, set *p=n and return the old value of *p + gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n); */ #include diff --git a/include/grpc/impl/codegen/atm_gcc_atomic.h b/include/grpc/impl/codegen/atm_gcc_atomic.h index 8caf7edbde..7d4ae98cf7 100644 --- a/include/grpc/impl/codegen/atm_gcc_atomic.h +++ b/include/grpc/impl/codegen/atm_gcc_atomic.h @@ -69,4 +69,6 @@ static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { __ATOMIC_RELAXED); } +#define gpr_atm_full_xchg(p, n) __atomic_exchange_n((p), (n), __ATOMIC_ACQ_REL) + #endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */ diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h index 915b09fb0c..86ce2f2548 100644 --- a/include/grpc/impl/codegen/atm_gcc_sync.h +++ b/include/grpc/impl/codegen/atm_gcc_sync.h @@ -84,4 +84,11 @@ static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) { #define gpr_atm_acq_cas(p, o, n) (__sync_bool_compare_and_swap((p), (o), (n))) #define gpr_atm_rel_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n)) +static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) { + gpr_atm cur; + do { + cur = gpr_atm_acq_load(p); + } while (!gpr_atm_rel_cas(p, cur, n)); +} + #endif /* GRPC_IMPL_CODEGEN_ATM_GCC_SYNC_H */ diff --git a/include/grpc/impl/codegen/atm_win32.h b/include/grpc/impl/codegen/atm_win32.h index 7c1ccaf8e2..2904007d63 100644 --- a/include/grpc/impl/codegen/atm_win32.h +++ b/include/grpc/impl/codegen/atm_win32.h @@ -122,4 +122,8 @@ static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) { return old; } +static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) { + return (gpr_atm)InterlockedExchangePointer((PVOID*)p, (PVOID)n); +} + #endif /* GRPC_IMPL_CODEGEN_ATM_WIN32_H */ diff --git a/package.xml b/package.xml index d259dd043f..ee2468bc87 100644 --- a/package.xml +++ b/package.xml @@ -97,6 +97,7 @@ + @@ -125,10 +126,10 @@ + - diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c new file mode 100644 index 0000000000..911fdd161c --- /dev/null +++ b/src/core/lib/support/mpscq.c @@ -0,0 +1,80 @@ +/* + * + * Copyright 2016, 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/lib/support/mpscq.h" + +#include + +void gpr_mpscq_init(gpr_mpscq *q) { + gpr_atm_no_barrier_store(&q->head, (gpr_atm)&q->stub); + q->tail = &q->stub; + gpr_atm_no_barrier_store(&q->stub.next, 0); +} + +void gpr_mpscq_destroy(gpr_mpscq *q) { + GPR_ASSERT(gpr_atm_no_barrier_load(&q->head) == (gpr_atm)&q->stub); + GPR_ASSERT(q->tail == &q->stub); +} + +void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) { + gpr_atm_no_barrier_store(&n->next, 0); + gpr_mpscq_node *prev = (gpr_mpscq_node*)gpr_atm_full_xchg(&q->head, (gpr_atm)n); + gpr_atm_rel_store(&prev->next, (gpr_atm)n); +} + +gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { + gpr_mpscq_node *tail = q->tail; + gpr_mpscq_node *next = (gpr_mpscq_node*)gpr_atm_acq_load(&tail->next); + if (tail == &q->stub) { + if (next == NULL) return NULL; + q->tail = next; + tail = next; + next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); + } + if (next != NULL) { + q->tail = next; + return tail; + } + gpr_mpscq_node *head = (gpr_mpscq_node*)gpr_atm_acq_load(&q->head); + if (tail != head) { + return 0; + } + gpr_mpscq_push(q, &q->stub); + next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); + if (next != NULL) { + q->tail = next; + return tail; + } + return NULL; +} + diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h new file mode 100644 index 0000000000..30b37a94a1 --- /dev/null +++ b/src/core/lib/support/mpscq.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2016, 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_CORE_LIB_SUPPORT_MPSCQ_H +#define GRPC_CORE_LIB_SUPPORT_MPSCQ_H + +#include +#include + +typedef struct gpr_mpscq_node { + gpr_atm next; +} gpr_mpscq_node; + +typedef struct gpr_mpscq { + gpr_atm head; + gpr_mpscq_node *tail; + gpr_mpscq_node stub; +} gpr_mpscq; + +void gpr_mpscq_init(gpr_mpscq *q); +void gpr_mpscq_destroy(gpr_mpscq *q); +void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n); +gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q); + +#endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 88db62abb4..58425a7a29 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -51,10 +51,10 @@ CORE_SOURCE_FILES = [ 'src/core/lib/support/log_linux.c', 'src/core/lib/support/log_posix.c', 'src/core/lib/support/log_win32.c', + 'src/core/lib/support/mpscq.c', 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', - 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 5caaa5a867..534775e6cd 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1138,6 +1138,7 @@ src/core/lib/support/backoff.h \ src/core/lib/support/block_annotate.h \ src/core/lib/support/env.h \ src/core/lib/support/load_file.h \ +src/core/lib/support/mpscq.h \ src/core/lib/support/murmur_hash.h \ src/core/lib/support/stack_lockfree.h \ src/core/lib/support/string.h \ @@ -1166,10 +1167,10 @@ src/core/lib/support/log_android.c \ src/core/lib/support/log_linux.c \ src/core/lib/support/log_posix.c \ src/core/lib/support/log_win32.c \ +src/core/lib/support/mpscq.c \ src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ -src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 74c8cce127..2b042b7e08 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -5457,6 +5457,7 @@ "src/core/lib/support/block_annotate.h", "src/core/lib/support/env.h", "src/core/lib/support/load_file.h", + "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.h", @@ -5522,11 +5523,12 @@ "src/core/lib/support/log_linux.c", "src/core/lib/support/log_posix.c", "src/core/lib/support/log_win32.c", + "src/core/lib/support/mpscq.c", + "src/core/lib/support/mpscq.h", "src/core/lib/support/murmur_hash.c", "src/core/lib/support/murmur_hash.h", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", - "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.c", "src/core/lib/support/string.h", diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj index 26195bb541..43fa41324d 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj @@ -196,6 +196,7 @@ + @@ -247,14 +248,14 @@ + + - - diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters index be15391b09..80c6ac7b55 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters @@ -64,6 +64,9 @@ src\core\lib\support + + src\core\lib\support + src\core\lib\support @@ -73,9 +76,6 @@ src\core\lib\support - - src\core\lib\support - src\core\lib\support @@ -284,6 +284,9 @@ src\core\lib\support + + src\core\lib\support + src\core\lib\support -- cgit v1.2.3 From ad3c8c1a5d56fac6b91d8f4fec50145d91721b63 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 21:47:30 -0700 Subject: Rewrite async_exec_lock using mpscq --- BUILD | 2 + Makefile | 1 + binding.gyp | 1 + build.yaml | 1 + config.m4 | 1 + gRPC.podspec | 1 + grpc.gemspec | 1 + package.xml | 1 + src/core/lib/iomgr/async_execution_lock.c | 103 ++++++---------------------- src/core/lib/iomgr/async_execution_lock.h | 11 ++- src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.core.internal | 1 + tools/run_tests/sources_and_headers.json | 1 + vsprojects/vcxproj/gpr/gpr.vcxproj | 2 + vsprojects/vcxproj/gpr/gpr.vcxproj.filters | 3 + 15 files changed, 43 insertions(+), 88 deletions(-) (limited to 'src/core/lib') diff --git a/BUILD b/BUILD index bd00ff670f..5dc0d86abe 100644 --- a/BUILD +++ b/BUILD @@ -83,6 +83,7 @@ cc_library( "src/core/lib/support/murmur_hash.c", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/string.c", "src/core/lib/support/string_posix.c", "src/core/lib/support/string_util_win32.c", @@ -1224,6 +1225,7 @@ objc_library( "src/core/lib/support/murmur_hash.c", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/string.c", "src/core/lib/support/string_posix.c", "src/core/lib/support/string_util_win32.c", diff --git a/Makefile b/Makefile index 50efcf349f..319f483e75 100644 --- a/Makefile +++ b/Makefile @@ -2352,6 +2352,7 @@ LIBGPR_SRC = \ src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ + src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/binding.gyp b/binding.gyp index ccd811a30b..9d04eb971a 100644 --- a/binding.gyp +++ b/binding.gyp @@ -520,6 +520,7 @@ 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', diff --git a/build.yaml b/build.yaml index e6f263aef7..addb91fcce 100644 --- a/build.yaml +++ b/build.yaml @@ -102,6 +102,7 @@ filegroups: - src/core/lib/support/murmur_hash.c - src/core/lib/support/slice.c - src/core/lib/support/slice_buffer.c + - src/core/lib/support/stack_lockfree.c - src/core/lib/support/string.c - src/core/lib/support/string_posix.c - src/core/lib/support/string_util_win32.c diff --git a/config.m4 b/config.m4 index 9ec7f493da..67ce4944ef 100644 --- a/config.m4 +++ b/config.m4 @@ -61,6 +61,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ + src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/gRPC.podspec b/gRPC.podspec index 3df13f9f42..f995e8ad65 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -143,6 +143,7 @@ Pod::Spec.new do |s| 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', diff --git a/grpc.gemspec b/grpc.gemspec index 2aad578a26..de488d6f44 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -123,6 +123,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/support/murmur_hash.c ) s.files += %w( src/core/lib/support/slice.c ) s.files += %w( src/core/lib/support/slice_buffer.c ) + s.files += %w( src/core/lib/support/stack_lockfree.c ) s.files += %w( src/core/lib/support/string.c ) s.files += %w( src/core/lib/support/string_posix.c ) s.files += %w( src/core/lib/support/string_util_win32.c ) diff --git a/package.xml b/package.xml index ee2468bc87..169d047a08 100644 --- a/package.xml +++ b/package.xml @@ -130,6 +130,7 @@ + diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 00cd27504b..b6b7e0d92c 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,105 +40,44 @@ #define NO_CONSUMER ((gpr_atm)1) -static void bad_action(grpc_exec_ctx *exec_ctx, void *arg) { - GPR_UNREACHABLE_CODE(return ); -} - void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue) { lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->head, NO_CONSUMER); - gpr_atm_no_barrier_store(&lock->tombstone.next, 0); - lock->tombstone.action = bad_action; - lock->tail = &lock->tombstone; + gpr_atm_no_barrier_store(&lock->locked, 0); + gpr_mpscq_init(&lock->queue); } void grpc_aelock_destroy(grpc_aelock *lock) { - GPR_ASSERT(gpr_atm_no_barrier_load(&lock->head) == NO_CONSUMER); + GPR_ASSERT(gpr_atm_no_barrier_load(&lock->locked) == 0); + gpr_mpscq_destroy(&lock->queue); } static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - for (;;) { - grpc_aelock_qnode *tail = lock->tail; - grpc_aelock_qnode *next = - (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); - if (tail == &lock->tombstone) { - if (next == NULL) { - if (gpr_atm_rel_cas(&lock->head, (gpr_atm)&lock->tombstone, - NO_CONSUMER)) { - return; - } - // TODO(ctiller): consider sleeping - continue; - } else { - // skip the tombstone: we'll re-add it later - lock->tail = next; - tail = next; - next = (grpc_aelock_qnode *)gpr_atm_acq_load(&tail->next); - } - } - if (next != NULL) { - // found a node - lock->tail = next; - tail->action(exec_ctx, tail->arg); - gpr_free(tail); - } else { - // nothing there: might be in an incosistant state - grpc_aelock_qnode *head = - (grpc_aelock_qnode *)gpr_atm_acq_load(&lock->head); - if (head != tail) { - // non-empty list: spin for a bit - // TODO(ctiller): consider sleeping? - continue; - } - // must have swallowed tombstone above: re-add it - gpr_atm_no_barrier_store(&lock->tombstone.next, 0); - while (!gpr_atm_rel_cas(&lock->head, (gpr_atm)head, - (gpr_atm)&lock->tombstone)) { - head = (grpc_aelock_qnode *)gpr_atm_acq_load(&lock->head); - } - gpr_atm_rel_store(&head->next, (gpr_atm)&lock->tombstone); + while (gpr_atm_full_fetch_add(&lock->locked, -1) != 1) { + gpr_mpscq_node *n; + while ((n = gpr_mpscq_pop(&lock->queue)) == NULL) { + // TODO(ctiller): find something to fill in the time } + grpc_aelock_qnode *ln = (grpc_aelock_qnode*)n; + ln->action(exec_ctx, ln->arg); + gpr_free(ln); } } void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { - gpr_atm head; -retry_top: - head = gpr_atm_acq_load(&lock->head); - if (head == NO_CONSUMER) { - if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, (gpr_atm)&lock->tombstone)) { - goto retry_top; - } + if (gpr_atm_full_fetch_add(&lock->locked, 1) == 0) { action(exec_ctx, arg); finish(exec_ctx, lock); - return; // early out - } - - grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); - n->action = action; - if (sizeof_arg > 0) { - memcpy(n + 1, arg, sizeof_arg); - n->arg = n + 1; } else { - n->arg = arg; - } - gpr_atm_rel_store(&n->next, 0); - while (!gpr_atm_rel_cas(&lock->head, head, (gpr_atm)n)) { - retry_queue_load: - head = gpr_atm_acq_load(&lock->head); - if (head == NO_CONSUMER) { - if (!gpr_atm_rel_cas(&lock->head, NO_CONSUMER, - (gpr_atm)&lock->tombstone)) { - goto retry_queue_load; - } - gpr_free(n); - action(exec_ctx, arg); - finish(exec_ctx, lock); - return; // early out + grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); + n->action = action; + if (sizeof_arg > 0) { + memcpy(n + 1, arg, sizeof_arg); + n->arg = n + 1; + } else { + n->arg = arg; } + gpr_mpscq_push(&lock->queue, &n->mpscq_node); } - GPR_ASSERT(gpr_atm_rel_cas(&((grpc_aelock_qnode *)head)->next, 0, (gpr_atm)n)); -// gpr_atm_rel_store(&((grpc_aelock_qnode *)head)->next, (gpr_atm)n); } diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index cd1c4811fe..20cbcaf2e1 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,22 +37,21 @@ #include #include +#include "src/core/lib/support/mpscq.h" #include "src/core/lib/iomgr/exec_ctx.h" typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); typedef struct grpc_aelock_qnode { + gpr_mpscq_node mpscq_node; grpc_aelock_action action; void *arg; - gpr_atm next; } grpc_aelock_qnode; typedef struct grpc_aelock { grpc_workqueue *optional_workqueue; - // grpc_aelock_qnode* - gpr_atm head; - grpc_aelock_qnode *tail; - grpc_aelock_qnode tombstone; + gpr_mpscq queue; + gpr_atm locked; } grpc_aelock; void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 58425a7a29..c843ed4062 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -55,6 +55,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/support/murmur_hash.c', 'src/core/lib/support/slice.c', 'src/core/lib/support/slice_buffer.c', + 'src/core/lib/support/stack_lockfree.c', 'src/core/lib/support/string.c', 'src/core/lib/support/string_posix.c', 'src/core/lib/support/string_util_win32.c', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 534775e6cd..4add517477 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1171,6 +1171,7 @@ src/core/lib/support/mpscq.c \ src/core/lib/support/murmur_hash.c \ src/core/lib/support/slice.c \ src/core/lib/support/slice_buffer.c \ +src/core/lib/support/stack_lockfree.c \ src/core/lib/support/string.c \ src/core/lib/support/string_posix.c \ src/core/lib/support/string_util_win32.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 2b042b7e08..4369771170 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -5529,6 +5529,7 @@ "src/core/lib/support/murmur_hash.h", "src/core/lib/support/slice.c", "src/core/lib/support/slice_buffer.c", + "src/core/lib/support/stack_lockfree.c", "src/core/lib/support/stack_lockfree.h", "src/core/lib/support/string.c", "src/core/lib/support/string.h", diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj index 43fa41324d..1a67cb9f61 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj @@ -256,6 +256,8 @@ + + diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters index 80c6ac7b55..c2d6b51c5b 100644 --- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters +++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters @@ -76,6 +76,9 @@ src\core\lib\support + + src\core\lib\support + src\core\lib\support -- cgit v1.2.3 From e49429587bbf01ff741a218c86a11fe2b59a0b5c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 21:50:44 -0700 Subject: clang-format --- include/grpc/impl/codegen/atm_win32.h | 2 +- src/core/lib/iomgr/async_execution_lock.c | 2 +- src/core/lib/iomgr/async_execution_lock.h | 2 +- src/core/lib/support/mpscq.c | 8 ++++---- src/core/lib/support/mpscq.h | 6 ++---- 5 files changed, 9 insertions(+), 11 deletions(-) (limited to 'src/core/lib') diff --git a/include/grpc/impl/codegen/atm_win32.h b/include/grpc/impl/codegen/atm_win32.h index 2904007d63..f931f4509f 100644 --- a/include/grpc/impl/codegen/atm_win32.h +++ b/include/grpc/impl/codegen/atm_win32.h @@ -123,7 +123,7 @@ static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) { } static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) { - return (gpr_atm)InterlockedExchangePointer((PVOID*)p, (PVOID)n); + return (gpr_atm)InterlockedExchangePointer((PVOID *)p, (PVOID)n); } #endif /* GRPC_IMPL_CODEGEN_ATM_WIN32_H */ diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index b6b7e0d92c..595290f78c 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -57,7 +57,7 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { while ((n = gpr_mpscq_pop(&lock->queue)) == NULL) { // TODO(ctiller): find something to fill in the time } - grpc_aelock_qnode *ln = (grpc_aelock_qnode*)n; + grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; ln->action(exec_ctx, ln->arg); gpr_free(ln); } diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index 20cbcaf2e1..66551f9398 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -37,8 +37,8 @@ #include #include -#include "src/core/lib/support/mpscq.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/support/mpscq.h" typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c index 911fdd161c..25b055b172 100644 --- a/src/core/lib/support/mpscq.c +++ b/src/core/lib/support/mpscq.c @@ -48,13 +48,14 @@ void gpr_mpscq_destroy(gpr_mpscq *q) { void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) { gpr_atm_no_barrier_store(&n->next, 0); - gpr_mpscq_node *prev = (gpr_mpscq_node*)gpr_atm_full_xchg(&q->head, (gpr_atm)n); + gpr_mpscq_node *prev = + (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n); gpr_atm_rel_store(&prev->next, (gpr_atm)n); } gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { gpr_mpscq_node *tail = q->tail; - gpr_mpscq_node *next = (gpr_mpscq_node*)gpr_atm_acq_load(&tail->next); + gpr_mpscq_node *next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); if (tail == &q->stub) { if (next == NULL) return NULL; q->tail = next; @@ -65,7 +66,7 @@ gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { q->tail = next; return tail; } - gpr_mpscq_node *head = (gpr_mpscq_node*)gpr_atm_acq_load(&q->head); + gpr_mpscq_node *head = (gpr_mpscq_node *)gpr_atm_acq_load(&q->head); if (tail != head) { return 0; } @@ -77,4 +78,3 @@ gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { } return NULL; } - diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h index 30b37a94a1..e7f4773258 100644 --- a/src/core/lib/support/mpscq.h +++ b/src/core/lib/support/mpscq.h @@ -34,12 +34,10 @@ #ifndef GRPC_CORE_LIB_SUPPORT_MPSCQ_H #define GRPC_CORE_LIB_SUPPORT_MPSCQ_H -#include #include +#include -typedef struct gpr_mpscq_node { - gpr_atm next; -} gpr_mpscq_node; +typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node; typedef struct gpr_mpscq { gpr_atm head; -- cgit v1.2.3 From 18879dcff91209abb0e5851b2e78efbecf341a6b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 22:13:48 -0700 Subject: Add cacheline padding, and a test --- Makefile | 36 ++++ build.yaml | 9 + src/core/lib/support/mpscq.h | 1 + test/core/support/mpscq_test.c | 124 +++++++++++++ tools/run_tests/sources_and_headers.json | 14 ++ tools/run_tests/tests.json | 21 +++ vsprojects/buildtests_c.sln | 25 +++ .../test/gpr_mpscq_test/gpr_mpscq_test.vcxproj | 193 +++++++++++++++++++++ .../gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters | 21 +++ 9 files changed, 444 insertions(+) create mode 100644 test/core/support/mpscq_test.c create mode 100644 vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj create mode 100644 vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters (limited to 'src/core/lib') diff --git a/Makefile b/Makefile index 319f483e75..a78910004a 100644 --- a/Makefile +++ b/Makefile @@ -915,6 +915,7 @@ gpr_histogram_test: $(BINDIR)/$(CONFIG)/gpr_histogram_test gpr_host_port_test: $(BINDIR)/$(CONFIG)/gpr_host_port_test gpr_load_file_test: $(BINDIR)/$(CONFIG)/gpr_load_file_test gpr_log_test: $(BINDIR)/$(CONFIG)/gpr_log_test +gpr_mpscq_test: $(BINDIR)/$(CONFIG)/gpr_mpscq_test gpr_slice_buffer_test: $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test gpr_slice_test: $(BINDIR)/$(CONFIG)/gpr_slice_test gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test @@ -1249,6 +1250,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/gpr_host_port_test \ $(BINDIR)/$(CONFIG)/gpr_load_file_test \ $(BINDIR)/$(CONFIG)/gpr_log_test \ + $(BINDIR)/$(CONFIG)/gpr_mpscq_test \ $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test \ $(BINDIR)/$(CONFIG)/gpr_slice_test \ $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test \ @@ -1530,6 +1532,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/gpr_load_file_test || ( echo test gpr_load_file_test failed ; exit 1 ) $(E) "[RUN] Testing gpr_log_test" $(Q) $(BINDIR)/$(CONFIG)/gpr_log_test || ( echo test gpr_log_test failed ; exit 1 ) + $(E) "[RUN] Testing gpr_mpscq_test" + $(Q) $(BINDIR)/$(CONFIG)/gpr_mpscq_test || ( echo test gpr_mpscq_test failed ; exit 1 ) $(E) "[RUN] Testing gpr_slice_buffer_test" $(Q) $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 ) $(E) "[RUN] Testing gpr_slice_test" @@ -7177,6 +7181,38 @@ endif endif +GPR_MPSCQ_TEST_SRC = \ + test/core/support/mpscq_test.c \ + +GPR_MPSCQ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MPSCQ_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/gpr_mpscq_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_mpscq_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/support/mpscq_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GPR_MPSCQ_TEST_OBJS:.o=.dep) +endif +endif + + GPR_SLICE_BUFFER_TEST_SRC = \ test/core/support/slice_buffer_test.c \ diff --git a/build.yaml b/build.yaml index addb91fcce..9cacc0e776 100644 --- a/build.yaml +++ b/build.yaml @@ -1480,6 +1480,15 @@ targets: deps: - gpr_test_util - gpr +- name: gpr_mpscq_test + cpu_cost: 10 + build: test + language: c + src: + - test/core/support/mpscq_test.c + deps: + - gpr_test_util + - gpr - name: gpr_slice_buffer_test build: test language: c diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h index e7f4773258..2b8350be74 100644 --- a/src/core/lib/support/mpscq.h +++ b/src/core/lib/support/mpscq.h @@ -41,6 +41,7 @@ typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node; typedef struct gpr_mpscq { gpr_atm head; + char padding[GPR_CACHELINE_SIZE]; gpr_mpscq_node *tail; gpr_mpscq_node stub; } gpr_mpscq; diff --git a/test/core/support/mpscq_test.c b/test/core/support/mpscq_test.c new file mode 100644 index 0000000000..393949dc52 --- /dev/null +++ b/test/core/support/mpscq_test.c @@ -0,0 +1,124 @@ +/* + * + * Copyright 2016, 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/lib/support/mpscq.h" + +#include + +#include +#include +#include +#include +#include "test/core/util/test_config.h" + +typedef struct test_node { + gpr_mpscq_node node; + size_t i; + size_t *ctr; +} test_node; + +static test_node *new_node(size_t i, size_t *ctr) { + test_node *n = gpr_malloc(sizeof(test_node)); + n->i = i; + n->ctr = ctr; + return n; +} + +static void test_serial(void) { + gpr_log(GPR_DEBUG, "test_serial"); + gpr_mpscq q; + gpr_mpscq_init(&q); + for (size_t i = 0; i < 10000000; i++) { + gpr_mpscq_push(&q, &new_node(i, NULL)->node); + } + for (size_t i = 0; i < 10000000; i++) { + test_node *n = (test_node *)gpr_mpscq_pop(&q); + GPR_ASSERT(n); + GPR_ASSERT(n->i == i); + gpr_free(n); + } +} + +typedef struct { + size_t ctr; + gpr_mpscq *q; +} thd_args; + +#define THREAD_ITERATIONS 1000000 + +static void test_thread(void *args) { + thd_args *a = args; + for (size_t i = 1; i <= THREAD_ITERATIONS; i++) { + gpr_mpscq_push(a->q, &new_node(i, &a->ctr)->node); + } +} + +static void test_mt(void) { + gpr_log(GPR_DEBUG, "test_mt"); + gpr_thd_id thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; + gpr_mpscq q; + gpr_mpscq_init(&q); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + ta[i].ctr = 0; + ta[i].q = &q; + GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options)); + } + size_t num_done = 0; + size_t spins = 0; + while (num_done != GPR_ARRAY_SIZE(thds)) { + gpr_mpscq_node *n; + while ((n = gpr_mpscq_pop(&q)) == NULL) { + spins++; + } + test_node *tn = (test_node *)n; + GPR_ASSERT(*tn->ctr == tn->i - 1); + *tn->ctr = tn->i; + if (tn->i == THREAD_ITERATIONS) num_done++; + gpr_free(tn); + } + gpr_log(GPR_DEBUG, "spins: %d", spins); + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + gpr_mpscq_destroy(&q); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + test_serial(); + test_mt(); + return 0; +} diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 4369771170..ab08bdf55d 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -580,6 +580,20 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util" + ], + "headers": [], + "language": "c", + "name": "gpr_mpscq_test", + "src": [ + "test/core/support/mpscq_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index a07082d996..fcf03a4eca 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -661,6 +661,27 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 10, + "exclude_configs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "gpr_mpscq_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index 9c44e0a217..356fabf930 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -418,6 +418,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_log_test", "vcxproj\tes {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_mpscq_test", "vcxproj\test\gpr_mpscq_test\gpr_mpscq_test.vcxproj", "{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_slice_buffer_test", "vcxproj\test\gpr_slice_buffer_test\gpr_slice_buffer_test.vcxproj", "{E679773D-DE89-AEBB-9787-59019989B825}" ProjectSection(myProperties) = preProject lib = "False" @@ -2090,6 +2099,22 @@ Global {38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|Win32.Build.0 = Release|Win32 {38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|x64.ActiveCfg = Release|x64 {38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|x64.Build.0 = Release|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|x64.ActiveCfg = Debug|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|Win32.ActiveCfg = Release|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|x64.ActiveCfg = Release|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|Win32.Build.0 = Debug|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|x64.Build.0 = Debug|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|Win32.Build.0 = Release|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|x64.Build.0 = Release|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|x64.Build.0 = Debug|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|Win32.Build.0 = Release|Win32 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|x64.ActiveCfg = Release|x64 + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|x64.Build.0 = Release|x64 {E679773D-DE89-AEBB-9787-59019989B825}.Debug|Win32.ActiveCfg = Debug|Win32 {E679773D-DE89-AEBB-9787-59019989B825}.Debug|x64.ActiveCfg = Debug|x64 {E679773D-DE89-AEBB-9787-59019989B825}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj new file mode 100644 index 0000000000..01342868b0 --- /dev/null +++ b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj @@ -0,0 +1,193 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + gpr_mpscq_test + static + Debug + static + Debug + + + gpr_mpscq_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters new file mode 100644 index 0000000000..9cceb9f3e2 --- /dev/null +++ b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\support + + + + + + {e82fb80c-10ba-2959-55d6-8653715f1e4f} + + + {32120233-25e6-f3e4-f828-c6408d47ec04} + + + {aa3a22bc-229a-c00a-dd4a-924c818c6a49} + + + + -- cgit v1.2.3 From 049a3a6392fd69cdc99fc6765a1a5ab2a1680bdc Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 22:17:23 -0700 Subject: Add some comments --- src/core/lib/support/mpscq.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/core/lib') diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h index 2b8350be74..f7620fc5ed 100644 --- a/src/core/lib/support/mpscq.h +++ b/src/core/lib/support/mpscq.h @@ -37,10 +37,18 @@ #include #include +// Multiple-producer single-consumer lock free queue, based upon the +// implementation from Dmitry Vyukov here: +// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue + +// List node (include this in a data structure and dangle the rest of the +// interesting bits off the end) typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node; +// Actual queue type typedef struct gpr_mpscq { gpr_atm head; + // make sure head & tail don't share a cacheline char padding[GPR_CACHELINE_SIZE]; gpr_mpscq_node *tail; gpr_mpscq_node stub; @@ -48,7 +56,11 @@ typedef struct gpr_mpscq { void gpr_mpscq_init(gpr_mpscq *q); void gpr_mpscq_destroy(gpr_mpscq *q); +// Push a node void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n); +// Pop a node (returns NULL if no node is ready - which doesn't indicate that +// the queue is empty!!) gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q); #endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */ + -- cgit v1.2.3 From 1df328fe30b64369f425d791b9d26dcd956339ff Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 22:17:35 -0700 Subject: clang-format --- src/core/lib/support/mpscq.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/core/lib') diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h index f7620fc5ed..1201edceb1 100644 --- a/src/core/lib/support/mpscq.h +++ b/src/core/lib/support/mpscq.h @@ -63,4 +63,3 @@ void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n); gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q); #endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */ - -- cgit v1.2.3 From a729f60cd3a8fbf06d26f1665ac9b58f2e0b30e0 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 2 May 2016 22:24:32 -0700 Subject: Add some comments --- src/core/lib/iomgr/async_execution_lock.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index 66551f9398..ba78f81cca 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -40,6 +40,11 @@ #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/mpscq.h" +// Provides serialized access to some resource. +// Each action queued on an aelock is executed serially in a borrowed thread. +// The actual thread executing actions may change over time (but there will only +// every be one at a time). + typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); typedef struct grpc_aelock_qnode { @@ -54,8 +59,13 @@ typedef struct grpc_aelock { gpr_atm locked; } grpc_aelock; +// Initialize the lock, with an optional workqueue to shift load to when +// necessary void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); +// Destroy the lock void grpc_aelock_destroy(grpc_aelock *lock); +// Execute \a action within the lock. \a arg is the argument to pass to \a +// action and sizeof_arg is the sizeof(*arg), or 0 if arg is non-copyable. void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg); -- cgit v1.2.3 From cf600c9f252d59f437fbcd81987115b30fb58896 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 3 May 2016 08:26:56 -0700 Subject: Refine async_execution_lock interface, implement exec_ctx based task switching on starvation --- src/core/ext/transport/chttp2/transport/internal.h | 2 +- src/core/lib/iomgr/async_execution_lock.c | 81 ++++++++++++++++++---- src/core/lib/iomgr/async_execution_lock.h | 16 +---- test/core/iomgr/async_execution_lock_test.c | 19 ++--- 4 files changed, 78 insertions(+), 40 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index a269338b49..d852965edb 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -291,7 +291,7 @@ struct grpc_chttp2_transport_parsing { int64_t outgoing_window; }; -typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx, +typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, void *arg); diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 595290f78c..3859f474bf 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -38,35 +38,88 @@ #include #include -#define NO_CONSUMER ((gpr_atm)1) +typedef struct grpc_aelock_qnode { + gpr_mpscq_node mpscq_node; + grpc_aelock_action action; + void *arg; +} grpc_aelock_qnode; -void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue) { +struct grpc_aelock { + grpc_workqueue *optional_workqueue; + gpr_mpscq queue; + // state is: + // lower bit - zero if orphaned + // other bits - number of items queued on the lock + gpr_atm state; + grpc_closure continue_finishing; +}; + +static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, + bool success); + +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue) { + grpc_aelock *lock = gpr_malloc(sizeof(*lock)); lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->locked, 0); + gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); + grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); + return lock; } -void grpc_aelock_destroy(grpc_aelock *lock) { - GPR_ASSERT(gpr_atm_no_barrier_load(&lock->locked) == 0); +static void really_destroy(grpc_aelock *lock) { + GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); } +void grpc_aelock_destroy(grpc_aelock *lock) { + if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { + really_destroy(lock); + } +} + +static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { + gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); + if (n == NULL) { + // queue is in an inconsistant state: use this as a cue that we should + // go off and do something else for a while (and come back later) + grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, + lock->optional_workqueue); + return false; + } + grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; + ln->action(exec_ctx, ln->arg); + gpr_free(ln); + return true; +} + static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - while (gpr_atm_full_fetch_add(&lock->locked, -1) != 1) { - gpr_mpscq_node *n; - while ((n = gpr_mpscq_pop(&lock->queue)) == NULL) { - // TODO(ctiller): find something to fill in the time + do { + switch (gpr_atm_full_fetch_add(&lock->state, -2)) { + case 3: // had one count, one unorphaned --> unlocked unorphaned + return; + case 2: // and one count, one orphaned --> unlocked and orphaned + really_destroy(lock); + return; + case 1: + case 0: + // these values are illegal - representing an already unlocked or + // deleted lock + GPR_UNREACHABLE_CODE(return ); } - grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; - ln->action(exec_ctx, ln->arg); - gpr_free(ln); - } + } while (maybe_finish_one(exec_ctx, lock)); +} + +static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, + bool success) { + if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); } void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { - if (gpr_atm_full_fetch_add(&lock->locked, 1) == 0) { + gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); + GPR_ASSERT(last & 1); // ensure lock has not been destroyed + if (last == 1) { action(exec_ctx, arg); finish(exec_ctx, lock); } else { diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index ba78f81cca..5ced82b08d 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -40,6 +40,8 @@ #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/mpscq.h" +typedef struct grpc_aelock grpc_aelock; + // Provides serialized access to some resource. // Each action queued on an aelock is executed serially in a borrowed thread. // The actual thread executing actions may change over time (but there will only @@ -47,21 +49,9 @@ typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); -typedef struct grpc_aelock_qnode { - gpr_mpscq_node mpscq_node; - grpc_aelock_action action; - void *arg; -} grpc_aelock_qnode; - -typedef struct grpc_aelock { - grpc_workqueue *optional_workqueue; - gpr_mpscq queue; - gpr_atm locked; -} grpc_aelock; - // Initialize the lock, with an optional workqueue to shift load to when // necessary -void grpc_aelock_init(grpc_aelock *lock, grpc_workqueue *optional_workqueue); +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue); // Destroy the lock void grpc_aelock_destroy(grpc_aelock *lock); // Execute \a action within the lock. \a arg is the argument to pass to \a diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c index 8c9665a458..526913bc3a 100644 --- a/test/core/iomgr/async_execution_lock_test.c +++ b/test/core/iomgr/async_execution_lock_test.c @@ -42,10 +42,7 @@ static void test_no_op(void) { gpr_log(GPR_DEBUG, "test_no_op"); - - grpc_aelock lock; - grpc_aelock_init(&lock, NULL); - grpc_aelock_destroy(&lock); + grpc_aelock_destroy(grpc_aelock_create(NULL)); } static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { @@ -55,14 +52,13 @@ static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { static void test_execute_one(void) { gpr_log(GPR_DEBUG, "test_execute_one"); - grpc_aelock lock; - grpc_aelock_init(&lock, NULL); + grpc_aelock *lock = grpc_aelock_create(NULL); bool done = false; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_aelock_execute(&exec_ctx, &lock, set_bool_to_true, &done, 0); + grpc_aelock_execute(&exec_ctx, lock, set_bool_to_true, &done, 0); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(done); - grpc_aelock_destroy(&lock); + grpc_aelock_destroy(lock); } typedef struct { @@ -100,21 +96,20 @@ static void execute_many_loop(void *a) { static void test_execute_many(void) { gpr_log(GPR_DEBUG, "test_execute_many"); - grpc_aelock lock; + grpc_aelock *lock = grpc_aelock_create(NULL); gpr_thd_id thds[100]; thd_args ta[GPR_ARRAY_SIZE(thds)]; - grpc_aelock_init(&lock, NULL); for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_options options = gpr_thd_options_default(); gpr_thd_options_set_joinable(&options); ta[i].ctr = 0; - ta[i].lock = &lock; + ta[i].lock = lock; GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options)); } for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_join(thds[i]); } - grpc_aelock_destroy(&lock); + grpc_aelock_destroy(lock); } int main(int argc, char **argv) { -- cgit v1.2.3 From 14e3d9bf5b5be4ae78d679213777bd68903d33a7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 3 May 2016 08:33:56 -0700 Subject: Fix leak --- src/core/lib/iomgr/async_execution_lock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 3859f474bf..96ba175a5a 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -69,6 +69,7 @@ grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue) { static void really_destroy(grpc_aelock *lock) { GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); + gpr_free(lock); } void grpc_aelock_destroy(grpc_aelock *lock) { -- cgit v1.2.3 From 5774a469c029fed88a98283129fd61cd5c78e78f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 3 May 2016 09:24:35 -0700 Subject: Fix header guards --- src/core/lib/iomgr/async_execution_lock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index 5ced82b08d..e52762f443 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -31,8 +31,8 @@ * */ -#ifndef AEL_H -#define AEL_H +#ifndef GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H +#define GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H #include @@ -60,4 +60,4 @@ void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg); -#endif +#endif /* GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H */ -- cgit v1.2.3 From c9d4b81dabf4dc2c262fc771c31790f2d60fe551 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 24 May 2016 10:50:40 -0700 Subject: Add the ability to run some action when the lock becomes idle --- src/core/lib/iomgr/async_execution_lock.c | 94 +++++++++++++++++++++++------ src/core/lib/iomgr/async_execution_lock.h | 4 +- test/core/iomgr/async_execution_lock_test.c | 22 +++++-- 3 files changed, 98 insertions(+), 22 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index 96ba175a5a..c656e7c940 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -38,6 +38,9 @@ #include #include +#define STATE_BIT_ALIVE 1 +#define STATE_BIT_REFS 2 + typedef struct grpc_aelock_qnode { gpr_mpscq_node mpscq_node; grpc_aelock_action action; @@ -50,17 +53,24 @@ struct grpc_aelock { // state is: // lower bit - zero if orphaned // other bits - number of items queued on the lock + // see: STATE_BIT_xxx gpr_atm state; + grpc_aelock_action before_idle_action; + void *before_idle_action_arg; grpc_closure continue_finishing; }; static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, bool success); -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue) { +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue, + grpc_aelock_action before_idle_action, + void *before_idle_action_arg) { grpc_aelock *lock = gpr_malloc(sizeof(*lock)); + lock->before_idle_action = before_idle_action; + lock->before_idle_action_arg = before_idle_action_arg; lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->state, 1); + gpr_atm_no_barrier_store(&lock->state, STATE_BIT_ALIVE); gpr_mpscq_init(&lock->queue); grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); return lock; @@ -73,7 +83,8 @@ static void really_destroy(grpc_aelock *lock) { } void grpc_aelock_destroy(grpc_aelock *lock) { - if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { + if (gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_ALIVE) == + STATE_BIT_ALIVE) { really_destroy(lock); } } @@ -81,10 +92,6 @@ void grpc_aelock_destroy(grpc_aelock *lock) { static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); if (n == NULL) { - // queue is in an inconsistant state: use this as a cue that we should - // go off and do something else for a while (and come back later) - grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, - lock->optional_workqueue); return false; } grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; @@ -94,36 +101,89 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { } static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - do { - switch (gpr_atm_full_fetch_add(&lock->state, -2)) { - case 3: // had one count, one unorphaned --> unlocked unorphaned + for (;;) { + gpr_atm last_state = gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS); + switch (last_state) { + default: + perform_one_step: + gpr_log(GPR_DEBUG, "ls=%d execute", last_state); + if (!maybe_finish_one(exec_ctx, lock)) { + // perform the idle action before going off to do something else + lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); + // quick peek to see if we can immediately resume + if (!maybe_finish_one(exec_ctx, lock)) { + // queue is in an inconsistant state: use this as a cue that we + // should + // go off and do something else for a while (and come back later) + grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, + lock->optional_workqueue); + return; + } + } + break; + case STATE_BIT_ALIVE | (2 * STATE_BIT_REFS): + gpr_log(GPR_DEBUG, "ls=%d final", last_state); + lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); + switch (gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS)) { + case STATE_BIT_ALIVE | STATE_BIT_REFS: + return; + case STATE_BIT_REFS: + really_destroy(lock); + return; + default: + gpr_log(GPR_DEBUG, "retry"); + // oops: did the before action, but something else came in + // better add another ref so we remember to do this again + gpr_atm_full_fetch_add(&lock->state, STATE_BIT_REFS); + goto perform_one_step; + } + break; + case STATE_BIT_ALIVE | STATE_BIT_REFS: + gpr_log(GPR_DEBUG, "ls=%d unlock", last_state); return; - case 2: // and one count, one orphaned --> unlocked and orphaned + case 2 * STATE_BIT_REFS: + gpr_log(GPR_DEBUG, "ls=%d idle", last_state); + lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); + GPR_ASSERT(gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS) == + STATE_BIT_REFS); + case STATE_BIT_REFS: + gpr_log(GPR_DEBUG, "ls=%d destroy", last_state); really_destroy(lock); return; - case 1: + case STATE_BIT_ALIVE: case 0: // these values are illegal - representing an already unlocked or // deleted lock GPR_UNREACHABLE_CODE(return ); } - } while (maybe_finish_one(exec_ctx, lock)); + } + + // while (maybe_finish_one(exec_ctx, lock)); } static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); + grpc_aelock *lock = arg; + if (maybe_finish_one(exec_ctx, lock)) { + finish(exec_ctx, lock); + } else { + // queue is in an inconsistant state: use this as a cue that we should + // go off and do something else for a while (and come back later) + grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, + lock->optional_workqueue); + } } void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { - gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); - GPR_ASSERT(last & 1); // ensure lock has not been destroyed - if (last == 1) { + gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2 * STATE_BIT_REFS); + GPR_ASSERT(last & STATE_BIT_ALIVE); // ensure lock has not been destroyed + if (last == STATE_BIT_ALIVE) { action(exec_ctx, arg); finish(exec_ctx, lock); } else { + gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS); grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); n->action = action; if (sizeof_arg > 0) { diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index e52762f443..ea7a322fae 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -51,7 +51,9 @@ typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); // Initialize the lock, with an optional workqueue to shift load to when // necessary -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue); +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue, + grpc_aelock_action before_idle_action, + void *before_idle_action_arg); // Destroy the lock void grpc_aelock_destroy(grpc_aelock *lock); // Execute \a action within the lock. \a arg is the argument to pass to \a diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c index 526913bc3a..0ce0183562 100644 --- a/test/core/iomgr/async_execution_lock_test.c +++ b/test/core/iomgr/async_execution_lock_test.c @@ -40,25 +40,34 @@ #include "test/core/util/test_config.h" +static void do_nothing_action(grpc_exec_ctx *exec_ctx, void *ignored) {} + static void test_no_op(void) { gpr_log(GPR_DEBUG, "test_no_op"); - grpc_aelock_destroy(grpc_aelock_create(NULL)); + grpc_aelock_destroy(grpc_aelock_create(NULL, do_nothing_action, NULL)); } static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { *(bool *)value = true; } +static void increment_atomic(grpc_exec_ctx *exec_ctx, void *value) { + gpr_atm_full_fetch_add((gpr_atm *)value, 1); +} + static void test_execute_one(void) { gpr_log(GPR_DEBUG, "test_execute_one"); - grpc_aelock *lock = grpc_aelock_create(NULL); + gpr_atm idles; + gpr_atm_no_barrier_store(&idles, 0); + grpc_aelock *lock = grpc_aelock_create(NULL, increment_atomic, &idles); bool done = false; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_aelock_execute(&exec_ctx, lock, set_bool_to_true, &done, 0); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(done); grpc_aelock_destroy(lock); + GPR_ASSERT(gpr_atm_no_barrier_load(&idles) == 1); } typedef struct { @@ -83,7 +92,7 @@ static void execute_many_loop(void *a) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; size_t n = 1; for (size_t i = 0; i < 10; i++) { - for (size_t j = 0; j < 10000; j++) { + for (size_t j = 0; j < 100; j++) { ex_args c = {&args->ctr, n++}; grpc_aelock_execute(&exec_ctx, args->lock, check_one, &c, sizeof(c)); grpc_exec_ctx_flush(&exec_ctx); @@ -96,7 +105,10 @@ static void execute_many_loop(void *a) { static void test_execute_many(void) { gpr_log(GPR_DEBUG, "test_execute_many"); - grpc_aelock *lock = grpc_aelock_create(NULL); + gpr_atm idles; + gpr_atm_no_barrier_store(&idles, 0); + + grpc_aelock *lock = grpc_aelock_create(NULL, increment_atomic, &idles); gpr_thd_id thds[100]; thd_args ta[GPR_ARRAY_SIZE(thds)]; for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { @@ -110,6 +122,8 @@ static void test_execute_many(void) { gpr_thd_join(thds[i]); } grpc_aelock_destroy(lock); + + gpr_log(GPR_DEBUG, "idles: %d", gpr_atm_no_barrier_load(&idles)); } int main(int argc, char **argv) { -- cgit v1.2.3 From 765c538d72572b9317661d4a6697d9547fb026a9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Jul 2016 21:25:04 -0700 Subject: Revert "Add the ability to run some action when the lock becomes idle" This reverts commit c9d4b81dabf4dc2c262fc771c31790f2d60fe551. --- src/core/lib/iomgr/async_execution_lock.c | 94 ++++++----------------------- src/core/lib/iomgr/async_execution_lock.h | 4 +- test/core/iomgr/async_execution_lock_test.c | 22 ++----- 3 files changed, 22 insertions(+), 98 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c index c656e7c940..96ba175a5a 100644 --- a/src/core/lib/iomgr/async_execution_lock.c +++ b/src/core/lib/iomgr/async_execution_lock.c @@ -38,9 +38,6 @@ #include #include -#define STATE_BIT_ALIVE 1 -#define STATE_BIT_REFS 2 - typedef struct grpc_aelock_qnode { gpr_mpscq_node mpscq_node; grpc_aelock_action action; @@ -53,24 +50,17 @@ struct grpc_aelock { // state is: // lower bit - zero if orphaned // other bits - number of items queued on the lock - // see: STATE_BIT_xxx gpr_atm state; - grpc_aelock_action before_idle_action; - void *before_idle_action_arg; grpc_closure continue_finishing; }; static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, bool success); -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue, - grpc_aelock_action before_idle_action, - void *before_idle_action_arg) { +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue) { grpc_aelock *lock = gpr_malloc(sizeof(*lock)); - lock->before_idle_action = before_idle_action; - lock->before_idle_action_arg = before_idle_action_arg; lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->state, STATE_BIT_ALIVE); + gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); return lock; @@ -83,8 +73,7 @@ static void really_destroy(grpc_aelock *lock) { } void grpc_aelock_destroy(grpc_aelock *lock) { - if (gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_ALIVE) == - STATE_BIT_ALIVE) { + if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { really_destroy(lock); } } @@ -92,6 +81,10 @@ void grpc_aelock_destroy(grpc_aelock *lock) { static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); if (n == NULL) { + // queue is in an inconsistant state: use this as a cue that we should + // go off and do something else for a while (and come back later) + grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, + lock->optional_workqueue); return false; } grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; @@ -101,89 +94,36 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { } static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - for (;;) { - gpr_atm last_state = gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS); - switch (last_state) { - default: - perform_one_step: - gpr_log(GPR_DEBUG, "ls=%d execute", last_state); - if (!maybe_finish_one(exec_ctx, lock)) { - // perform the idle action before going off to do something else - lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); - // quick peek to see if we can immediately resume - if (!maybe_finish_one(exec_ctx, lock)) { - // queue is in an inconsistant state: use this as a cue that we - // should - // go off and do something else for a while (and come back later) - grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, - lock->optional_workqueue); - return; - } - } - break; - case STATE_BIT_ALIVE | (2 * STATE_BIT_REFS): - gpr_log(GPR_DEBUG, "ls=%d final", last_state); - lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); - switch (gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS)) { - case STATE_BIT_ALIVE | STATE_BIT_REFS: - return; - case STATE_BIT_REFS: - really_destroy(lock); - return; - default: - gpr_log(GPR_DEBUG, "retry"); - // oops: did the before action, but something else came in - // better add another ref so we remember to do this again - gpr_atm_full_fetch_add(&lock->state, STATE_BIT_REFS); - goto perform_one_step; - } - break; - case STATE_BIT_ALIVE | STATE_BIT_REFS: - gpr_log(GPR_DEBUG, "ls=%d unlock", last_state); + do { + switch (gpr_atm_full_fetch_add(&lock->state, -2)) { + case 3: // had one count, one unorphaned --> unlocked unorphaned return; - case 2 * STATE_BIT_REFS: - gpr_log(GPR_DEBUG, "ls=%d idle", last_state); - lock->before_idle_action(exec_ctx, lock->before_idle_action_arg); - GPR_ASSERT(gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS) == - STATE_BIT_REFS); - case STATE_BIT_REFS: - gpr_log(GPR_DEBUG, "ls=%d destroy", last_state); + case 2: // and one count, one orphaned --> unlocked and orphaned really_destroy(lock); return; - case STATE_BIT_ALIVE: + case 1: case 0: // these values are illegal - representing an already unlocked or // deleted lock GPR_UNREACHABLE_CODE(return ); } - } - - // while (maybe_finish_one(exec_ctx, lock)); + } while (maybe_finish_one(exec_ctx, lock)); } static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, bool success) { - grpc_aelock *lock = arg; - if (maybe_finish_one(exec_ctx, lock)) { - finish(exec_ctx, lock); - } else { - // queue is in an inconsistant state: use this as a cue that we should - // go off and do something else for a while (and come back later) - grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, - lock->optional_workqueue); - } + if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); } void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, grpc_aelock_action action, void *arg, size_t sizeof_arg) { - gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2 * STATE_BIT_REFS); - GPR_ASSERT(last & STATE_BIT_ALIVE); // ensure lock has not been destroyed - if (last == STATE_BIT_ALIVE) { + gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); + GPR_ASSERT(last & 1); // ensure lock has not been destroyed + if (last == 1) { action(exec_ctx, arg); finish(exec_ctx, lock); } else { - gpr_atm_full_fetch_add(&lock->state, -STATE_BIT_REFS); grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); n->action = action; if (sizeof_arg > 0) { diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h index ea7a322fae..e52762f443 100644 --- a/src/core/lib/iomgr/async_execution_lock.h +++ b/src/core/lib/iomgr/async_execution_lock.h @@ -51,9 +51,7 @@ typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); // Initialize the lock, with an optional workqueue to shift load to when // necessary -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue, - grpc_aelock_action before_idle_action, - void *before_idle_action_arg); +grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue); // Destroy the lock void grpc_aelock_destroy(grpc_aelock *lock); // Execute \a action within the lock. \a arg is the argument to pass to \a diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c index 0ce0183562..526913bc3a 100644 --- a/test/core/iomgr/async_execution_lock_test.c +++ b/test/core/iomgr/async_execution_lock_test.c @@ -40,34 +40,25 @@ #include "test/core/util/test_config.h" -static void do_nothing_action(grpc_exec_ctx *exec_ctx, void *ignored) {} - static void test_no_op(void) { gpr_log(GPR_DEBUG, "test_no_op"); - grpc_aelock_destroy(grpc_aelock_create(NULL, do_nothing_action, NULL)); + grpc_aelock_destroy(grpc_aelock_create(NULL)); } static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { *(bool *)value = true; } -static void increment_atomic(grpc_exec_ctx *exec_ctx, void *value) { - gpr_atm_full_fetch_add((gpr_atm *)value, 1); -} - static void test_execute_one(void) { gpr_log(GPR_DEBUG, "test_execute_one"); - gpr_atm idles; - gpr_atm_no_barrier_store(&idles, 0); - grpc_aelock *lock = grpc_aelock_create(NULL, increment_atomic, &idles); + grpc_aelock *lock = grpc_aelock_create(NULL); bool done = false; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_aelock_execute(&exec_ctx, lock, set_bool_to_true, &done, 0); grpc_exec_ctx_finish(&exec_ctx); GPR_ASSERT(done); grpc_aelock_destroy(lock); - GPR_ASSERT(gpr_atm_no_barrier_load(&idles) == 1); } typedef struct { @@ -92,7 +83,7 @@ static void execute_many_loop(void *a) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; size_t n = 1; for (size_t i = 0; i < 10; i++) { - for (size_t j = 0; j < 100; j++) { + for (size_t j = 0; j < 10000; j++) { ex_args c = {&args->ctr, n++}; grpc_aelock_execute(&exec_ctx, args->lock, check_one, &c, sizeof(c)); grpc_exec_ctx_flush(&exec_ctx); @@ -105,10 +96,7 @@ static void execute_many_loop(void *a) { static void test_execute_many(void) { gpr_log(GPR_DEBUG, "test_execute_many"); - gpr_atm idles; - gpr_atm_no_barrier_store(&idles, 0); - - grpc_aelock *lock = grpc_aelock_create(NULL, increment_atomic, &idles); + grpc_aelock *lock = grpc_aelock_create(NULL); gpr_thd_id thds[100]; thd_args ta[GPR_ARRAY_SIZE(thds)]; for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { @@ -122,8 +110,6 @@ static void test_execute_many(void) { gpr_thd_join(thds[i]); } grpc_aelock_destroy(lock); - - gpr_log(GPR_DEBUG, "idles: %d", gpr_atm_no_barrier_load(&idles)); } int main(int argc, char **argv) { -- cgit v1.2.3 From f7cade1b4fee90abb0fabe48426e95357465c976 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Jul 2016 21:41:10 -0700 Subject: Rename async_execution_lock --> combiner, make it use closures, unroll previous changes for idleness --- BUILD | 24 +-- CMakeLists.txt | 10 +- Makefile | 82 ++++----- binding.gyp | 2 +- build.yaml | 26 +-- config.m4 | 2 +- gRPC.podspec | 6 +- grpc.gemspec | 4 +- package.xml | 4 +- src/core/lib/iomgr/async_execution_lock.c | 137 -------------- src/core/lib/iomgr/async_execution_lock.h | 63 ------- src/core/lib/iomgr/closure.h | 16 +- src/core/lib/iomgr/combiner.c | 125 +++++++++++++ src/core/lib/iomgr/combiner.h | 60 +++++++ src/python/grpcio/grpc_core_dependencies.py | 2 +- test/core/iomgr/async_execution_lock_test.c | 124 ------------- test/core/iomgr/combiner_test.c | 129 +++++++++++++ test/core/support/mpscq_test.c | 2 +- third_party/protobuf | 2 +- tools/doxygen/Doxyfile.c++.internal | 4 +- tools/doxygen/Doxyfile.core.internal | 4 +- tools/run_tests/sources_and_headers.json | 38 ++-- tools/run_tests/tests.json | 24 +-- vsprojects/buildtests_c.sln | 54 +++--- vsprojects/vcxproj/grpc++/grpc++.vcxproj | 6 +- vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters | 8 +- .../grpc++_unsecure/grpc++_unsecure.vcxproj | 6 +- .../grpc++_unsecure.vcxproj.filters | 8 +- vsprojects/vcxproj/grpc/grpc.vcxproj | 6 +- vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 8 +- .../vcxproj/grpc_unsecure/grpc_unsecure.vcxproj | 6 +- .../grpc_unsecure/grpc_unsecure.vcxproj.filters | 8 +- .../async_execution_lock_test.vcxproj | 199 --------------------- .../async_execution_lock_test.vcxproj.filters | 21 --- .../test/combiner_test/combiner_test.vcxproj | 199 +++++++++++++++++++++ .../combiner_test/combiner_test.vcxproj.filters | 21 +++ 36 files changed, 716 insertions(+), 724 deletions(-) delete mode 100644 src/core/lib/iomgr/async_execution_lock.c delete mode 100644 src/core/lib/iomgr/async_execution_lock.h create mode 100644 src/core/lib/iomgr/combiner.c create mode 100644 src/core/lib/iomgr/combiner.h delete mode 100644 test/core/iomgr/async_execution_lock_test.c create mode 100644 test/core/iomgr/combiner_test.c delete mode 100644 vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj delete mode 100644 vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters create mode 100644 vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj create mode 100644 vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters (limited to 'src/core/lib') diff --git a/BUILD b/BUILD index 0b090fa81c..957c153f8e 100644 --- a/BUILD +++ b/BUILD @@ -175,8 +175,8 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -327,8 +327,8 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -564,8 +564,8 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -706,8 +706,8 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -918,8 +918,8 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -1047,8 +1047,8 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -1257,8 +1257,8 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -1392,8 +1392,8 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -1718,8 +1718,8 @@ cc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -1848,8 +1848,8 @@ cc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -2267,8 +2267,8 @@ objc_library( "src/core/lib/http/format_request.c", "src/core/lib/http/httpcli.c", "src/core/lib/http/parser.c", - "src/core/lib/iomgr/async_execution_lock.c", "src/core/lib/iomgr/closure.c", + "src/core/lib/iomgr/combiner.c", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_windows.c", @@ -2483,8 +2483,8 @@ objc_library( "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index ec4f75bab0..36d0727735 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,8 +141,8 @@ add_library(grpc src/core/lib/http/format_request.c src/core/lib/http/httpcli.c src/core/lib/http/parser.c - src/core/lib/iomgr/async_execution_lock.c src/core/lib/iomgr/closure.c + src/core/lib/iomgr/combiner.c src/core/lib/iomgr/endpoint.c src/core/lib/iomgr/endpoint_pair_posix.c src/core/lib/iomgr/endpoint_pair_windows.c @@ -347,8 +347,8 @@ add_library(grpc_cronet src/core/lib/http/format_request.c src/core/lib/http/httpcli.c src/core/lib/http/parser.c - src/core/lib/iomgr/async_execution_lock.c src/core/lib/iomgr/closure.c + src/core/lib/iomgr/combiner.c src/core/lib/iomgr/endpoint.c src/core/lib/iomgr/endpoint_pair_posix.c src/core/lib/iomgr/endpoint_pair_windows.c @@ -530,8 +530,8 @@ add_library(grpc_unsecure src/core/lib/http/format_request.c src/core/lib/http/httpcli.c src/core/lib/http/parser.c - src/core/lib/iomgr/async_execution_lock.c src/core/lib/iomgr/closure.c + src/core/lib/iomgr/combiner.c src/core/lib/iomgr/endpoint.c src/core/lib/iomgr/endpoint_pair_posix.c src/core/lib/iomgr/endpoint_pair_windows.c @@ -735,8 +735,8 @@ add_library(grpc++ src/core/lib/http/format_request.c src/core/lib/http/httpcli.c src/core/lib/http/parser.c - src/core/lib/iomgr/async_execution_lock.c src/core/lib/iomgr/closure.c + src/core/lib/iomgr/combiner.c src/core/lib/iomgr/endpoint.c src/core/lib/iomgr/endpoint_pair_posix.c src/core/lib/iomgr/endpoint_pair_windows.c @@ -921,8 +921,8 @@ add_library(grpc++_unsecure src/core/lib/http/format_request.c src/core/lib/http/httpcli.c src/core/lib/http/parser.c - src/core/lib/iomgr/async_execution_lock.c src/core/lib/iomgr/closure.c + src/core/lib/iomgr/combiner.c src/core/lib/iomgr/endpoint.c src/core/lib/iomgr/endpoint_pair_posix.c src/core/lib/iomgr/endpoint_pair_windows.c diff --git a/Makefile b/Makefile index 41d5bfa47c..710fd941fe 100644 --- a/Makefile +++ b/Makefile @@ -879,7 +879,6 @@ algorithm_test: $(BINDIR)/$(CONFIG)/algorithm_test alloc_test: $(BINDIR)/$(CONFIG)/alloc_test alpn_test: $(BINDIR)/$(CONFIG)/alpn_test api_fuzzer: $(BINDIR)/$(CONFIG)/api_fuzzer -async_execution_lock_test: $(BINDIR)/$(CONFIG)/async_execution_lock_test bad_server_response_test: $(BINDIR)/$(CONFIG)/bad_server_response_test bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test @@ -890,6 +889,7 @@ chttp2_status_conversion_test: $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test client_fuzzer: $(BINDIR)/$(CONFIG)/client_fuzzer +combiner_test: $(BINDIR)/$(CONFIG)/combiner_test compression_test: $(BINDIR)/$(CONFIG)/compression_test concurrent_connectivity_test: $(BINDIR)/$(CONFIG)/concurrent_connectivity_test dns_resolver_connectivity_test: $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test @@ -1199,7 +1199,6 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/algorithm_test \ $(BINDIR)/$(CONFIG)/alloc_test \ $(BINDIR)/$(CONFIG)/alpn_test \ - $(BINDIR)/$(CONFIG)/async_execution_lock_test \ $(BINDIR)/$(CONFIG)/bad_server_response_test \ $(BINDIR)/$(CONFIG)/bin_decoder_test \ $(BINDIR)/$(CONFIG)/bin_encoder_test \ @@ -1209,6 +1208,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test \ $(BINDIR)/$(CONFIG)/chttp2_stream_map_test \ $(BINDIR)/$(CONFIG)/chttp2_varint_test \ + $(BINDIR)/$(CONFIG)/combiner_test \ $(BINDIR)/$(CONFIG)/compression_test \ $(BINDIR)/$(CONFIG)/concurrent_connectivity_test \ $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test \ @@ -1500,8 +1500,6 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/alloc_test || ( echo test alloc_test failed ; exit 1 ) $(E) "[RUN] Testing alpn_test" $(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 ) - $(E) "[RUN] Testing async_execution_lock_test" - $(Q) $(BINDIR)/$(CONFIG)/async_execution_lock_test || ( echo test async_execution_lock_test failed ; exit 1 ) $(E) "[RUN] Testing bad_server_response_test" $(Q) $(BINDIR)/$(CONFIG)/bad_server_response_test || ( echo test bad_server_response_test failed ; exit 1 ) $(E) "[RUN] Testing bin_decoder_test" @@ -1520,6 +1518,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 ) $(E) "[RUN] Testing chttp2_varint_test" $(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 ) + $(E) "[RUN] Testing combiner_test" + $(Q) $(BINDIR)/$(CONFIG)/combiner_test || ( echo test combiner_test failed ; exit 1 ) $(E) "[RUN] Testing compression_test" $(Q) $(BINDIR)/$(CONFIG)/compression_test || ( echo test compression_test failed ; exit 1 ) $(E) "[RUN] Testing concurrent_connectivity_test" @@ -2492,8 +2492,8 @@ LIBGRPC_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ @@ -2765,8 +2765,8 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ @@ -3107,8 +3107,8 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ @@ -3442,8 +3442,8 @@ LIBGRPC++_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ @@ -4054,8 +4054,8 @@ LIBGRPC++_UNSECURE_SRC = \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ @@ -6849,38 +6849,6 @@ endif endif -ASYNC_EXECUTION_LOCK_TEST_SRC = \ - test/core/iomgr/async_execution_lock_test.c \ - -ASYNC_EXECUTION_LOCK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ASYNC_EXECUTION_LOCK_TEST_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/async_execution_lock_test: openssl_dep_error - -else - - - -$(BINDIR)/$(CONFIG)/async_execution_lock_test: $(ASYNC_EXECUTION_LOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LD) $(LDFLAGS) $(ASYNC_EXECUTION_LOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/async_execution_lock_test - -endif - -$(OBJDIR)/$(CONFIG)/test/core/iomgr/async_execution_lock_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - -deps_async_execution_lock_test: $(ASYNC_EXECUTION_LOCK_TEST_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(ASYNC_EXECUTION_LOCK_TEST_OBJS:.o=.dep) -endif -endif - - BAD_SERVER_RESPONSE_TEST_SRC = \ test/core/end2end/bad_server_response_test.c \ @@ -7201,6 +7169,38 @@ endif endif +COMBINER_TEST_SRC = \ + test/core/iomgr/combiner_test.c \ + +COMBINER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(COMBINER_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/combiner_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/combiner_test: $(COMBINER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(COMBINER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/combiner_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/iomgr/combiner_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_combiner_test: $(COMBINER_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(COMBINER_TEST_OBJS:.o=.dep) +endif +endif + + COMPRESSION_TEST_SRC = \ test/core/compression/compression_test.c \ diff --git a/binding.gyp b/binding.gyp index efd76616c4..86e819a480 100644 --- a/binding.gyp +++ b/binding.gyp @@ -577,8 +577,8 @@ 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', - 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/combiner.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', 'src/core/lib/iomgr/endpoint_pair_windows.c', diff --git a/build.yaml b/build.yaml index 3c3a9209d3..5daad9d948 100644 --- a/build.yaml +++ b/build.yaml @@ -166,8 +166,8 @@ filegroups: - src/core/lib/http/format_request.h - src/core/lib/http/httpcli.h - src/core/lib/http/parser.h - - src/core/lib/iomgr/async_execution_lock.h - src/core/lib/iomgr/closure.h + - src/core/lib/iomgr/combiner.h - src/core/lib/iomgr/endpoint.h - src/core/lib/iomgr/endpoint_pair.h - src/core/lib/iomgr/error.h @@ -245,8 +245,8 @@ filegroups: - src/core/lib/http/format_request.c - src/core/lib/http/httpcli.c - src/core/lib/http/parser.c - - src/core/lib/iomgr/async_execution_lock.c - src/core/lib/iomgr/closure.c + - src/core/lib/iomgr/combiner.c - src/core/lib/iomgr/endpoint.c - src/core/lib/iomgr/endpoint_pair_posix.c - src/core/lib/iomgr/endpoint_pair_windows.c @@ -1246,17 +1246,6 @@ targets: - test/core/end2end/fuzzers/api_fuzzer_corpus dict: test/core/end2end/fuzzers/api_fuzzer.dictionary maxlen: 2048 -- name: async_execution_lock_test - cpu_cost: 30 - build: test - language: c - src: - - test/core/iomgr/async_execution_lock_test.c - deps: - - grpc_test_util - - grpc - - gpr_test_util - - gpr - name: bad_server_response_test build: test language: c @@ -1358,6 +1347,17 @@ targets: - test/core/end2end/fuzzers/client_fuzzer_corpus dict: test/core/end2end/fuzzers/hpack.dictionary maxlen: 2048 +- name: combiner_test + cpu_cost: 30 + build: test + language: c + src: + - test/core/iomgr/combiner_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr - name: compression_test build: test language: c diff --git a/config.m4 b/config.m4 index 2974d2ed8d..6ecacb9173 100644 --- a/config.m4 +++ b/config.m4 @@ -96,8 +96,8 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ - src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ + src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ diff --git a/gRPC.podspec b/gRPC.podspec index e6105b9603..4f2203c7a5 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -178,8 +178,8 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', 'src/core/lib/http/parser.h', - 'src/core/lib/iomgr/async_execution_lock.h', 'src/core/lib/iomgr/closure.h', + 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', @@ -364,8 +364,8 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', - 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/combiner.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', 'src/core/lib/iomgr/endpoint_pair_windows.c', @@ -564,8 +564,8 @@ Pod::Spec.new do |s| 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', 'src/core/lib/http/parser.h', - 'src/core/lib/iomgr/async_execution_lock.h', 'src/core/lib/iomgr/closure.h', + 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', diff --git a/grpc.gemspec b/grpc.gemspec index a4e0182131..b9f858284a 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -187,8 +187,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/format_request.h ) s.files += %w( src/core/lib/http/httpcli.h ) s.files += %w( src/core/lib/http/parser.h ) - s.files += %w( src/core/lib/iomgr/async_execution_lock.h ) s.files += %w( src/core/lib/iomgr/closure.h ) + s.files += %w( src/core/lib/iomgr/combiner.h ) s.files += %w( src/core/lib/iomgr/endpoint.h ) s.files += %w( src/core/lib/iomgr/endpoint_pair.h ) s.files += %w( src/core/lib/iomgr/error.h ) @@ -343,8 +343,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/format_request.c ) s.files += %w( src/core/lib/http/httpcli.c ) s.files += %w( src/core/lib/http/parser.c ) - s.files += %w( src/core/lib/iomgr/async_execution_lock.c ) s.files += %w( src/core/lib/iomgr/closure.c ) + s.files += %w( src/core/lib/iomgr/combiner.c ) s.files += %w( src/core/lib/iomgr/endpoint.c ) s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c ) s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c ) diff --git a/package.xml b/package.xml index 3631a1d682..91e5b05291 100644 --- a/package.xml +++ b/package.xml @@ -194,8 +194,8 @@ - + @@ -350,8 +350,8 @@ - + diff --git a/src/core/lib/iomgr/async_execution_lock.c b/src/core/lib/iomgr/async_execution_lock.c deleted file mode 100644 index 96ba175a5a..0000000000 --- a/src/core/lib/iomgr/async_execution_lock.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Copyright 2016, 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/lib/iomgr/async_execution_lock.h" - -#include - -#include -#include - -typedef struct grpc_aelock_qnode { - gpr_mpscq_node mpscq_node; - grpc_aelock_action action; - void *arg; -} grpc_aelock_qnode; - -struct grpc_aelock { - grpc_workqueue *optional_workqueue; - gpr_mpscq queue; - // state is: - // lower bit - zero if orphaned - // other bits - number of items queued on the lock - gpr_atm state; - grpc_closure continue_finishing; -}; - -static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, - bool success); - -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue) { - grpc_aelock *lock = gpr_malloc(sizeof(*lock)); - lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->state, 1); - gpr_mpscq_init(&lock->queue); - grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); - return lock; -} - -static void really_destroy(grpc_aelock *lock) { - GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); - gpr_mpscq_destroy(&lock->queue); - gpr_free(lock); -} - -void grpc_aelock_destroy(grpc_aelock *lock) { - if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { - really_destroy(lock); - } -} - -static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); - if (n == NULL) { - // queue is in an inconsistant state: use this as a cue that we should - // go off and do something else for a while (and come back later) - grpc_exec_ctx_enqueue(exec_ctx, &lock->continue_finishing, true, - lock->optional_workqueue); - return false; - } - grpc_aelock_qnode *ln = (grpc_aelock_qnode *)n; - ln->action(exec_ctx, ln->arg); - gpr_free(ln); - return true; -} - -static void finish(grpc_exec_ctx *exec_ctx, grpc_aelock *lock) { - do { - switch (gpr_atm_full_fetch_add(&lock->state, -2)) { - case 3: // had one count, one unorphaned --> unlocked unorphaned - return; - case 2: // and one count, one orphaned --> unlocked and orphaned - really_destroy(lock); - return; - case 1: - case 0: - // these values are illegal - representing an already unlocked or - // deleted lock - GPR_UNREACHABLE_CODE(return ); - } - } while (maybe_finish_one(exec_ctx, lock)); -} - -static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, - bool success) { - if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); -} - -void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, - grpc_aelock_action action, void *arg, - size_t sizeof_arg) { - gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); - GPR_ASSERT(last & 1); // ensure lock has not been destroyed - if (last == 1) { - action(exec_ctx, arg); - finish(exec_ctx, lock); - } else { - grpc_aelock_qnode *n = gpr_malloc(sizeof(*n) + sizeof_arg); - n->action = action; - if (sizeof_arg > 0) { - memcpy(n + 1, arg, sizeof_arg); - n->arg = n + 1; - } else { - n->arg = arg; - } - gpr_mpscq_push(&lock->queue, &n->mpscq_node); - } -} diff --git a/src/core/lib/iomgr/async_execution_lock.h b/src/core/lib/iomgr/async_execution_lock.h deleted file mode 100644 index e52762f443..0000000000 --- a/src/core/lib/iomgr/async_execution_lock.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * Copyright 2016, 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_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H -#define GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H - -#include - -#include -#include "src/core/lib/iomgr/exec_ctx.h" -#include "src/core/lib/support/mpscq.h" - -typedef struct grpc_aelock grpc_aelock; - -// Provides serialized access to some resource. -// Each action queued on an aelock is executed serially in a borrowed thread. -// The actual thread executing actions may change over time (but there will only -// every be one at a time). - -typedef void (*grpc_aelock_action)(grpc_exec_ctx *exec_ctx, void *arg); - -// Initialize the lock, with an optional workqueue to shift load to when -// necessary -grpc_aelock *grpc_aelock_create(grpc_workqueue *optional_workqueue); -// Destroy the lock -void grpc_aelock_destroy(grpc_aelock *lock); -// Execute \a action within the lock. \a arg is the argument to pass to \a -// action and sizeof_arg is the sizeof(*arg), or 0 if arg is non-copyable. -void grpc_aelock_execute(grpc_exec_ctx *exec_ctx, grpc_aelock *lock, - grpc_aelock_action action, void *arg, - size_t sizeof_arg); - -#endif /* GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H */ diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index 08e59a168e..310fcb1b86 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -37,6 +37,7 @@ #include #include #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/support/mpscq.h" struct grpc_closure; typedef struct grpc_closure grpc_closure; @@ -60,6 +61,14 @@ typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg, /** A closure over a grpc_iomgr_cb_func. */ struct grpc_closure { + /** Once queued, next indicates the next queued closure; before then, scratch + * space */ + union { + grpc_closure *next; + gpr_mpscq_node atm_next; + uintptr_t scratch; + } next_data; + /** Bound callback. */ grpc_iomgr_cb_func cb; @@ -68,13 +77,6 @@ struct grpc_closure { /** Once queued, the result of the closure. Before then: scratch space */ grpc_error *error; - - /** Once queued, next indicates the next queued closure; before then, scratch - * space */ - union { - grpc_closure *next; - uintptr_t scratch; - } next_data; }; /** Initializes \a closure with \a cb and \a cb_arg. */ diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c new file mode 100644 index 0000000000..72e4d0edcb --- /dev/null +++ b/src/core/lib/iomgr/combiner.c @@ -0,0 +1,125 @@ +/* + * + * Copyright 2016, 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/lib/iomgr/combiner.h" + +#include + +#include +#include + +struct grpc_combiner { + grpc_workqueue *optional_workqueue; + gpr_mpscq queue; + // state is: + // lower bit - zero if orphaned + // other bits - number of items queued on the lock + gpr_atm state; + grpc_closure continue_finishing; +}; + +static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); + +grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { + grpc_combiner *lock = gpr_malloc(sizeof(*lock)); + lock->optional_workqueue = optional_workqueue; + gpr_atm_no_barrier_store(&lock->state, 1); + gpr_mpscq_init(&lock->queue); + grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); + return lock; +} + +static void really_destroy(grpc_combiner *lock) { + GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); + gpr_mpscq_destroy(&lock->queue); + gpr_free(lock); +} + +void grpc_combiner_destroy(grpc_combiner *lock) { + if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { + really_destroy(lock); + } +} + +static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); + if (n == NULL) { + // queue is in an inconsistant state: use this as a cue that we should + // go off and do something else for a while (and come back later) + grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, + lock->optional_workqueue); + return false; + } + grpc_closure *cl = (grpc_closure *)n; + grpc_error *error = cl->error; + cl->cb(exec_ctx, cl->cb_arg, error); + GRPC_ERROR_UNREF(error); + return true; +} + +static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + do { + switch (gpr_atm_full_fetch_add(&lock->state, -2)) { + case 3: // had one count, one unorphaned --> unlocked unorphaned + return; + case 2: // and one count, one orphaned --> unlocked and orphaned + really_destroy(lock); + return; + case 1: + case 0: + // these values are illegal - representing an already unlocked or + // deleted lock + GPR_UNREACHABLE_CODE(return ); + } + } while (maybe_finish_one(exec_ctx, lock)); +} + +static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); +} + +void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, + grpc_closure *cl, grpc_error *error) { + gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); + GPR_ASSERT(last & 1); // ensure lock has not been destroyed + if (last == 1) { + cl->cb(exec_ctx, cl->cb_arg, error); + GRPC_ERROR_UNREF(error); + finish(exec_ctx, lock); + } else { + cl->error = error; + gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + } +} diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h new file mode 100644 index 0000000000..cef1611acc --- /dev/null +++ b/src/core/lib/iomgr/combiner.h @@ -0,0 +1,60 @@ +/* + * + * Copyright 2016, 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_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H +#define GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H + +#include + +#include +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/support/mpscq.h" + +typedef struct grpc_combiner grpc_combiner; + +// Provides serialized access to some resource. +// Each action queued on an aelock is executed serially in a borrowed thread. +// The actual thread executing actions may change over time (but there will only +// every be one at a time). + +// Initialize the lock, with an optional workqueue to shift load to when +// necessary +grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); +// Destroy the lock +void grpc_combiner_destroy(grpc_combiner *lock); +// Execute \a action within the lock. \a arg is the argument to pass to \a +// action and sizeof_arg is the sizeof(*arg), or 0 if arg is non-copyable. +void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, + grpc_closure *closure, grpc_error *error); + +#endif /* GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 310851c583..5441af4c66 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -90,8 +90,8 @@ CORE_SOURCE_FILES = [ 'src/core/lib/http/format_request.c', 'src/core/lib/http/httpcli.c', 'src/core/lib/http/parser.c', - 'src/core/lib/iomgr/async_execution_lock.c', 'src/core/lib/iomgr/closure.c', + 'src/core/lib/iomgr/combiner.c', 'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint_pair_posix.c', 'src/core/lib/iomgr/endpoint_pair_windows.c', diff --git a/test/core/iomgr/async_execution_lock_test.c b/test/core/iomgr/async_execution_lock_test.c deleted file mode 100644 index 526913bc3a..0000000000 --- a/test/core/iomgr/async_execution_lock_test.c +++ /dev/null @@ -1,124 +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/lib/iomgr/async_execution_lock.h" - -#include -#include -#include -#include - -#include "test/core/util/test_config.h" - -static void test_no_op(void) { - gpr_log(GPR_DEBUG, "test_no_op"); - grpc_aelock_destroy(grpc_aelock_create(NULL)); -} - -static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value) { - *(bool *)value = true; -} - -static void test_execute_one(void) { - gpr_log(GPR_DEBUG, "test_execute_one"); - - grpc_aelock *lock = grpc_aelock_create(NULL); - bool done = false; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_aelock_execute(&exec_ctx, lock, set_bool_to_true, &done, 0); - grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(done); - grpc_aelock_destroy(lock); -} - -typedef struct { - size_t ctr; - grpc_aelock *lock; -} thd_args; - -typedef struct { - size_t *ctr; - size_t value; -} ex_args; - -static void check_one(grpc_exec_ctx *exec_ctx, void *a) { - ex_args *args = a; - // gpr_log(GPR_DEBUG, "*%p=%d; step %d", args->ctr, *args->ctr, args->value); - GPR_ASSERT(*args->ctr == args->value - 1); - *args->ctr = args->value; -} - -static void execute_many_loop(void *a) { - thd_args *args = a; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - size_t n = 1; - for (size_t i = 0; i < 10; i++) { - for (size_t j = 0; j < 10000; j++) { - ex_args c = {&args->ctr, n++}; - grpc_aelock_execute(&exec_ctx, args->lock, check_one, &c, sizeof(c)); - grpc_exec_ctx_flush(&exec_ctx); - } - gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); - } - grpc_exec_ctx_finish(&exec_ctx); -} - -static void test_execute_many(void) { - gpr_log(GPR_DEBUG, "test_execute_many"); - - grpc_aelock *lock = grpc_aelock_create(NULL); - gpr_thd_id thds[100]; - thd_args ta[GPR_ARRAY_SIZE(thds)]; - for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { - gpr_thd_options options = gpr_thd_options_default(); - gpr_thd_options_set_joinable(&options); - ta[i].ctr = 0; - ta[i].lock = lock; - GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options)); - } - for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { - gpr_thd_join(thds[i]); - } - grpc_aelock_destroy(lock); -} - -int main(int argc, char **argv) { - grpc_test_init(argc, argv); - grpc_init(); - test_no_op(); - test_execute_one(); - test_execute_many(); - grpc_shutdown(); - - return 0; -} diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c new file mode 100644 index 0000000000..090f7be832 --- /dev/null +++ b/test/core/iomgr/combiner_test.c @@ -0,0 +1,129 @@ +/* + * + * 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/lib/iomgr/combiner.h" + +#include +#include +#include +#include + +#include "test/core/util/test_config.h" + +static void test_no_op(void) { + gpr_log(GPR_DEBUG, "test_no_op"); + grpc_combiner_destroy(grpc_combiner_create(NULL)); +} + +static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value, + grpc_error *error) { + *(bool *)value = true; +} + +static void test_execute_one(void) { + gpr_log(GPR_DEBUG, "test_execute_one"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + bool done = false; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_execute(&exec_ctx, lock, + grpc_closure_create(set_bool_to_true, &done), + GRPC_ERROR_NONE); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(done); + grpc_combiner_destroy(lock); +} + +typedef struct { + size_t ctr; + grpc_combiner *lock; +} thd_args; + +typedef struct { + size_t *ctr; + size_t value; +} ex_args; + +static void check_one(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) { + ex_args *args = a; + // gpr_log(GPR_DEBUG, "*%p=%d; step %d", args->ctr, *args->ctr, args->value); + GPR_ASSERT(*args->ctr == args->value - 1); + *args->ctr = args->value; +} + +static void execute_many_loop(void *a) { + thd_args *args = a; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + size_t n = 1; + for (size_t i = 0; i < 10; i++) { + for (size_t j = 0; j < 10000; j++) { + ex_args c = {&args->ctr, n++}; + grpc_combiner_execute(&exec_ctx, args->lock, + grpc_closure_create(check_one, &c), + GRPC_ERROR_NONE); + grpc_exec_ctx_flush(&exec_ctx); + } + gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); + } + grpc_exec_ctx_finish(&exec_ctx); +} + +static void test_execute_many(void) { + gpr_log(GPR_DEBUG, "test_execute_many"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + gpr_thd_id thds[100]; + thd_args ta[GPR_ARRAY_SIZE(thds)]; + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + ta[i].ctr = 0; + ta[i].lock = lock; + GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options)); + } + for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { + gpr_thd_join(thds[i]); + } + grpc_combiner_destroy(lock); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + grpc_init(); + test_no_op(); + test_execute_one(); + test_execute_many(); + grpc_shutdown(); + + return 0; +} diff --git a/test/core/support/mpscq_test.c b/test/core/support/mpscq_test.c index 4357a7c353..0b4bc254e2 100644 --- a/test/core/support/mpscq_test.c +++ b/test/core/support/mpscq_test.c @@ -109,7 +109,7 @@ static void test_mt(void) { if (tn->i == THREAD_ITERATIONS) num_done++; gpr_free(tn); } - gpr_log(GPR_DEBUG, "spins: %d", spins); + gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins); for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_join(thds[i]); } diff --git a/third_party/protobuf b/third_party/protobuf index d4d13a4349..3470b6895a 160000 --- a/third_party/protobuf +++ b/third_party/protobuf @@ -1 +1 @@ -Subproject commit d4d13a4349e4e59d67f311185ddcc1890d956d7a +Subproject commit 3470b6895aa659b7559ed678e029a5338e535f14 diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 8e78adf70f..afae199610 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -887,8 +887,8 @@ src/core/lib/debug/trace.h \ src/core/lib/http/format_request.h \ src/core/lib/http/httpcli.h \ src/core/lib/http/parser.h \ -src/core/lib/iomgr/async_execution_lock.h \ src/core/lib/iomgr/closure.h \ +src/core/lib/iomgr/combiner.h \ src/core/lib/iomgr/endpoint.h \ src/core/lib/iomgr/endpoint_pair.h \ src/core/lib/iomgr/error.h \ @@ -1022,8 +1022,8 @@ src/core/lib/debug/trace.c \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ -src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ +src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 9360febf8b..1a6bca9a4d 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -804,8 +804,8 @@ src/core/lib/debug/trace.h \ src/core/lib/http/format_request.h \ src/core/lib/http/httpcli.h \ src/core/lib/http/parser.h \ -src/core/lib/iomgr/async_execution_lock.h \ src/core/lib/iomgr/closure.h \ +src/core/lib/iomgr/combiner.h \ src/core/lib/iomgr/endpoint.h \ src/core/lib/iomgr/endpoint_pair.h \ src/core/lib/iomgr/error.h \ @@ -960,8 +960,8 @@ src/core/lib/debug/trace.c \ src/core/lib/http/format_request.c \ src/core/lib/http/httpcli.c \ src/core/lib/http/parser.c \ -src/core/lib/iomgr/async_execution_lock.c \ src/core/lib/iomgr/closure.c \ +src/core/lib/iomgr/combiner.c \ src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_windows.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 322d3f3451..0fde7ba084 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -79,22 +79,6 @@ "third_party": false, "type": "target" }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc_test_util" - ], - "headers": [], - "language": "c", - "name": "async_execution_lock_test", - "src": [ - "test/core/iomgr/async_execution_lock_test.c" - ], - "third_party": false, - "type": "target" - }, { "deps": [ "gpr", @@ -252,6 +236,22 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "language": "c", + "name": "combiner_test", + "src": [ + "test/core/iomgr/combiner_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -5737,8 +5737,8 @@ "src/core/lib/http/format_request.h", "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", @@ -5839,10 +5839,10 @@ "src/core/lib/http/httpcli.h", "src/core/lib/http/parser.c", "src/core/lib/http/parser.h", - "src/core/lib/iomgr/async_execution_lock.c", - "src/core/lib/iomgr/async_execution_lock.h", "src/core/lib/iomgr/closure.c", "src/core/lib/iomgr/closure.h", + "src/core/lib/iomgr/combiner.c", + "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint_pair.h", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index f654a7ba8e..fd5ff37389 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -93,12 +93,12 @@ "posix", "windows" ], - "cpu_cost": 30, + "cpu_cost": 1.0, "exclude_configs": [], "flaky": false, "gtest": false, "language": "c", - "name": "async_execution_lock_test", + "name": "bad_server_response_test", "platforms": [ "linux", "mac", @@ -119,7 +119,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "bad_server_response_test", + "name": "bin_decoder_test", "platforms": [ "linux", "mac", @@ -140,7 +140,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "bin_decoder_test", + "name": "bin_encoder_test", "platforms": [ "linux", "mac", @@ -161,7 +161,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "bin_encoder_test", + "name": "census_context_test", "platforms": [ "linux", "mac", @@ -182,7 +182,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "census_context_test", + "name": "channel_create_test", "platforms": [ "linux", "mac", @@ -203,7 +203,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "channel_create_test", + "name": "chttp2_hpack_encoder_test", "platforms": [ "linux", "mac", @@ -224,7 +224,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "chttp2_hpack_encoder_test", + "name": "chttp2_status_conversion_test", "platforms": [ "linux", "mac", @@ -245,7 +245,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "chttp2_status_conversion_test", + "name": "chttp2_stream_map_test", "platforms": [ "linux", "mac", @@ -266,7 +266,7 @@ "flaky": false, "gtest": false, "language": "c", - "name": "chttp2_stream_map_test", + "name": "chttp2_varint_test", "platforms": [ "linux", "mac", @@ -282,12 +282,12 @@ "posix", "windows" ], - "cpu_cost": 1.0, + "cpu_cost": 30, "exclude_configs": [], "flaky": false, "gtest": false, "language": "c", - "name": "chttp2_varint_test", + "name": "combiner_test", "platforms": [ "linux", "mac", diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index c3638685a8..c28ad2fc31 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -45,17 +45,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alpn_test", "vcxproj\test\a {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "async_execution_lock_test", "vcxproj\test\async_execution_lock_test\async_execution_lock_test.vcxproj", "{5FC080AE-1FE8-2849-6481-E52ADBBC205C}" - ProjectSection(myProperties) = preProject - lib = "False" - EndProjectSection - ProjectSection(ProjectDependencies) = postProject - {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} - {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} - {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} - {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bad_client_test", "vcxproj\test/bad_client\bad_client_test\bad_client_test.vcxproj", "{BA67B418-B699-E41A-9CC4-0279C49481A5}" ProjectSection(myProperties) = preProject lib = "True" @@ -175,6 +164,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chttp2_varint_test", "vcxpr {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "combiner_test", "vcxproj\test\combiner_test\combiner_test.vcxproj", "{C237D1E4-8825-80BA-1FC3-5E147E53E96E}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compression_test", "vcxproj\test\compression_test\compression_test.vcxproj", "{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}" ProjectSection(myProperties) = preProject lib = "False" @@ -1523,22 +1523,6 @@ Global {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|Win32.Build.0 = Release|Win32 {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|x64.ActiveCfg = Release|x64 {5BAAE7EA-A972-DD80-F190-29B9E3110BB3}.Release-DLL|x64.Build.0 = Release|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|Win32.ActiveCfg = Debug|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|x64.ActiveCfg = Debug|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|Win32.ActiveCfg = Release|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|x64.ActiveCfg = Release|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|Win32.Build.0 = Debug|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug|x64.Build.0 = Debug|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|Win32.Build.0 = Release|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release|x64.Build.0 = Release|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|Win32.Build.0 = Debug|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|x64.ActiveCfg = Debug|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Debug-DLL|x64.Build.0 = Debug|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|Win32.ActiveCfg = Release|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|Win32.Build.0 = Release|Win32 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|x64.ActiveCfg = Release|x64 - {5FC080AE-1FE8-2849-6481-E52ADBBC205C}.Release-DLL|x64.Build.0 = Release|x64 {BA67B418-B699-E41A-9CC4-0279C49481A5}.Debug|Win32.ActiveCfg = Debug|Win32 {BA67B418-B699-E41A-9CC4-0279C49481A5}.Debug|x64.ActiveCfg = Debug|x64 {BA67B418-B699-E41A-9CC4-0279C49481A5}.Release|Win32.ActiveCfg = Release|Win32 @@ -1715,6 +1699,22 @@ Global {6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|Win32.Build.0 = Release|Win32 {6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|x64.ActiveCfg = Release|x64 {6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|x64.Build.0 = Release|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|Win32.ActiveCfg = Debug|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|x64.ActiveCfg = Debug|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|Win32.ActiveCfg = Release|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|x64.ActiveCfg = Release|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|Win32.Build.0 = Debug|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|x64.Build.0 = Debug|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|Win32.Build.0 = Release|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|x64.Build.0 = Release|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|x64.Build.0 = Debug|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|Win32.Build.0 = Release|Win32 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|x64.ActiveCfg = Release|x64 + {C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|x64.Build.0 = Release|x64 {5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Debug|Win32.ActiveCfg = Debug|Win32 {5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Debug|x64.ActiveCfg = Debug|x64 {5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj index d299686eae..bc6642bdb1 100644 --- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj +++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj @@ -387,8 +387,8 @@ - + @@ -569,10 +569,10 @@ - - + + diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters index 0a13d21893..2354d68748 100644 --- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters +++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters @@ -136,10 +136,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr @@ -836,10 +836,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj index b20d46475b..6af4759449 100644 --- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj @@ -383,8 +383,8 @@ - + @@ -555,10 +555,10 @@ - - + + diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters index d12e3c7306..6985a1562c 100644 --- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters @@ -121,10 +121,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr @@ -809,10 +809,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 55f8fe85e2..e44299007e 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -313,8 +313,8 @@ - + @@ -485,10 +485,10 @@ - - + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 46b5710305..82a8ffb40a 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -43,10 +43,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr @@ -698,10 +698,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 3e0aac4622..b993c9bdf7 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -302,8 +302,8 @@ - + @@ -452,10 +452,10 @@ - - + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index c922e48f61..4b0a7a01cd 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -46,10 +46,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr @@ -605,10 +605,10 @@ src\core\lib\http - + src\core\lib\iomgr - + src\core\lib\iomgr diff --git a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj deleted file mode 100644 index 92b277801e..0000000000 --- a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {5FC080AE-1FE8-2849-6481-E52ADBBC205C} - true - $(SolutionDir)IntDir\$(MSBuildProjectName)\ - - - - v100 - - - v110 - - - v120 - - - v140 - - - Application - true - Unicode - - - Application - false - true - Unicode - - - - - - - - - - - - - - async_execution_lock_test - static - Debug - static - Debug - - - async_execution_lock_test - static - Release - static - Release - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreadedDebug - true - None - false - - - Console - true - false - - - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) - true - MultiThreadedDebug - true - None - false - - - Console - true - false - - - - - - NotUsing - Level3 - MaxSpeed - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - true - true - MultiThreaded - true - None - false - - - Console - true - false - true - true - - - - - - NotUsing - Level3 - MaxSpeed - WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) - true - true - true - MultiThreaded - true - None - false - - - Console - true - false - true - true - - - - - - - - - - {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} - - - {29D16885-7228-4C31-81ED-5F9187C7F2A9} - - - {EAB0A629-17A9-44DB-B5FF-E91A721FE037} - - - {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - diff --git a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters b/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters deleted file mode 100644 index ff116cb9b0..0000000000 --- a/vsprojects/vcxproj/test/async_execution_lock_test/async_execution_lock_test.vcxproj.filters +++ /dev/null @@ -1,21 +0,0 @@ - - - - - test\core\iomgr - - - - - - {1553c040-57a4-1c71-539f-06be026b4844} - - - {112c4757-8861-21ed-d535-83c90a22e14b} - - - {341d4313-1479-2a6a-8ba4-a44c4c15e0d7} - - - - diff --git a/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj new file mode 100644 index 0000000000..f889d21e2d --- /dev/null +++ b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C237D1E4-8825-80BA-1FC3-5E147E53E96E} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + combiner_test + static + Debug + static + Debug + + + combiner_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters new file mode 100644 index 0000000000..e8ebb09898 --- /dev/null +++ b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\iomgr + + + + + + {82bca2af-d499-b405-fd05-4d345372496c} + + + {c32d8e20-b719-532d-ba23-bd9d523fac15} + + + {b4fa8ca1-e6c7-dec5-6d62-8a62396825c6} + + + + -- cgit v1.2.3 From 09df1d6e6591edadd8346f56267ced5211ddde7d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Jul 2016 22:33:23 -0700 Subject: Make workqueue lockfree, and distributing --- src/core/lib/iomgr/combiner.h | 3 +- src/core/lib/iomgr/workqueue.h | 2 - src/core/lib/iomgr/workqueue_posix.c | 74 +++++++++++++++++++++++----------- src/core/lib/iomgr/workqueue_posix.h | 9 +++-- src/core/lib/iomgr/workqueue_windows.c | 2 - 5 files changed, 57 insertions(+), 33 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index cef1611acc..d16ce3d0f6 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -52,8 +52,7 @@ typedef struct grpc_combiner grpc_combiner; grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); // Destroy the lock void grpc_combiner_destroy(grpc_combiner *lock); -// Execute \a action within the lock. \a arg is the argument to pass to \a -// action and sizeof_arg is the sizeof(*arg), or 0 if arg is non-copyable. +// Execute \a action within the lock. void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h index 9f7219ebf1..416618e258 100644 --- a/src/core/lib/iomgr/workqueue.h +++ b/src/core/lib/iomgr/workqueue.h @@ -50,8 +50,6 @@ /* grpc_workqueue is forward declared in exec_ctx.h */ -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); - //#define GRPC_WORKQUEUE_REFCOUNT_DEBUG #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #define GRPC_WORKQUEUE_REF(p, r) \ diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index e0d6dac230..1d52a91694 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -52,8 +52,7 @@ grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, char name[32]; *workqueue = gpr_malloc(sizeof(grpc_workqueue)); gpr_ref_init(&(*workqueue)->refs, 1); - gpr_mu_init(&(*workqueue)->mu); - (*workqueue)->closure_list.head = (*workqueue)->closure_list.tail = NULL; + gpr_atm_no_barrier_store(&(*workqueue)->state, 1); grpc_error *err = grpc_wakeup_fd_init(&(*workqueue)->wakeup_fd); if (err != GRPC_ERROR_NONE) { gpr_free(*workqueue); @@ -62,6 +61,7 @@ grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, sprintf(name, "workqueue:%p", (void *)(*workqueue)); (*workqueue)->wakeup_read_fd = grpc_fd_create( GRPC_WAKEUP_FD_GET_READ_FD(&(*workqueue)->wakeup_fd), name); + gpr_mpscq_init(&(*workqueue)->queue); grpc_closure_init(&(*workqueue)->read_closure, on_readable, *workqueue); grpc_fd_notify_on_read(exec_ctx, (*workqueue)->wakeup_read_fd, &(*workqueue)->read_closure); @@ -70,10 +70,16 @@ grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, static void workqueue_destroy(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd); } +static void workqueue_orphan(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue) { + if (gpr_atm_full_fetch_add(&workqueue->state, -1) == 1) { + workqueue_destroy(exec_ctx, workqueue); + } +} + #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, const char *reason) { @@ -96,31 +102,34 @@ void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { #endif if (gpr_unref(&workqueue->refs)) { - workqueue_destroy(exec_ctx, workqueue); + workqueue_orphan(exec_ctx, workqueue); } } -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - gpr_mu_lock(&workqueue->mu); - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); - gpr_mu_unlock(&workqueue->mu); +static void drain(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + abort(); +} + +static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + grpc_error *err = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); + if (!GRPC_LOG_IF_ERROR("wakeupfd_wakeup", err)) { + drain(exec_ctx, workqueue); + } } static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_workqueue *workqueue = arg; if (error != GRPC_ERROR_NONE) { - gpr_mu_destroy(&workqueue->mu); /* HACK: let wakeup_fd code know that we stole the fd */ workqueue->wakeup_fd.read_fd = 0; grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); + drain(exec_ctx, workqueue); gpr_free(workqueue); } else { - gpr_mu_lock(&workqueue->mu); - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); - gpr_mu_unlock(&workqueue->mu); + gpr_mpscq_node *n = gpr_mpscq_pop(&workqueue->queue); if (error == GRPC_ERROR_NONE) { grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, &workqueue->read_closure); @@ -128,24 +137,41 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { /* recurse to get error handling */ on_readable(exec_ctx, arg, error); } + if (n == NULL) { + /* try again - queue in an inconsistant state */ + wakeup(exec_ctx, workqueue); + } else { + switch (gpr_atm_full_fetch_add(&workqueue->state, -2)) { + case 3: // had one count, one unorphaned --> done, unorphaned + break; + case 2: // had one count, one orphaned --> done, orphaned + workqueue_destroy(exec_ctx, workqueue); + break; + case 1: + case 0: + // these values are illegal - representing an already done or + // deleted workqueue + GPR_UNREACHABLE_CODE(break); + default: + // schedule a wakeup since there's more to do + wakeup(exec_ctx, workqueue); + } + grpc_closure *cl = (grpc_closure *)n; + grpc_error *clerr = cl->error; + cl->cb(exec_ctx, cl->cb_arg, clerr); + GRPC_ERROR_UNREF(clerr); + } } } void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, grpc_closure *closure, grpc_error *error) { - grpc_error *push_error = GRPC_ERROR_NONE; - gpr_mu_lock(&workqueue->mu); - if (grpc_closure_list_empty(workqueue->closure_list)) { - push_error = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); - } - grpc_closure_list_append(&workqueue->closure_list, closure, error); - if (push_error != GRPC_ERROR_NONE) { - const char *msg = grpc_error_string(push_error); - gpr_log(GPR_ERROR, "Failed to push to workqueue: %s", msg); - grpc_error_free_string(msg); - grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); + gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, 2); + GPR_ASSERT(last & 1); + gpr_mpscq_push(&workqueue->queue, &closure->next_data.atm_next); + if (last == 1) { + wakeup(exec_ctx, workqueue); } - gpr_mu_unlock(&workqueue->mu); } #endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/core/lib/iomgr/workqueue_posix.h index 2e8aca1816..c69ae8a941 100644 --- a/src/core/lib/iomgr/workqueue_posix.h +++ b/src/core/lib/iomgr/workqueue_posix.h @@ -35,14 +35,17 @@ #define GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H #include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/support/mpscq.h" struct grpc_fd; struct grpc_workqueue { gpr_refcount refs; - - gpr_mu mu; - grpc_closure_list closure_list; + gpr_mpscq queue; + // state is: + // lower bit - zero if orphaned + // other bits - number of items enqueued + gpr_atm state; grpc_wakeup_fd wakeup_fd; struct grpc_fd *wakeup_read_fd; diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c index 23e2dea185..ee81dc248e 100644 --- a/src/core/lib/iomgr/workqueue_windows.c +++ b/src/core/lib/iomgr/workqueue_windows.c @@ -42,8 +42,6 @@ // context, which is at least correct, if not performant or in the spirit of // workqueues. -void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {} - #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, const char *reason) {} -- cgit v1.2.3 From ece4aaf578ac61e07b0a9a30a50b88425cdb7e25 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Jul 2016 22:35:23 -0700 Subject: Fix header --- src/core/lib/iomgr/combiner.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index d16ce3d0f6..a3f75d48cf 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -31,8 +31,8 @@ * */ -#ifndef GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H -#define GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H +#ifndef GRPC_CORE_LIB_IOMGR_COMBINER_H +#define GRPC_CORE_LIB_IOMGR_COMBINER_H #include @@ -56,4 +56,4 @@ void grpc_combiner_destroy(grpc_combiner *lock); void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); -#endif /* GRPC_CORE_LIB_IOMGR_ASYNC_EXECUTION_LOCK_H */ +#endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ -- cgit v1.2.3 From a36857da24b126300234f86450a61b7b2a7d0daa Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 8 Jul 2016 16:57:42 -0700 Subject: Progress on a finalization list --- src/core/lib/iomgr/closure.h | 2 ++ src/core/lib/iomgr/combiner.c | 76 +++++++++++++++++++++++++++++++++++------ src/core/lib/iomgr/combiner.h | 8 +++++ test/core/iomgr/combiner_test.c | 14 ++++++++ 4 files changed, 90 insertions(+), 10 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index 310fcb1b86..c1a22b6021 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -89,6 +89,8 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg); #define GRPC_CLOSURE_LIST_INIT \ { NULL, NULL } +void grpc_closure_list_init(grpc_closure_list *list); + /** add \a closure to the end of \a list and set \a closure's result to \a error */ void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure, diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 72e4d0edcb..00799e88c5 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -45,18 +45,18 @@ struct grpc_combiner { // lower bit - zero if orphaned // other bits - number of items queued on the lock gpr_atm state; + bool take_async_break_before_final_list; + grpc_closure_list final_list; grpc_closure continue_finishing; }; -static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); - grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { grpc_combiner *lock = gpr_malloc(sizeof(*lock)); lock->optional_workqueue = optional_workqueue; gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); - grpc_closure_init(&lock->continue_finishing, continue_finishing, lock); + lock->take_async_break_before_final_list = false; + grpc_closure_list_init(&lock->final_list); return lock; } @@ -72,11 +72,52 @@ void grpc_combiner_destroy(grpc_combiner *lock) { } } +static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); +static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); + +static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); +} + +static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + grpc_closure *c = lock->final_list.head; + grpc_closure_list_init(&lock->final_list); + while (c != NULL) { + grpc_closure *next = c->next_data.next; + grpc_error *error = c->error; + c->cb(exec_ctx, c->cb_arg, error); + GRPC_ERROR_UNREF(error); + c = next; + } +} + +static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + execute_final(exec_ctx, arg); + finish(exec_ctx, arg); +} + +static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + if (lock->take_async_break_before_final_list) { + grpc_closure_init(&lock->continue_finishing, continue_executing_final, + lock); + grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, + lock->optional_workqueue); + return false; + } else { + execute_final(exec_ctx, lock); + return true; + } +} + static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); if (n == NULL) { // queue is in an inconsistant state: use this as a cue that we should // go off and do something else for a while (and come back later) + grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, + lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, lock->optional_workqueue); return false; @@ -89,8 +130,16 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + bool (*executor)(grpc_exec_ctx * exec_ctx, grpc_combiner * lock) = + maybe_finish_one; do { switch (gpr_atm_full_fetch_add(&lock->state, -2)) { + case 5: // we're down to one queued item: if it's the final list we + case 4: // should do that + if (!grpc_closure_list_empty(lock->final_list)) { + executor = start_execute_final; + } + break; case 3: // had one count, one unorphaned --> unlocked unorphaned return; case 2: // and one count, one orphaned --> unlocked and orphaned @@ -102,12 +151,7 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { // deleted lock GPR_UNREACHABLE_CODE(return ); } - } while (maybe_finish_one(exec_ctx, lock)); -} - -static void continue_finishing(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); + } while (executor(exec_ctx, lock)); } void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, @@ -123,3 +167,15 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); } } + +void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, + grpc_closure *closure, grpc_error *error, + bool force_async_break) { + if (force_async_break) { + lock->take_async_break_before_final_list = true; + } + if (grpc_closure_list_empty(lock->final_list)) { + gpr_atm_full_fetch_add(&lock->state, 2); + } + grpc_closure_list_append(&lock->final_list, closure, error); +} diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index a3f75d48cf..d6bc27111f 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -55,5 +55,13 @@ void grpc_combiner_destroy(grpc_combiner *lock); // Execute \a action within the lock. void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); +// Execute \a action within the lock just prior to unlocking. +// if \a force_async_break is additionally set, the combiner is forced to trip +// through the workqueue between finishing the primary queue of combined +// closures and executing the finally list. +// Can only be called from within a closure scheduled by grpc_combiner_execute +void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, + grpc_closure *closure, grpc_error *error, + bool force_async_break); #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c index 925a4f81ad..d9f7601722 100644 --- a/test/core/iomgr/combiner_test.c +++ b/test/core/iomgr/combiner_test.c @@ -120,12 +120,26 @@ static void test_execute_many(void) { grpc_combiner_destroy(lock); } +static void test_execute_finally(void) { + gpr_log(GPR_DEBUG, "test_execute_finally"); + + grpc_combiner *lock = grpc_combiner_create(NULL); + bool done = false; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock), + GRPC_ERROR_NONE); + grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(done); + grpc_combiner_destroy(lock); +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); grpc_init(); test_no_op(); test_execute_one(); test_execute_many(); + test_execute_finally(); grpc_shutdown(); return 0; -- cgit v1.2.3 From 8d8d0d3d10709fe3413f5112531d89a5531203e7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 8 Jul 2016 17:08:57 -0700 Subject: Get combiner finalization lists working --- src/core/lib/iomgr/closure.c | 4 ++++ test/core/iomgr/combiner_test.c | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c index 0b6c3b2539..1ba0a5c141 100644 --- a/src/core/lib/iomgr/closure.c +++ b/src/core/lib/iomgr/closure.c @@ -41,6 +41,10 @@ void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, closure->cb_arg = cb_arg; } +void grpc_closure_list_init(grpc_closure_list *closure_list) { + closure_list->head = closure_list->tail = NULL; +} + void grpc_closure_list_append(grpc_closure_list *closure_list, grpc_closure *closure, grpc_error *error) { if (closure == NULL) { diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c index d9f7601722..0aaeada345 100644 --- a/test/core/iomgr/combiner_test.c +++ b/test/core/iomgr/combiner_test.c @@ -120,16 +120,27 @@ static void test_execute_many(void) { grpc_combiner_destroy(lock); } +static bool got_in_finally = false; + +static void in_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + got_in_finally = true; +} + +static void add_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_combiner_execute_finally(exec_ctx, arg, + grpc_closure_create(in_finally, NULL), + GRPC_ERROR_NONE, false); +} + static void test_execute_finally(void) { gpr_log(GPR_DEBUG, "test_execute_finally"); grpc_combiner *lock = grpc_combiner_create(NULL); - bool done = false; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock), GRPC_ERROR_NONE); grpc_exec_ctx_finish(&exec_ctx); - GPR_ASSERT(done); + GPR_ASSERT(got_in_finally); grpc_combiner_destroy(lock); } @@ -138,8 +149,8 @@ int main(int argc, char **argv) { grpc_init(); test_no_op(); test_execute_one(); - test_execute_many(); test_execute_finally(); + test_execute_many(); grpc_shutdown(); return 0; -- cgit v1.2.3 From 6e7b45ed215fe113abed17002fddf5635c97549c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 8 Jul 2016 17:25:49 -0700 Subject: Make transport_stream_ops all be heap allocated --- src/core/lib/channel/channel_stack.c | 23 +++++--- src/core/lib/channel/compress_filter.c | 14 ++--- .../lib/security/transport/server_auth_filter.c | 27 ++++++---- src/core/lib/surface/call.c | 63 +++++++++++----------- 4 files changed, 71 insertions(+), 56 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c index 87175d7943..e1375348a9 100644 --- a/src/core/lib/channel/channel_stack.c +++ b/src/core/lib/channel/channel_stack.c @@ -32,6 +32,7 @@ */ #include "src/core/lib/channel/channel_stack.h" +#include #include #include @@ -259,21 +260,27 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) { sizeof(grpc_call_stack))); } +static void destroy_op(grpc_exec_ctx *exec_ctx, void *op, grpc_error *error) { + gpr_free(op); +} + void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx, grpc_call_element *cur_elem) { - grpc_transport_stream_op op; - memset(&op, 0, sizeof(op)); - op.cancel_error = GRPC_ERROR_CANCELLED; - grpc_call_next_op(exec_ctx, cur_elem, &op); + grpc_transport_stream_op *op = gpr_malloc(sizeof(*op)); + memset(op, 0, sizeof(*op)); + op->cancel_error = GRPC_ERROR_CANCELLED; + op->on_complete = grpc_closure_create(destroy_op, op); + grpc_call_next_op(exec_ctx, cur_elem, op); } void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx, grpc_call_element *cur_elem, grpc_status_code status, gpr_slice *optional_message) { - grpc_transport_stream_op op; - memset(&op, 0, sizeof(op)); - grpc_transport_stream_op_add_cancellation_with_message(&op, status, + grpc_transport_stream_op *op = gpr_malloc(sizeof(*op)); + memset(op, 0, sizeof(*op)); + op->on_complete = grpc_closure_create(destroy_op, op); + grpc_transport_stream_op_add_cancellation_with_message(op, status, optional_message); - grpc_call_next_op(exec_ctx, cur_elem, &op); + grpc_call_next_op(exec_ctx, cur_elem, op); } diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c index 32ebe53ee6..d4b1cf0296 100644 --- a/src/core/lib/channel/compress_filter.c +++ b/src/core/lib/channel/compress_filter.c @@ -60,7 +60,7 @@ typedef struct call_data { /** If true, contents of \a compression_algorithm are authoritative */ int has_compression_algorithm; - grpc_transport_stream_op send_op; + grpc_transport_stream_op *send_op; uint32_t send_length; uint32_t send_flags; gpr_slice incoming_slice; @@ -199,11 +199,11 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx, grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, calld->send_flags); - calld->send_op.send_message = &calld->replacement_stream.base; - calld->post_send = calld->send_op.on_complete; - calld->send_op.on_complete = &calld->send_done; + calld->send_op->send_message = &calld->replacement_stream.base; + calld->post_send = calld->send_op->on_complete; + calld->send_op->on_complete = &calld->send_done; - grpc_call_next_op(exec_ctx, elem, &calld->send_op); + grpc_call_next_op(exec_ctx, elem, calld->send_op); } static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { @@ -220,7 +220,7 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { static void continue_send_message(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; - while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message, + while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message, &calld->incoming_slice, ~(size_t)0, &calld->got_slice)) { gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); @@ -243,7 +243,7 @@ static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx, } if (op->send_message != NULL && !skip_compression(elem) && 0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) { - calld->send_op = *op; + calld->send_op = op; calld->send_length = op->send_message->length; calld->send_flags = op->send_message->flags; continue_send_message(exec_ctx, elem); diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c index 12e789bde9..1958a72b93 100644 --- a/src/core/lib/security/transport/server_auth_filter.c +++ b/src/core/lib/security/transport/server_auth_filter.c @@ -48,7 +48,7 @@ typedef struct call_data { up-call on transport_op, and remember to call our on_done_recv member after handling it. */ grpc_closure auth_on_recv; - grpc_transport_stream_op transport_op; + grpc_transport_stream_op *transport_op; grpc_metadata_array md; const grpc_metadata *consumed_md; size_t num_consumed_md; @@ -106,6 +106,10 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { return md; } +static void destroy_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + gpr_free(arg); +} + /* called from application code */ static void on_md_processing_done( void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, @@ -131,21 +135,22 @@ static void on_md_processing_done( grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL); } else { gpr_slice message; - grpc_transport_stream_op close_op; - memset(&close_op, 0, sizeof(close_op)); + grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op)); + memset(close_op, 0, sizeof(*close_op)); grpc_metadata_array_destroy(&calld->md); error_details = error_details != NULL ? error_details : "Authentication metadata processing failed."; message = gpr_slice_from_copied_string(error_details); - calld->transport_op.send_initial_metadata = NULL; - if (calld->transport_op.send_message != NULL) { - grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message); - calld->transport_op.send_message = NULL; + calld->transport_op->send_initial_metadata = NULL; + if (calld->transport_op->send_message != NULL) { + grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message); + calld->transport_op->send_message = NULL; } - calld->transport_op.send_trailing_metadata = NULL; - grpc_transport_stream_op_add_close(&close_op, status, &message); - grpc_call_next_op(&exec_ctx, elem, &close_op); + calld->transport_op->send_trailing_metadata = NULL; + close_op->on_complete = grpc_closure_create(destroy_op, close_op); + grpc_transport_stream_op_add_close(close_op, status, &message); + grpc_call_next_op(&exec_ctx, elem, close_op); grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, grpc_error_set_int(GRPC_ERROR_CREATE(error_details), GRPC_ERROR_INT_GRPC_STATUS, status), @@ -182,7 +187,7 @@ static void set_recv_ops_md_callbacks(grpc_call_element *elem, calld->recv_initial_metadata = op->recv_initial_metadata; calld->on_done_recv = op->recv_initial_metadata_ready; op->recv_initial_metadata_ready = &calld->auth_on_recv; - calld->transport_op = *op; + calld->transport_op = op; } } diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index e5668be47f..7739a395b9 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -109,6 +109,10 @@ typedef struct batch_control { uint8_t recv_message; uint8_t recv_final_op; uint8_t is_notify_tag_closure; + + /* TODO(ctiller): now that this is inlined, figure out how much of the above + state can be eliminated */ + grpc_transport_stream_op op; } batch_control; struct grpc_call { @@ -761,6 +765,7 @@ typedef struct termination_closure { grpc_error *error; grpc_closure *op_closure; enum { TC_CANCEL, TC_CLOSE } type; + grpc_transport_stream_op op; } termination_closure; static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp, @@ -780,26 +785,24 @@ static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp, } static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) { - grpc_transport_stream_op op; termination_closure *tc = tcp; - memset(&op, 0, sizeof(op)); - op.cancel_error = tc->error; + memset(&tc->op, 0, sizeof(tc->op)); + tc->op.cancel_error = tc->error; /* reuse closure to catch completion */ grpc_closure_init(&tc->closure, done_termination, tc); - op.on_complete = &tc->closure; - execute_op(exec_ctx, tc->call, &op); + tc->op.on_complete = &tc->closure; + execute_op(exec_ctx, tc->call, &tc->op); } static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) { - grpc_transport_stream_op op; termination_closure *tc = tcp; - memset(&op, 0, sizeof(op)); - op.close_error = tc->error; + memset(&tc->op, 0, sizeof(tc->op)); + tc->op.close_error = tc->error; /* reuse closure to catch completion */ grpc_closure_init(&tc->closure, done_termination, tc); - tc->op_closure = op.on_complete; - op.on_complete = &tc->closure; - execute_op(exec_ctx, tc->call, &op); + tc->op_closure = tc->op.on_complete; + tc->op.on_complete = &tc->closure; + execute_op(exec_ctx, tc->call, &tc->op); } static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx, @@ -1353,7 +1356,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, grpc_call *call, const grpc_op *ops, size_t nops, void *notify_tag, int is_notify_tag_closure) { - grpc_transport_stream_op stream_op; size_t i; const grpc_op *op; batch_control *bctl; @@ -1364,8 +1366,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag); - memset(&stream_op, 0, sizeof(stream_op)); - /* TODO(ctiller): this feels like it could be made lock-free */ gpr_mu_lock(&call->mu); bctl = allocate_batch_control(call); @@ -1374,6 +1374,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, bctl->notify_tag = notify_tag; bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0); + grpc_transport_stream_op *stream_op = &bctl->op; + memset(stream_op, 0, sizeof(*stream_op)); + if (nops == 0) { GRPC_CALL_INTERNAL_REF(call, "completion"); bctl->error = GRPC_ERROR_NONE; @@ -1452,9 +1455,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, } /* TODO(ctiller): just make these the same variable? */ call->metadata_batch[0][0].deadline = call->send_deadline; - stream_op.send_initial_metadata = + stream_op->send_initial_metadata = &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]; - stream_op.send_initial_metadata_flags = op->flags; + stream_op->send_initial_metadata_flags = op->flags; break; case GRPC_OP_SEND_MESSAGE: if (!are_write_flags_valid(op->flags)) { @@ -1474,7 +1477,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, grpc_slice_buffer_stream_init( &call->sending_stream, &op->data.send_message->data.raw.slice_buffer, op->flags); - stream_op.send_message = &call->sending_stream.base; + stream_op->send_message = &call->sending_stream.base; break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: /* Flag validation: currently allow no flags */ @@ -1492,7 +1495,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, } bctl->send_final_op = 1; call->sent_final_op = 1; - stream_op.send_trailing_metadata = + stream_op->send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; break; case GRPC_OP_SEND_STATUS_FROM_SERVER: @@ -1539,7 +1542,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } - stream_op.send_trailing_metadata = + stream_op->send_trailing_metadata = &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]; break; case GRPC_OP_RECV_INITIAL_METADATA: @@ -1557,9 +1560,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, grpc_closure_init(&call->receiving_initial_metadata_ready, receiving_initial_metadata_ready, bctl); bctl->recv_initial_metadata = 1; - stream_op.recv_initial_metadata = + stream_op->recv_initial_metadata = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; - stream_op.recv_initial_metadata_ready = + stream_op->recv_initial_metadata_ready = &call->receiving_initial_metadata_ready; num_completion_callbacks_needed++; break; @@ -1576,10 +1579,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, call->receiving_message = 1; bctl->recv_message = 1; call->receiving_buffer = op->data.recv_message; - stream_op.recv_message = &call->receiving_stream; + stream_op->recv_message = &call->receiving_stream; grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready, bctl); - stream_op.recv_message_ready = &call->receiving_stream_ready; + stream_op->recv_message_ready = &call->receiving_stream_ready; num_completion_callbacks_needed++; break; case GRPC_OP_RECV_STATUS_ON_CLIENT: @@ -1605,9 +1608,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, call->final_op.client.status_details_capacity = op->data.recv_status_on_client.status_details_capacity; bctl->recv_final_op = 1; - stream_op.recv_trailing_metadata = + stream_op->recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op.collect_stats = &call->stats.transport_stream_stats; + stream_op->collect_stats = &call->stats.transport_stream_stats; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: /* Flag validation: currently allow no flags */ @@ -1627,9 +1630,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, call->final_op.server.cancelled = op->data.recv_close_on_server.cancelled; bctl->recv_final_op = 1; - stream_op.recv_trailing_metadata = + stream_op->recv_trailing_metadata = &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */]; - stream_op.collect_stats = &call->stats.transport_stream_stats; + stream_op->collect_stats = &call->stats.transport_stream_stats; break; } } @@ -1640,12 +1643,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, } gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed); - stream_op.context = call->context; + stream_op->context = call->context; grpc_closure_init(&bctl->finish_batch, finish_batch, bctl); - stream_op.on_complete = &bctl->finish_batch; + stream_op->on_complete = &bctl->finish_batch; gpr_mu_unlock(&call->mu); - execute_op(exec_ctx, call, &stream_op); + execute_op(exec_ctx, call, stream_op); done: GPR_TIMER_END("grpc_call_start_batch", 0); -- cgit v1.2.3 From 4e43685e511a1a3c19ac4060a8ee9f7894dea94d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 10 Jul 2016 14:01:50 -0700 Subject: Afford other threads the opportunity to insert into a combiner prior to the final list being executed but after the async pause --- src/core/lib/iomgr/combiner.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 00799e88c5..34e8f43905 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -83,6 +83,7 @@ static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { grpc_closure *c = lock->final_list.head; grpc_closure_list_init(&lock->final_list); + lock->take_async_break_before_final_list = false; while (c != NULL) { grpc_closure *next = c->next_data.next; grpc_error *error = c->error; @@ -94,8 +95,15 @@ static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - execute_final(exec_ctx, arg); - finish(exec_ctx, arg); + grpc_combiner *lock = arg; + // quick peek to see if new things have turned up on the queue: if so, go back + // to executing them before the final list + if ((gpr_atm_acq_load(&lock->state) >> 1) > 1) { + if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); + } else { + execute_final(exec_ctx, lock); + finish(exec_ctx, lock); + } } static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { -- cgit v1.2.3 From 93023e410b0ab351a9a4bb6312327f18d5fa4b68 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Jul 2016 12:43:23 -0700 Subject: Progress to converting chttp2 to combiner locks --- .../transport/chttp2/transport/chttp2_transport.c | 612 +++++++-------------- src/core/ext/transport/chttp2/transport/internal.h | 46 +- src/core/lib/iomgr/combiner.c | 4 + src/core/lib/iomgr/combiner.h | 1 + src/core/lib/transport/transport.h | 17 + 5 files changed, 245 insertions(+), 435 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 41506094de..a3020236cf 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -31,6 +31,9 @@ * */ +// TODO(ctiller): schedule check_read_ops whenever something is added to that +// list + #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include @@ -89,8 +92,14 @@ static const grpc_transport_vtable vtable; static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void initiate_writing(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); +static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void initiate_writing_locked(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); +static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); static void end_waiting_for_write(grpc_exec_ctx *exec_ctx, @@ -104,11 +113,6 @@ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error); -/** Perform a transport_op */ -static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, void *transport_op); - /** Cancel a stream: coming from the transport API */ static void cancel_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, @@ -120,22 +124,10 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream_global *stream_global, grpc_error *error); -/** Add endpoint from this transport to pollset */ -static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_ignored, void *pollset); -static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_ignored, - void *pollset_set); - /** Start new streams that have been created if we can */ static void maybe_start_some_streams( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global); -static void finish_global_actions(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t); - static void connectivity_state_set( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_connectivity_state state, grpc_error *error, const char *reason); @@ -148,9 +140,8 @@ static void incoming_byte_stream_update_flow_control( grpc_chttp2_stream_global *stream_global, size_t max_size_hint, size_t have_already); static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *byte_stream); + void *byte_stream, + grpc_error *error_ignored); static void fail_pending_writes(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, @@ -164,9 +155,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { size_t i; - gpr_mu_lock(&t->executor.mu); - - GPR_ASSERT(t->ep == NULL); + grpc_endpoint_destroy(exec_ctx, t->ep); gpr_slice_buffer_destroy(&t->global.qbuf); @@ -190,8 +179,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream_map_destroy(&t->new_stream_map); grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); - gpr_mu_unlock(&t->executor.mu); - gpr_mu_destroy(&t->executor.mu); + grpc_combiner_destroy(t->executor.combiner); /* callback remaining pings: they're not allowed to call into the transpot, and maybe they hold resources that need to be freed */ @@ -250,11 +238,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->base.vtable = &vtable; t->ep = ep; - /* one ref is for destroy, the other for when ep becomes NULL */ - gpr_ref_init(&t->refs, 2); + /* one ref is for destroy */ + gpr_ref_init(&t->refs, 1); /* ref is dropped at transport close() */ gpr_ref_init(&t->shutdown_ep_refs, 1); - gpr_mu_init(&t->executor.mu); + t->executor.combiner = grpc_combiner_create(grpc_endpoint_get_workqueue(ep)); t->peer_string = grpc_endpoint_get_peer(ep); t->endpoint_reading = 1; t->global.next_stream_id = is_client ? 1 : 2; @@ -280,15 +268,18 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor); grpc_closure_init(&t->writing_action, writing_action, t); grpc_closure_init(&t->reading_action, reading_action, t); + grpc_closure_init(&t->reading_action_locked, reading_action_locked, t); grpc_closure_init(&t->parsing_action, parsing_action, t); - grpc_closure_init(&t->initiate_writing, initiate_writing, t); + grpc_closure_init(&t->post_parse_locked, post_parse_locked, t); + grpc_closure_init(&t->initiate_writing, initiate_writing_locked, t); + grpc_closure_init(&t->terminate_writing, terminate_writing_with_lock, t); + grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, + &t->writing); gpr_slice_buffer_init(&t->parsing.qbuf); grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser); - grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, - &t->writing); gpr_slice_buffer_init(&t->read_buffer); if (is_client) { @@ -412,45 +403,34 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } -static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_ignored, - void *arg_ignored) { +static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; t->destroying = 1; drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed")); } static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, destroy_transport_locked, - NULL, 0); + grpc_combiner_execute(exec_ctx, t->executor.combiner, + grpc_closure_create(destroy_transport_locked, t), + GRPC_ERROR_NONE); UNREF_TRANSPORT(exec_ctx, t, "destroy"); } /** block grpc_endpoint_shutdown being called until a paired allow_endpoint_shutdown is made */ static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) { - GPR_ASSERT(t->ep); gpr_ref(&t->shutdown_ep_refs); } static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { if (gpr_unref(&t->shutdown_ep_refs)) { - if (t->ep) { - grpc_endpoint_shutdown(exec_ctx, t->ep); - } + grpc_endpoint_shutdown(exec_ctx, t->ep); } } -static void destroy_endpoint(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - grpc_endpoint_destroy(exec_ctx, t->ep); - t->ep = NULL; - /* safe because we'll still have the ref for write */ - UNREF_TRANSPORT(exec_ctx, t, "disconnect"); -} - static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { @@ -461,9 +441,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx, t->closed = 1; connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), "close_transport"); - if (t->ep) { - allow_endpoint_shutdown_locked(exec_ctx, t); - } + allow_endpoint_shutdown_locked(exec_ctx, t); /* flush writable stream list to avoid dangling references */ grpc_chttp2_stream_global *stream_global; @@ -497,11 +475,10 @@ void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, } #endif -static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *arg_ignored) { - grpc_chttp2_register_stream(t, s); +static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, + grpc_error *error) { + grpc_chttp2_stream *s = sp; + grpc_chttp2_register_stream(s->t, s); } static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, @@ -509,6 +486,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, const void *server_data) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + s->t = t; memset(s, 0, sizeof(*s)); @@ -545,16 +523,18 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, s->global.in_stream_map = true; } - grpc_chttp2_run_with_global_lock(exec_ctx, t, s, finish_init_stream_locked, - NULL, 0); + grpc_closure_init(&s->init_stream, finish_init_stream_locked, s); + grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->init_stream, + GRPC_ERROR_NONE); return 0; } -static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, void *arg) { +static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, + grpc_error *error) { grpc_byte_stream *bs; + grpc_chttp2_stream *s = sp; + grpc_chttp2_transport *t = s->t; GPR_TIMER_BEGIN("destroy_stream", 0); @@ -573,7 +553,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, while ( (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) { - incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs); + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global, @@ -610,7 +590,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, GPR_TIMER_END("destroy_stream", 0); - gpr_free(arg); + gpr_free(s->destroy_stream_arg); } static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, @@ -618,8 +598,10 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - grpc_chttp2_run_with_global_lock(exec_ctx, t, s, destroy_stream_locked, - and_free_memory, 0); + s->destroy_stream_arg = and_free_memory; + grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s); + grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->destroy_stream, + GRPC_ERROR_NONE); } grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( @@ -652,10 +634,6 @@ static const char *write_state_name(grpc_chttp2_write_state state) { switch (state) { case GRPC_CHTTP2_WRITING_INACTIVE: return "INACTIVE"; - case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER: - return "REQUESTED[p=0]"; - case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER: - return "REQUESTED[p=1]"; case GRPC_CHTTP2_WRITE_SCHEDULED: return "SCHEDULED"; case GRPC_CHTTP2_WRITING: @@ -678,119 +656,17 @@ static void set_write_state(grpc_chttp2_transport *t, t->executor.write_state = state; } -static void finish_global_actions(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - grpc_chttp2_executor_action_header *hdr; - grpc_chttp2_executor_action_header *next; - - GPR_TIMER_BEGIN("finish_global_actions", 0); - - for (;;) { - check_read_ops(exec_ctx, &t->global); - - gpr_mu_lock(&t->executor.mu); - if (t->executor.pending_actions_head != NULL) { - hdr = t->executor.pending_actions_head; - t->executor.pending_actions_head = t->executor.pending_actions_tail = - NULL; - gpr_mu_unlock(&t->executor.mu); - while (hdr != NULL) { - GPR_TIMER_BEGIN("chttp2:locked_action", 0); - hdr->action(exec_ctx, t, hdr->stream, hdr->arg); - GPR_TIMER_END("chttp2:locked_action", 0); - next = hdr->next; - gpr_free(hdr); - UNREF_TRANSPORT(exec_ctx, t, "pending_action"); - hdr = next; - } - continue; - } else { - t->executor.global_active = false; - switch (t->executor.write_state) { - case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER: - set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking"); - REF_TRANSPORT(t, "initiate_writing"); - gpr_mu_unlock(&t->executor.mu); - grpc_exec_ctx_sched(exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE, - grpc_endpoint_get_workqueue(t->ep)); - break; - case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER: - start_writing(exec_ctx, t); - gpr_mu_unlock(&t->executor.mu); - break; - case GRPC_CHTTP2_WRITING_INACTIVE: - case GRPC_CHTTP2_WRITING: - case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: - case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: - case GRPC_CHTTP2_WRITE_SCHEDULED: - gpr_mu_unlock(&t->executor.mu); - break; - } - } - break; - } - - GPR_TIMER_END("finish_global_actions", 0); +static void initiate_writing_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED); + start_writing(exec_ctx, t); } -void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *optional_stream, - grpc_chttp2_locked_action action, - void *arg, size_t sizeof_arg) { - grpc_chttp2_executor_action_header *hdr; - - GPR_TIMER_BEGIN("grpc_chttp2_run_with_global_lock", 0); - - REF_TRANSPORT(t, "run_global"); - gpr_mu_lock(&t->executor.mu); - - for (;;) { - if (!t->executor.global_active) { - t->executor.global_active = 1; - gpr_mu_unlock(&t->executor.mu); - - GPR_TIMER_BEGIN("chttp2:locked_action", 0); - action(exec_ctx, t, optional_stream, arg); - GPR_TIMER_END("chttp2:locked_action", 0); - - finish_global_actions(exec_ctx, t); - } else { - gpr_mu_unlock(&t->executor.mu); - - hdr = gpr_malloc(sizeof(*hdr) + sizeof_arg); - hdr->stream = optional_stream; - hdr->action = action; - if (sizeof_arg == 0) { - hdr->arg = arg; - } else { - hdr->arg = hdr + 1; - memcpy(hdr->arg, arg, sizeof_arg); - } - - gpr_mu_lock(&t->executor.mu); - if (!t->executor.global_active) { - /* global lock was released while allocating memory: release & retry */ - gpr_free(hdr); - continue; - } - hdr->next = NULL; - if (t->executor.pending_actions_head != NULL) { - t->executor.pending_actions_tail = - t->executor.pending_actions_tail->next = hdr; - } else { - t->executor.pending_actions_tail = t->executor.pending_actions_head = - hdr; - } - REF_TRANSPORT(t, "pending_action"); - gpr_mu_unlock(&t->executor.mu); - } - break; - } - - UNREF_TRANSPORT(exec_ctx, t, "run_global"); - - GPR_TIMER_END("grpc_chttp2_run_with_global_lock", 0); +static void initiate_read_flush_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + check_read_ops(exec_ctx, &t->global); } /******************************************************************************* @@ -803,23 +679,17 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); switch (t->executor.write_state) { case GRPC_CHTTP2_WRITING_INACTIVE: - set_write_state(t, covered_by_poller - ? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER - : GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER, - reason); - break; - case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER: - /* nothing to do: write already requested */ + set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, reason); + grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, + &t->initiate_writing, GRPC_ERROR_NONE, + covered_by_poller); break; - case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER: + case GRPC_CHTTP2_WRITE_SCHEDULED: if (covered_by_poller) { /* upgrade to note poller is available to cover the write */ - set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason); + grpc_combiner_force_async_finally(t->executor.combiner); } break; - case GRPC_CHTTP2_WRITE_SCHEDULED: - /* nothing to do: write already scheduled */ - break; case GRPC_CHTTP2_WRITING: set_write_state(t, covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER @@ -839,8 +709,7 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, } static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED || - t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER); + GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED); if (!t->closed && grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) { set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing"); @@ -856,26 +725,9 @@ static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { "start_writing:nothing_to_write"); } end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write")); - if (t->ep && !t->endpoint_reading) { - destroy_endpoint(exec_ctx, t); - } } } -static void initiate_writing_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, - void *arg_ignored) { - start_writing(exec_ctx, t); - UNREF_TRANSPORT(exec_ctx, t, "initiate_writing"); -} - -static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked, - NULL, 0); -} - void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global, @@ -916,12 +768,9 @@ static void end_waiting_for_write(grpc_exec_ctx *exec_ctx, GRPC_ERROR_UNREF(error); } -static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_ignored, - void *a) { - grpc_error *error = a; - +static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; allow_endpoint_shutdown_locked(exec_ctx, t); if (error != GRPC_ERROR_NONE) { @@ -930,39 +779,37 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); - end_waiting_for_write(exec_ctx, t, error); + end_waiting_for_write(exec_ctx, t, GRPC_ERROR_REF(error)); switch (t->executor.write_state) { case GRPC_CHTTP2_WRITING_INACTIVE: - case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER: - case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER: case GRPC_CHTTP2_WRITE_SCHEDULED: GPR_UNREACHABLE_CODE(break); case GRPC_CHTTP2_WRITING: set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing"); break; case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: - set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, - "terminate_writing"); + set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); + grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, + &t->initiate_writing, GRPC_ERROR_NONE, + true); break; case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: - set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER, - "terminate_writing"); + set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); + grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, + &t->initiate_writing, GRPC_ERROR_NONE, + false); break; } - if (t->ep && !t->endpoint_reading) { - destroy_endpoint(exec_ctx, t); - } - UNREF_TRANSPORT(exec_ctx, t, "writing"); } void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, void *transport_writing, grpc_error *error) { grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); - grpc_chttp2_run_with_global_lock( - exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0); + grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->terminate_writing, + GRPC_ERROR_REF(error)); } static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, @@ -1106,12 +953,13 @@ static int contains_non_ok_status( static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} -static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, void *stream_op) { +static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, + grpc_error *error_ignored) { GPR_TIMER_BEGIN("perform_stream_op_locked", 0); grpc_transport_stream_op *op = stream_op; + grpc_chttp2_transport *t = op->transport_private.args[0]; + grpc_chttp2_stream *s = op->transport_private.args[1]; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_stream_global *stream_global = &s->global; @@ -1291,9 +1139,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_transport_stream_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - grpc_chttp2_run_with_global_lock(exec_ctx, t, s, perform_stream_op_locked, op, - sizeof(*op)); + grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked, + op); + op->transport_private.args[0] = gt; + op->transport_private.args[1] = gs; + grpc_combiner_execute(exec_ctx, t->executor.combiner, + &op->transport_private.closure, GRPC_ERROR_NONE); } static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, @@ -1315,13 +1166,20 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping"); } -static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s, void *opaque_8bytes) { +typedef struct ack_ping_args { + grpc_closure closure; + grpc_chttp2_transport *t; + uint8_t opaque_8bytes[8]; +} ack_ping_args; + +static void ack_ping_locked(grpc_exec_ctx *exec_ctx, void *a, + grpc_error *error_ignored) { + ack_ping_args *args = a; grpc_chttp2_outstanding_ping *ping; - grpc_chttp2_transport_global *transport_global = &t->global; + grpc_chttp2_transport_global *transport_global = &args->t->global; for (ping = transport_global->pings.next; ping != &transport_global->pings; ping = ping->next) { - if (0 == memcmp(opaque_8bytes, ping->id, 8)) { + if (0 == memcmp(args->opaque_8bytes, ping->id, 8)) { grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL); ping->next->prev = ping->prev; ping->prev->next = ping->next; @@ -1329,21 +1187,25 @@ static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, break; } } + gpr_free(args); } void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, const uint8_t *opaque_8bytes) { - grpc_chttp2_run_with_global_lock( - exec_ctx, TRANSPORT_FROM_PARSING(transport_parsing), NULL, - ack_ping_locked, (void *)opaque_8bytes, 8); + ack_ping_args *args = gpr_malloc(sizeof(*args)); + args->t = TRANSPORT_FROM_PARSING(transport_parsing); + memcpy(args->opaque_8bytes, opaque_8bytes, sizeof(args->opaque_8bytes)); + grpc_closure_init(&args->closure, ack_ping_locked, args); + grpc_combiner_execute(exec_ctx, args->t->executor.combiner, &args->closure, + GRPC_ERROR_NONE); } static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, - void *stream_op) { + void *stream_op, + grpc_error *error_ignored) { grpc_transport_op *op = stream_op; + grpc_chttp2_transport *t = op->transport_private.args[0]; grpc_error *close_transport = op->disconnect_with_error; /* If there's a set_accept_stream ensure that we're not parsing @@ -1355,8 +1217,6 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, return; } - grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); - if (op->on_connectivity_state_change != NULL) { grpc_connectivity_state_notify_on_state_change( exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, @@ -1382,11 +1242,11 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, } if (op->bind_pollset) { - add_to_pollset_locked(exec_ctx, t, NULL, op->bind_pollset); + grpc_endpoint_add_to_pollset(exec_ctx, t->ep, op->bind_pollset); } if (op->bind_pollset_set) { - add_to_pollset_set_locked(exec_ctx, t, NULL, op->bind_pollset_set); + grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, op->bind_pollset_set); } if (op->send_ping) { @@ -1396,13 +1256,18 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, if (close_transport != GRPC_ERROR_NONE) { close_transport_locked(exec_ctx, t, close_transport); } + + grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); } static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_transport_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_chttp2_run_with_global_lock( - exec_ctx, t, NULL, perform_transport_op_locked, op, sizeof(*op)); + op->transport_private.args[0] = gt; + grpc_closure_init(&op->transport_private.closure, perform_transport_op_locked, + op); + grpc_combiner_execute(exec_ctx, t->executor.combiner, + &op->transport_private.closure, GRPC_ERROR_NONE); } /******************************************************************************* @@ -1420,7 +1285,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, if (stream_global->seen_error) { while ((bs = grpc_chttp2_incoming_frame_queue_pop( &stream_global->incoming_frames)) != NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs); + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } if (stream_global->exceeded_metadata_size) { cancel_from_api( @@ -1443,7 +1308,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, stream_global->seen_error && (bs = grpc_chttp2_incoming_frame_queue_pop( &stream_global->incoming_frames)) != NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs); + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } if (stream_global->incoming_frames.head != NULL) { *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop( @@ -1464,7 +1329,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, if (stream_global->seen_error) { while ((bs = grpc_chttp2_incoming_frame_queue_pop( &stream_global->incoming_frames)) != NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs); + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } if (stream_global->exceeded_metadata_size) { cancel_from_api( @@ -1905,16 +1770,12 @@ static void update_global_window(void *args, uint32_t id, void *stream) { * INPUT PROCESSING - PARSING */ -static void reading_action_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *arg); static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); -static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *arg); -static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *arg); +static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); +static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { @@ -1922,16 +1783,16 @@ static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, reading_action_locked -> (parse_unlocked -> post_parse_locked)? -> post_reading_action_locked */ - grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked, - GRPC_ERROR_REF(error), 0); + grpc_chttp2_transport *t = tp; + grpc_combiner_execute(exec_ctx, t->executor.combiner, + &t->reading_action_locked, GRPC_ERROR_REF(error)); } -static void reading_action_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *arg) { +static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; - grpc_error *error = arg; GPR_ASSERT(!t->executor.parsing_active); if (!t->closed) { @@ -1942,7 +1803,7 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_prepare_to_read(transport_global, transport_parsing); grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL); } else { - post_reading_action_locked(exec_ctx, t, s_unused, arg); + post_reading_action_locked(exec_ctx, t, GRPC_ERROR_REF(error)); } } @@ -1997,12 +1858,13 @@ static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, GRPC_ERROR_UNREF(errors[i]); } GPR_TIMER_END("reading_action.parse", 0); - grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err, - 0); + grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->post_parse_locked, + err); } -static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *arg) { +static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; /* copy parsing qbuf to global qbuf */ @@ -2028,7 +1890,7 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (t->post_parsing_op) { grpc_transport_op *op = t->post_parsing_op; t->post_parsing_op = NULL; - perform_transport_op_locked(exec_ctx, t, NULL, op); + perform_transport_op_locked(exec_ctx, op, GRPC_ERROR_NONE); gpr_free(op); } /* if a stream is in the stream map, and gets cancelled, we need to @@ -2045,15 +1907,14 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); } - post_reading_action_locked(exec_ctx, t, s_unused, arg); + post_reading_action_locked(exec_ctx, t, error); } -static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, - void *arg) { - grpc_error *error = arg; +static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_chttp2_transport *t = arg; bool keep_reading = false; + GRPC_ERROR_REF(error); if (error == GRPC_ERROR_NONE && t->closed) { error = GRPC_ERROR_CREATE("Transport closed"); } @@ -2068,16 +1929,12 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t, write_state_name(t->executor.write_state)); } - if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) { - destroy_endpoint(exec_ctx, t); - } } else if (!t->closed) { keep_reading = true; REF_TRANSPORT(t, "keep_reading"); prevent_endpoint_shutdown(t); } gpr_slice_buffer_reset_and_unref(&t->read_buffer); - GRPC_ERROR_UNREF(error); if (keep_reading) { grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->reading_action); @@ -2086,6 +1943,7 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, } else { UNREF_TRANSPORT(exec_ctx, t, "reading_action"); } + GRPC_ERROR_UNREF(error); } /******************************************************************************* @@ -2107,36 +1965,16 @@ static void connectivity_state_set( * POLLSET STUFF */ -static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, void *pollset) { - if (t->ep) { - grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset); - } -} - -static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s_unused, - void *pollset_set) { - if (t->ep) { - grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set); - } -} - static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_pollset *pollset) { - /* TODO(ctiller): keep pollset alive */ - grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt, - (grpc_chttp2_stream *)gs, - add_to_pollset_locked, pollset, 0); + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset); } static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_pollset_set *pollset_set) { - grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt, - (grpc_chttp2_stream *)gs, - add_to_pollset_set_locked, pollset_set, 0); + grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set); } /******************************************************************************* @@ -2148,6 +1986,7 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, if (gpr_unref(&bs->refs)) { GRPC_ERROR_UNREF(bs->error); gpr_slice_buffer_destroy(&bs->slices); + gpr_mu_destroy(&bs->slice_mu); gpr_free(bs); } } @@ -2193,38 +2032,31 @@ static void incoming_byte_stream_update_flow_control( } } -typedef struct { - grpc_chttp2_incoming_byte_stream *byte_stream; - gpr_slice *slice; - size_t max_size_hint; - grpc_closure *on_complete; -} incoming_byte_stream_next_arg; - static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *argp) { - incoming_byte_stream_next_arg *arg = argp; - grpc_chttp2_incoming_byte_stream *bs = - (grpc_chttp2_incoming_byte_stream *)arg->byte_stream; + void *argp, + grpc_error *error_ignored) { + grpc_chttp2_incoming_byte_stream *bs = argp; grpc_chttp2_transport_global *transport_global = &bs->transport->global; grpc_chttp2_stream_global *stream_global = &bs->stream->global; if (bs->is_tail) { - incoming_byte_stream_update_flow_control(exec_ctx, transport_global, - stream_global, arg->max_size_hint, - bs->slices.length); + incoming_byte_stream_update_flow_control( + exec_ctx, transport_global, stream_global, + bs->next_action.max_size_hint, bs->slices.length); } + gpr_mu_lock(&bs->slice_mu); if (bs->slices.count > 0) { - *arg->slice = gpr_slice_buffer_take_first(&bs->slices); - grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL); - } else if (bs->error != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_REF(bs->error), + *bs->next_action.slice = gpr_slice_buffer_take_first(&bs->slices); + grpc_exec_ctx_sched(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE, NULL); + } else if (bs->error != GRPC_ERROR_NONE) { + grpc_exec_ctx_sched(exec_ctx, bs->next_action.on_complete, + GRPC_ERROR_REF(bs->error), NULL); } else { - bs->on_next = arg->on_complete; - bs->next = arg->slice; + bs->on_next = bs->next_action.on_complete; + bs->next = bs->next_action.slice; } + gpr_mu_unlock(&bs->slice_mu); incoming_byte_stream_unref(exec_ctx, bs); } @@ -2234,11 +2066,14 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, grpc_closure *on_complete) { grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; - incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete}; gpr_ref(&bs->refs); - grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream, - incoming_byte_stream_next_locked, &arg, - sizeof(arg)); + bs->next_action.slice = slice; + bs->next_action.max_size_hint = max_size_hint; + bs->next_action.on_complete = on_complete; + grpc_closure_init(&bs->next_action.closure, incoming_byte_stream_next_locked, + bs); + grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, + &bs->next_action.closure, GRPC_ERROR_NONE); return 0; } @@ -2246,9 +2081,8 @@ static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream); static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *byte_stream) { + void *byte_stream, + grpc_error *error_ignored) { grpc_chttp2_incoming_byte_stream *bs = byte_stream; GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy); decrement_active_streams_locked(exec_ctx, &bs->transport->global, @@ -2260,8 +2094,10 @@ static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; - grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream, - incoming_byte_stream_destroy_locked, bs, 0); + grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked, + bs); + grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, + &bs->destroy_action, GRPC_ERROR_NONE); } typedef struct { @@ -2269,64 +2105,29 @@ typedef struct { gpr_slice slice; } incoming_byte_stream_push_arg; -static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *argp) { - incoming_byte_stream_push_arg *arg = argp; - grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream; +void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, + grpc_chttp2_incoming_byte_stream *bs, + gpr_slice slice) { + gpr_mu_lock(&bs->slice_mu); if (bs->on_next != NULL) { - *bs->next = arg->slice; + *bs->next = slice; grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL); bs->on_next = NULL; } else { - gpr_slice_buffer_add(&bs->slices, arg->slice); + gpr_slice_buffer_add(&bs->slices, slice); } - incoming_byte_stream_unref(exec_ctx, bs); -} - -void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, - grpc_chttp2_incoming_byte_stream *bs, - gpr_slice slice) { - incoming_byte_stream_push_arg arg = {bs, slice}; - gpr_ref(&bs->refs); - grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream, - incoming_byte_stream_push_locked, &arg, - sizeof(arg)); -} - -typedef struct { - grpc_chttp2_incoming_byte_stream *bs; - grpc_error *error; -} bs_fail_args; - -static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs, - grpc_error *error) { - bs_fail_args *a = gpr_malloc(sizeof(*a)); - a->bs = bs; - a->error = error; - return a; -} - -static void incoming_byte_stream_finished_failed_locked( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, - void *argp) { - bs_fail_args *a = argp; - grpc_chttp2_incoming_byte_stream *bs = a->bs; - grpc_error *error = a->error; - gpr_free(a); - grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL); - bs->on_next = NULL; - GRPC_ERROR_UNREF(bs->error); - bs->error = error; - incoming_byte_stream_unref(exec_ctx, bs); + gpr_mu_unlock(&bs->slice_mu); } -static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, - void *argp) { - grpc_chttp2_incoming_byte_stream *bs = argp; +static void incoming_byte_stream_finished_locked(grpc_exec_ctx *exec_ctx, + void *bsp, grpc_error *error) { + grpc_chttp2_incoming_byte_stream *bs = bsp; + if (error != GRPC_ERROR_NONE) { + grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL); + bs->on_next = NULL; + GRPC_ERROR_UNREF(bs->error); + bs->error = error; + } incoming_byte_stream_unref(exec_ctx, bs); } @@ -2334,24 +2135,12 @@ void grpc_chttp2_incoming_byte_stream_finished( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, grpc_error *error, int from_parsing_thread) { if (from_parsing_thread) { - if (error == GRPC_ERROR_NONE) { - grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream, - incoming_byte_stream_finished_ok_locked, - bs, 0); - } else { - grpc_chttp2_run_with_global_lock( - exec_ctx, bs->transport, bs->stream, - incoming_byte_stream_finished_failed_locked, - make_bs_fail_args(bs, error), 0); - } + grpc_closure_init(&bs->finished_action, + incoming_byte_stream_finished_locked, bs); + grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, + &bs->finished_action, GRPC_ERROR_REF(error)); } else { - if (error == GRPC_ERROR_NONE) { - incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport, - bs->stream, bs); - } else { - incoming_byte_stream_finished_failed_locked( - exec_ctx, bs->transport, bs->stream, make_bs_fail_args(bs, error)); - } + incoming_byte_stream_finished_locked(exec_ctx, bs, error); } } @@ -2365,6 +2154,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( incoming_byte_stream->base.flags = flags; incoming_byte_stream->base.next = incoming_byte_stream_next; incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; + gpr_mu_init(&incoming_byte_stream->slice_mu); gpr_ref_init(&incoming_byte_stream->refs, 2); incoming_byte_stream->next_message = NULL; incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 81ddaa8fa1..efac10a93c 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -48,6 +48,7 @@ #include "src/core/ext/transport/chttp2/transport/hpack_parser.h" #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" #include "src/core/ext/transport/chttp2/transport/stream_map.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/transport_impl.h" @@ -161,9 +162,20 @@ struct grpc_chttp2_incoming_byte_stream { grpc_chttp2_transport *transport; grpc_chttp2_stream *stream; int is_tail; + + gpr_mu slice_mu; // protects slices, on_next gpr_slice_buffer slices; grpc_closure *on_next; gpr_slice *next; + + struct { + grpc_closure closure; + gpr_slice *slice; + size_t max_size_hint; + grpc_closure *on_complete; + } next_action; + grpc_closure destroy_action; + grpc_closure finished_action; }; typedef struct { @@ -294,23 +306,9 @@ struct grpc_chttp2_transport_parsing { int64_t outgoing_window; }; -typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, - grpc_chttp2_stream *s, void *arg); - -typedef struct grpc_chttp2_executor_action_header { - grpc_chttp2_stream *stream; - grpc_chttp2_locked_action action; - struct grpc_chttp2_executor_action_header *next; - void *arg; -} grpc_chttp2_executor_action_header; - typedef enum { /** no writing activity */ GRPC_CHTTP2_WRITING_INACTIVE, - /** write has been requested, but not scheduled yet */ - GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, - GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER, /** write has been requested and scheduled against the workqueue */ GRPC_CHTTP2_WRITE_SCHEDULED, /** write has been initiated after being reaped from the workqueue */ @@ -331,7 +329,7 @@ struct grpc_chttp2_transport { gpr_refcount shutdown_ep_refs; struct { - gpr_mu mu; + grpc_combiner *combiner; /** is a thread currently in the global lock */ bool global_active; @@ -339,9 +337,6 @@ struct grpc_chttp2_transport { bool parsing_active; /** write execution state of the transport */ grpc_chttp2_write_state write_state; - - grpc_chttp2_executor_action_header *pending_actions_head; - grpc_chttp2_executor_action_header *pending_actions_tail; } executor; /** is the transport destroying itself? */ @@ -377,10 +372,14 @@ struct grpc_chttp2_transport { grpc_closure writing_action; /** closure to start reading from the endpoint */ grpc_closure reading_action; + grpc_closure reading_action_locked; + grpc_closure post_parse_locked; /** closure to actually do parsing */ grpc_closure parsing_action; /** closure to initiate writing */ grpc_closure initiate_writing; + /** closure to finish writing */ + grpc_closure terminate_writing; /** incoming read bytes */ gpr_slice_buffer read_buffer; @@ -522,11 +521,16 @@ struct grpc_chttp2_stream_parsing { }; struct grpc_chttp2_stream { + grpc_chttp2_transport *t; grpc_stream_refcount *refcount; grpc_chttp2_stream_global global; grpc_chttp2_stream_writing writing; grpc_chttp2_stream_parsing parsing; + grpc_closure init_stream; + grpc_closure destroy_stream; + void *destroy_stream_arg; + grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; uint8_t included[STREAM_LIST_COUNT]; }; @@ -698,12 +702,6 @@ void grpc_chttp2_complete_closure_step( grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure, grpc_error *error); -void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *transport, - grpc_chttp2_stream *optional_stream, - grpc_chttp2_locked_action action, - void *arg, size_t sizeof_arg); - #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1) diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 34e8f43905..5dfef4f25b 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -187,3 +187,7 @@ void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, } grpc_closure_list_append(&lock->final_list, closure, error); } + +void grpc_combiner_force_async_finally(grpc_combiner *lock) { + lock->take_async_break_before_final_list = true; +} diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index d6bc27111f..3554202aae 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -63,5 +63,6 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool force_async_break); +void grpc_combiner_force_async_finally(grpc_combiner *lock); #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 08c0a237c9..b04b60ec3d 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -96,6 +96,11 @@ void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats *from, void grpc_transport_move_stats(grpc_transport_stream_stats *from, grpc_transport_stream_stats *to); +typedef struct { + grpc_closure closure; + void *args[2]; +} grpc_transport_private_op_data; + /* Transport stream op: a set of operations to perform on a transport against a single stream */ typedef struct grpc_transport_stream_op { @@ -144,6 +149,12 @@ typedef struct grpc_transport_stream_op { /* Indexes correspond to grpc_context_index enum values */ grpc_call_context_element *context; + + /*************************************************************************** + * remaining fields are initialized and used at the discretion of the + * transport implementation */ + + grpc_transport_private_op_data transport_private; } grpc_transport_stream_op; /** Transport op: a set of operations to perform on a transport as a whole */ @@ -177,6 +188,12 @@ typedef struct grpc_transport_op { grpc_pollset_set *bind_pollset_set; /** send a ping, call this back if not NULL */ grpc_closure *send_ping; + + /*************************************************************************** + * remaining fields are initialized and used at the discretion of the + * transport implementation */ + + grpc_transport_private_op_data transport_private; } grpc_transport_op; /* Returns the amount of memory required to store a grpc_stream for this -- cgit v1.2.3 From e0221ff3401d397b981fbb3e057fa7812de37f35 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Jul 2016 15:56:08 -0700 Subject: Debugging --- src/core/ext/client_config/subchannel.c | 17 +++--- .../transport/chttp2/transport/chttp2_transport.c | 2 +- src/core/lib/iomgr/combiner.c | 61 ++++++++++++++++++---- src/core/lib/iomgr/combiner.h | 11 ++-- src/core/lib/iomgr/exec_ctx.h | 6 ++- src/core/lib/surface/channel.c | 7 ++- src/core/lib/surface/channel_ping.c | 9 ++-- src/core/lib/surface/server.c | 56 +++++++++----------- src/core/lib/transport/transport.c | 26 +++++++++ src/core/lib/transport/transport.h | 4 ++ test/core/iomgr/combiner_test.c | 20 ++++--- test/core/surface/lame_client_test.c | 15 +++--- 12 files changed, 152 insertions(+), 82 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c index d089cd4399..2318bd1023 100644 --- a/src/core/ext/client_config/subchannel.c +++ b/src/core/ext/client_config/subchannel.c @@ -504,14 +504,14 @@ static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx, grpc_pollset_set *interested_parties, grpc_connectivity_state *state, grpc_closure *closure) { - grpc_transport_op op; + grpc_transport_op *op = grpc_make_transport_op(NULL); grpc_channel_element *elem; memset(&op, 0, sizeof(op)); - op.connectivity_state = state; - op.on_connectivity_state_change = closure; - op.bind_pollset_set = interested_parties; + op->connectivity_state = state; + op->on_connectivity_state_change = closure; + op->bind_pollset_set = interested_parties; elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); + elem->filter->start_transport_op(exec_ctx, elem, op); } void grpc_connected_subchannel_notify_on_state_change( @@ -525,12 +525,11 @@ void grpc_connected_subchannel_notify_on_state_change( void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, grpc_closure *closure) { - grpc_transport_op op; + grpc_transport_op *op = grpc_make_transport_op(NULL); grpc_channel_element *elem; - memset(&op, 0, sizeof(op)); - op.send_ping = closure; + op->send_ping = closure; elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); + elem->filter->start_transport_op(exec_ctx, elem, op); } static void publish_transport_locked(grpc_exec_ctx *exec_ctx, diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 194264c8f9..4dc642e37a 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -181,7 +181,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream_map_destroy(&t->new_stream_map); grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); - grpc_combiner_destroy(t->executor.combiner); + grpc_combiner_destroy(exec_ctx, t->executor.combiner); /* callback remaining pings: they're not allowed to call into the transpot, and maybe they hold resources that need to be freed */ diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 5dfef4f25b..99e112308b 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -32,6 +32,7 @@ */ #include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/workqueue.h" #include @@ -52,7 +53,9 @@ struct grpc_combiner { grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { grpc_combiner *lock = gpr_malloc(sizeof(*lock)); - lock->optional_workqueue = optional_workqueue; + lock->optional_workqueue = + optional_workqueue ? GRPC_WORKQUEUE_REF(optional_workqueue, "combiner") + : NULL; gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); lock->take_async_break_before_final_list = false; @@ -60,15 +63,18 @@ grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { return lock; } -static void really_destroy(grpc_combiner *lock) { +static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); + if (lock->optional_workqueue != NULL) { + GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); + } gpr_free(lock); } -void grpc_combiner_destroy(grpc_combiner *lock) { +void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { - really_destroy(lock); + really_destroy(exec_ctx, lock); } } @@ -77,7 +83,12 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - if (maybe_finish_one(exec_ctx, arg)) finish(exec_ctx, arg); + grpc_combiner *lock = arg; + GPR_ASSERT(exec_ctx->active_combiner == NULL); + exec_ctx->active_combiner = lock; + if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); + GPR_ASSERT(exec_ctx->active_combiner == lock); + exec_ctx->active_combiner = NULL; } static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { @@ -96,6 +107,8 @@ static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_combiner *lock = arg; + GPR_ASSERT(exec_ctx->active_combiner == NULL); + exec_ctx->active_combiner = lock; // quick peek to see if new things have turned up on the queue: if so, go back // to executing them before the final list if ((gpr_atm_acq_load(&lock->state) >> 1) > 1) { @@ -104,9 +117,12 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, execute_final(exec_ctx, lock); finish(exec_ctx, lock); } + GPR_ASSERT(exec_ctx->active_combiner == lock); + exec_ctx->active_combiner = NULL; } static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + GPR_ASSERT(exec_ctx->active_combiner == lock); if (lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); @@ -121,6 +137,7 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); + GPR_ASSERT(exec_ctx->active_combiner == lock); if (n == NULL) { // queue is in an inconsistant state: use this as a cue that we should // go off and do something else for a while (and come back later) @@ -151,7 +168,7 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { case 3: // had one count, one unorphaned --> unlocked unorphaned return; case 2: // and one count, one orphaned --> unlocked and orphaned - really_destroy(lock); + really_destroy(exec_ctx, lock); return; case 1: case 0: @@ -166,19 +183,43 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *cl, grpc_error *error) { gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); GPR_ASSERT(last & 1); // ensure lock has not been destroyed - if (last == 1) { - cl->cb(exec_ctx, cl->cb_arg, error); - GRPC_ERROR_UNREF(error); - finish(exec_ctx, lock); + if (exec_ctx->active_combiner == NULL) { + if (last == 1) { + exec_ctx->active_combiner = lock; + cl->cb(exec_ctx, cl->cb_arg, error); + GRPC_ERROR_UNREF(error); + finish(exec_ctx, lock); + GPR_ASSERT(exec_ctx->active_combiner == lock); + exec_ctx->active_combiner = NULL; + } else { + cl->error = error; + gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + } } else { cl->error = error; gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, + lock); + grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, + lock->optional_workqueue); } } +static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, + grpc_error *error) { + grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure, + GRPC_ERROR_REF(error), true); +} + void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool force_async_break) { + if (exec_ctx->active_combiner != lock) { + grpc_combiner_execute(exec_ctx, lock, + grpc_closure_create(enqueue_finally, closure), error); + return; + } + if (force_async_break) { lock->take_async_break_before_final_list = true; } diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 3554202aae..5b94d5bd99 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -40,8 +40,6 @@ #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/mpscq.h" -typedef struct grpc_combiner grpc_combiner; - // Provides serialized access to some resource. // Each action queued on an aelock is executed serially in a borrowed thread. // The actual thread executing actions may change over time (but there will only @@ -51,18 +49,19 @@ typedef struct grpc_combiner grpc_combiner; // necessary grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); // Destroy the lock -void grpc_combiner_destroy(grpc_combiner *lock); +void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); // Execute \a action within the lock. void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); // Execute \a action within the lock just prior to unlocking. -// if \a force_async_break is additionally set, the combiner is forced to trip +// if \a hint_async_break is additionally set, the combiner is tries to trip // through the workqueue between finishing the primary queue of combined // closures and executing the finally list. -// Can only be called from within a closure scheduled by grpc_combiner_execute +// Takes a very slow and round-about path if not called from a +// grpc_combiner_execute closure void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, - bool force_async_break); + bool hint_async_break); void grpc_combiner_force_async_finally(grpc_combiner *lock); #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index 917f332f03..1895ee6245 100644 --- a/src/core/lib/iomgr/exec_ctx.h +++ b/src/core/lib/iomgr/exec_ctx.h @@ -40,8 +40,8 @@ /** A workqueue represents a list of work to be executed asynchronously. Forward declared here to avoid a circular dependency with workqueue.h. */ -struct grpc_workqueue; typedef struct grpc_workqueue grpc_workqueue; +typedef struct grpc_combiner grpc_combiner; #ifndef GRPC_EXECUTION_CONTEXT_SANITIZER /** Execution context. @@ -66,13 +66,15 @@ typedef struct grpc_workqueue grpc_workqueue; */ struct grpc_exec_ctx { grpc_closure_list closure_list; + /** currently active combiner: updated only via combiner.c */ + grpc_combiner *active_combiner; bool cached_ready_to_finish; void *check_ready_to_finish_arg; bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg); }; #define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \ - { GRPC_CLOSURE_LIST_INIT, false, finish_check_arg, finish_check } + { GRPC_CLOSURE_LIST_INIT, NULL, false, finish_check_arg, finish_check } #else struct grpc_exec_ctx { bool cached_ready_to_finish; diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c index 6d2b1c4935..52e78567bd 100644 --- a/src/core/lib/surface/channel.c +++ b/src/core/lib/surface/channel.c @@ -334,14 +334,13 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, } void grpc_channel_destroy(grpc_channel *channel) { - grpc_transport_op op; + grpc_transport_op *op = grpc_make_transport_op(NULL); grpc_channel_element *elem; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel)); - memset(&op, 0, sizeof(op)); - op.disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed"); + op->disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed"); elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0); - elem->filter->start_transport_op(&exec_ctx, elem, &op); + elem->filter->start_transport_op(&exec_ctx, elem, op); GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel"); diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c index 9818f9d2f2..5f9f07f89a 100644 --- a/src/core/lib/surface/channel_ping.c +++ b/src/core/lib/surface/channel_ping.c @@ -61,19 +61,18 @@ static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq, void *tag, void *reserved) { - grpc_transport_op op; + grpc_transport_op *op = grpc_make_transport_op(NULL); ping_result *pr = gpr_malloc(sizeof(*pr)); grpc_channel_element *top_elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_ASSERT(reserved == NULL); - memset(&op, 0, sizeof(op)); pr->tag = tag; pr->cq = cq; grpc_closure_init(&pr->closure, ping_done, pr); - op.send_ping = &pr->closure; - op.bind_pollset = grpc_cq_pollset(cq); + op->send_ping = &pr->closure; + op->bind_pollset = grpc_cq_pollset(cq); grpc_cq_begin_op(cq, tag); - top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op); + top_elem->filter->start_transport_op(&exec_ctx, top_elem, op); grpc_exec_ctx_finish(&exec_ctx); } diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index def6e5068b..fc9987f0aa 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -272,22 +272,20 @@ static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg, static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, int send_goaway, grpc_error *send_disconnect) { - grpc_transport_op op; - struct shutdown_cleanup_args *sc; + struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc)); + grpc_closure_init(&sc->closure, shutdown_cleanup, sc); + grpc_transport_op *op = grpc_make_transport_op(&sc->closure); grpc_channel_element *elem; - memset(&op, 0, sizeof(op)); - op.send_goaway = send_goaway; - sc = gpr_malloc(sizeof(*sc)); + op->send_goaway = send_goaway; sc->slice = gpr_slice_from_copied_string("Server shutdown"); - op.goaway_message = &sc->slice; - op.goaway_status = GRPC_STATUS_OK; - op.disconnect_with_error = send_disconnect; - grpc_closure_init(&sc->closure, shutdown_cleanup, sc); - op.on_consumed = &sc->closure; + op->goaway_message = &sc->slice; + op->goaway_status = GRPC_STATUS_OK; + op->disconnect_with_error = send_disconnect; + op->on_consumed = &sc->closure; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - elem->filter->start_transport_op(exec_ctx, elem, &op); + elem->filter->start_transport_op(exec_ctx, elem, op); } static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx, @@ -434,14 +432,13 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) { chand->finish_destroy_channel_closure.cb = finish_destroy_channel; chand->finish_destroy_channel_closure.cb_arg = chand; - grpc_transport_op op; - memset(&op, 0, sizeof(op)); - op.set_accept_stream = true; - op.on_consumed = &chand->finish_destroy_channel_closure; + grpc_transport_op *op = + grpc_make_transport_op(&chand->finish_destroy_channel_closure); + op->set_accept_stream = true; grpc_channel_next_op(exec_ctx, grpc_channel_stack_element( grpc_channel_get_channel_stack(chand->channel), 0), - &op); + op); } static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { @@ -832,14 +829,13 @@ static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd, channel_data *chand = cd; grpc_server *server = chand->server; if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) { - grpc_transport_op op; - memset(&op, 0, sizeof(op)); - op.on_connectivity_state_change = &chand->channel_connectivity_changed, - op.connectivity_state = &chand->connectivity_state; + grpc_transport_op *op = grpc_make_transport_op(NULL); + op->on_connectivity_state_change = &chand->channel_connectivity_changed, + op->connectivity_state = &chand->connectivity_state; grpc_channel_next_op(exec_ctx, grpc_channel_stack_element( grpc_channel_get_channel_stack(chand->channel), 0), - &op); + op); } else { gpr_mu_lock(&server->mu_global); destroy_channel(exec_ctx, chand); @@ -1101,7 +1097,7 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, size_t slots; uint32_t probes; uint32_t max_probes = 0; - grpc_transport_op op; + grpc_transport_op *op = NULL; channel = grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport); @@ -1161,16 +1157,16 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s, gpr_mu_unlock(&s->mu_global); GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity"); - memset(&op, 0, sizeof(op)); - op.set_accept_stream = true; - op.set_accept_stream_fn = accept_stream; - op.set_accept_stream_user_data = chand; - op.on_connectivity_state_change = &chand->channel_connectivity_changed; - op.connectivity_state = &chand->connectivity_state; + op = grpc_make_transport_op(NULL); + op->set_accept_stream = true; + op->set_accept_stream_fn = accept_stream; + op->set_accept_stream_user_data = chand; + op->on_connectivity_state_change = &chand->channel_connectivity_changed; + op->connectivity_state = &chand->connectivity_state; if (gpr_atm_acq_load(&s->shutdown_flag) != 0) { - op.disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown"); + op->disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown"); } - grpc_transport_perform_op(exec_ctx, transport, &op); + grpc_transport_perform_op(exec_ctx, transport, op); } void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg, diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c index 857c3909d2..970d9c389a 100644 --- a/src/core/lib/transport/transport.c +++ b/src/core/lib/transport/transport.c @@ -32,10 +32,14 @@ */ #include "src/core/lib/transport/transport.h" + +#include + #include #include #include #include + #include "src/core/lib/support/string.h" #include "src/core/lib/transport/transport_impl.h" @@ -247,3 +251,25 @@ void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status); add_error(op, &op->close_error, error); } + +typedef struct { + grpc_closure outer_on_complete; + grpc_closure *inner_on_complete; + grpc_transport_op op; +} made_transport_op; + +static void destroy_made_transport_op(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + made_transport_op *op = arg; + grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error), + NULL); + gpr_free(op); +} + +grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) { + made_transport_op *op = gpr_malloc(sizeof(*op)); + grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op); + op->inner_on_complete = on_complete; + memset(&op->op, 0, sizeof(op->op)); + return &op->op; +} diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index b04b60ec3d..508b57a5b4 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -285,4 +285,8 @@ void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport); char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *transport); +/* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to + \a on_consumed and then delete the returned transport op */ +grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed); + #endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H */ diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c index 0aaeada345..7cf016d82c 100644 --- a/test/core/iomgr/combiner_test.c +++ b/test/core/iomgr/combiner_test.c @@ -43,7 +43,9 @@ static void test_no_op(void) { gpr_log(GPR_DEBUG, "test_no_op"); - grpc_combiner_destroy(grpc_combiner_create(NULL)); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_destroy(&exec_ctx, grpc_combiner_create(NULL)); + grpc_exec_ctx_finish(&exec_ctx); } static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value, @@ -60,9 +62,10 @@ static void test_execute_one(void) { grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(set_bool_to_true, &done), GRPC_ERROR_NONE); - grpc_exec_ctx_finish(&exec_ctx); + grpc_exec_ctx_flush(&exec_ctx); GPR_ASSERT(done); - grpc_combiner_destroy(lock); + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); } typedef struct { @@ -89,7 +92,7 @@ static void execute_many_loop(void *a) { size_t n = 1; for (size_t i = 0; i < 10; i++) { for (size_t j = 0; j < 10000; j++) { - ex_args *c = gpr_malloc(sizeof(*a)); + ex_args *c = gpr_malloc(sizeof(*c)); c->ctr = &args->ctr; c->value = n++; grpc_combiner_execute(&exec_ctx, args->lock, @@ -117,7 +120,9 @@ static void test_execute_many(void) { for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) { gpr_thd_join(thds[i]); } - grpc_combiner_destroy(lock); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); } static bool got_in_finally = false; @@ -139,9 +144,10 @@ static void test_execute_finally(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock), GRPC_ERROR_NONE); - grpc_exec_ctx_finish(&exec_ctx); + grpc_exec_ctx_flush(&exec_ctx); GPR_ASSERT(got_in_finally); - grpc_combiner_destroy(lock); + grpc_combiner_destroy(&exec_ctx, lock); + grpc_exec_ctx_finish(&exec_ctx); } int main(int argc, char **argv) { diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c index f36f980575..cad45cc9fa 100644 --- a/test/core/surface/lame_client_test.c +++ b/test/core/surface/lame_client_test.c @@ -57,24 +57,23 @@ void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg, void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} void test_transport_op(grpc_channel *channel) { - grpc_transport_op op; + grpc_transport_op *op; grpc_channel_element *elem; grpc_connectivity_state state = GRPC_CHANNEL_IDLE; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - memset(&op, 0, sizeof(op)); grpc_closure_init(&transport_op_cb, verify_connectivity, &op); - op.on_connectivity_state_change = &transport_op_cb; - op.connectivity_state = &state; + op = grpc_make_transport_op(NULL); + op->on_connectivity_state_change = &transport_op_cb; + op->connectivity_state = &state; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); - elem->filter->start_transport_op(&exec_ctx, elem, &op); + elem->filter->start_transport_op(&exec_ctx, elem, op); grpc_exec_ctx_finish(&exec_ctx); - memset(&op, 0, sizeof(op)); grpc_closure_init(&transport_op_cb, do_nothing, NULL); - op.on_consumed = &transport_op_cb; - elem->filter->start_transport_op(&exec_ctx, elem, &op); + op = grpc_make_transport_op(&transport_op_cb); + elem->filter->start_transport_op(&exec_ctx, elem, op); grpc_exec_ctx_finish(&exec_ctx); } -- cgit v1.2.3 From 9dc01dd44d169811141853b47d6331e4c3a4245b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Jul 2016 16:26:34 -0700 Subject: Fix some refcounting bugs --- src/core/ext/client_config/subchannel.c | 1 - .../transport/chttp2/transport/chttp2_transport.c | 2 +- src/core/lib/iomgr/combiner.c | 35 +++++++--------------- src/core/lib/iomgr/workqueue_posix.c | 11 +++++-- 4 files changed, 21 insertions(+), 28 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c index 2318bd1023..43b88d2ce4 100644 --- a/src/core/ext/client_config/subchannel.c +++ b/src/core/ext/client_config/subchannel.c @@ -506,7 +506,6 @@ static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx, grpc_closure *closure) { grpc_transport_op *op = grpc_make_transport_op(NULL); grpc_channel_element *elem; - memset(&op, 0, sizeof(op)); op->connectivity_state = state; op->on_connectivity_state_change = closure; op->bind_pollset_set = interested_parties; diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 4dc642e37a..28f27c271d 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -490,10 +490,10 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, const void *server_data) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; - s->t = t; memset(s, 0, sizeof(*s)); + s->t = t; s->refcount = refcount; /* We reserve one 'active stream' that's dropped when the stream is read-closed. The others are for incoming_byte_streams that are actively diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 99e112308b..6b326facc3 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -53,9 +53,7 @@ struct grpc_combiner { grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { grpc_combiner *lock = gpr_malloc(sizeof(*lock)); - lock->optional_workqueue = - optional_workqueue ? GRPC_WORKQUEUE_REF(optional_workqueue, "combiner") - : NULL; + lock->optional_workqueue = GRPC_WORKQUEUE_REF(optional_workqueue, "combiner"); gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); lock->take_async_break_before_final_list = false; @@ -66,9 +64,7 @@ grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); - if (lock->optional_workqueue != NULL) { - GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); - } + GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); gpr_free(lock); } @@ -127,7 +123,7 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - lock->optional_workqueue); + GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); return false; } else { execute_final(exec_ctx, lock); @@ -144,7 +140,7 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - lock->optional_workqueue); + GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); return false; } grpc_closure *cl = (grpc_closure *)n; @@ -183,25 +179,16 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *cl, grpc_error *error) { gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); GPR_ASSERT(last & 1); // ensure lock has not been destroyed - if (exec_ctx->active_combiner == NULL) { - if (last == 1) { - exec_ctx->active_combiner = lock; - cl->cb(exec_ctx, cl->cb_arg, error); - GRPC_ERROR_UNREF(error); - finish(exec_ctx, lock); - GPR_ASSERT(exec_ctx->active_combiner == lock); - exec_ctx->active_combiner = NULL; - } else { - cl->error = error; - gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); - } + if (last == 1) { + exec_ctx->active_combiner = lock; + cl->cb(exec_ctx, cl->cb_arg, error); + GRPC_ERROR_UNREF(error); + finish(exec_ctx, lock); + GPR_ASSERT(exec_ctx->active_combiner == lock); + exec_ctx->active_combiner = NULL; } else { cl->error = error; gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); - grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, - lock); - grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - lock->optional_workqueue); } } diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 1d52a91694..5accd06744 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -86,11 +86,13 @@ void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p ref %d -> %d %s", workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1, reason); + gpr_ref(&workqueue->refs); +} #else void grpc_workqueue_ref(grpc_workqueue *workqueue) { -#endif gpr_ref(&workqueue->refs); } +#endif #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, @@ -98,13 +100,17 @@ void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s", workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1, reason); + if (gpr_unref(&workqueue->refs)) { + workqueue_orphan(exec_ctx, workqueue); + } +} #else void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { -#endif if (gpr_unref(&workqueue->refs)) { workqueue_orphan(exec_ctx, workqueue); } } +#endif static void drain(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { abort(); @@ -168,6 +174,7 @@ void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, grpc_closure *closure, grpc_error *error) { gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, 2); GPR_ASSERT(last & 1); + closure->error = error; gpr_mpscq_push(&workqueue->queue, &closure->next_data.atm_next); if (last == 1) { wakeup(exec_ctx, workqueue); -- cgit v1.2.3 From 5beba2818e9a2436dcf410ac6d4c6886cb00444c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Jul 2016 22:05:07 -0700 Subject: fixes --- composer.json | 6 ++---- src/core/ext/transport/chttp2/transport/chttp2_transport.c | 6 ++---- src/core/lib/iomgr/workqueue_posix.c | 2 ++ 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src/core/lib') diff --git a/composer.json b/composer.json index 6e7f24b451..05ac003714 100644 --- a/composer.json +++ b/composer.json @@ -13,10 +13,8 @@ ], "require": { "php": ">=5.5.0", - "datto/protobuf-php": "dev-master" - }, - "require-dev": { - "google/auth": "v0.9" + "datto/protobuf-php": "dev-master", + "google/auth": "v0.7" }, "autoload": { "psr-4": { diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 28f27c271d..91ca2683e0 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -31,9 +31,6 @@ * */ -// TODO(ctiller): schedule check_read_ops whenever something is added to that -// list - #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include @@ -1816,7 +1813,8 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); grpc_chttp2_prepare_to_read(transport_global, transport_parsing); - grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL); + grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, GRPC_ERROR_REF(error), + NULL); } else { post_reading_action_locked(exec_ctx, t, GRPC_ERROR_REF(error)); } diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 5accd06744..160f88bdee 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -90,6 +90,7 @@ void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, } #else void grpc_workqueue_ref(grpc_workqueue *workqueue) { + if (workqueue == NULL) return; gpr_ref(&workqueue->refs); } #endif @@ -106,6 +107,7 @@ void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, } #else void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + if (workqueue == NULL) return; if (gpr_unref(&workqueue->refs)) { workqueue_orphan(exec_ctx, workqueue); } -- cgit v1.2.3 From ed334f0f3ead942c23f474c7d241a66b9cf8dafa Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 12 Jul 2016 09:15:07 -0700 Subject: Fixes --- src/core/ext/transport/chttp2/transport/chttp2_transport.c | 2 +- src/core/lib/iomgr/workqueue_posix.c | 2 +- src/core/lib/security/transport/secure_endpoint.c | 4 ++-- src/core/lib/surface/server.c | 1 - src/core/lib/transport/transport.c | 1 + 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 91ca2683e0..aff3afce12 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1816,7 +1816,7 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, GRPC_ERROR_REF(error), NULL); } else { - post_reading_action_locked(exec_ctx, t, GRPC_ERROR_REF(error)); + post_reading_action_locked(exec_ctx, t, error); } } diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 160f88bdee..49a100520e 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -133,7 +133,7 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { workqueue->wakeup_fd.read_fd = 0; grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); - drain(exec_ctx, workqueue); + GPR_ASSERT(gpr_atm_no_barrier_load(&workqueue->state) == 0); gpr_free(workqueue); } else { error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c index bc50f9d1b0..0169ccd9ef 100644 --- a/src/core/lib/security/transport/secure_endpoint.c +++ b/src/core/lib/security/transport/secure_endpoint.c @@ -128,7 +128,7 @@ static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, grpc_error *error) { - if (false && grpc_trace_secure_endpoint) { + if (grpc_trace_secure_endpoint) { size_t i; for (i = 0; i < ep->read_buffer->count; i++) { char *data = gpr_dump_slice(ep->read_buffer->slices[i], @@ -256,7 +256,7 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, gpr_slice_buffer_reset_and_unref(&ep->output_buffer); - if (false && grpc_trace_secure_endpoint) { + if (grpc_trace_secure_endpoint) { for (i = 0; i < slices->count; i++) { char *data = gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index fc9987f0aa..08f741119d 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -282,7 +282,6 @@ static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, op->goaway_message = &sc->slice; op->goaway_status = GRPC_STATUS_OK; op->disconnect_with_error = send_disconnect; - op->on_consumed = &sc->closure; elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); elem->filter->start_transport_op(exec_ctx, elem, op); diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c index 970d9c389a..08f9d7e8d9 100644 --- a/src/core/lib/transport/transport.c +++ b/src/core/lib/transport/transport.c @@ -271,5 +271,6 @@ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) { grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op); op->inner_on_complete = on_complete; memset(&op->op, 0, sizeof(op->op)); + op->op.on_consumed = &op->outer_on_complete; return &op->op; } -- cgit v1.2.3 From 16125a805f533fb6e73e60b2b22976e9dbef2388 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 13 Jul 2016 16:46:22 -0700 Subject: Refs --- src/core/lib/iomgr/combiner.c | 2 +- src/core/lib/iomgr/workqueue.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 6b326facc3..73347d5024 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -53,7 +53,7 @@ struct grpc_combiner { grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { grpc_combiner *lock = gpr_malloc(sizeof(*lock)); - lock->optional_workqueue = GRPC_WORKQUEUE_REF(optional_workqueue, "combiner"); + lock->optional_workqueue = optional_workqueue; gpr_atm_no_barrier_store(&lock->state, 1); gpr_mpscq_init(&lock->queue); lock->take_async_break_before_final_list = false; diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h index 416618e258..01f4cb01b8 100644 --- a/src/core/lib/iomgr/workqueue.h +++ b/src/core/lib/iomgr/workqueue.h @@ -50,7 +50,7 @@ /* grpc_workqueue is forward declared in exec_ctx.h */ -//#define GRPC_WORKQUEUE_REFCOUNT_DEBUG +#define GRPC_WORKQUEUE_REFCOUNT_DEBUG #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #define GRPC_WORKQUEUE_REF(p, r) \ (grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p)) -- cgit v1.2.3 From 9e1803ec0b0efa28a8845e538c796853bca5011a Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 13 Jul 2016 17:24:47 -0700 Subject: wq fixes --- src/core/lib/iomgr/workqueue.h | 2 +- src/core/lib/iomgr/workqueue_posix.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h index 01f4cb01b8..416618e258 100644 --- a/src/core/lib/iomgr/workqueue.h +++ b/src/core/lib/iomgr/workqueue.h @@ -50,7 +50,7 @@ /* grpc_workqueue is forward declared in exec_ctx.h */ -#define GRPC_WORKQUEUE_REFCOUNT_DEBUG +//#define GRPC_WORKQUEUE_REFCOUNT_DEBUG #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #define GRPC_WORKQUEUE_REF(p, r) \ (grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p)) diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 49a100520e..801c097566 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -83,6 +83,7 @@ static void workqueue_orphan(grpc_exec_ctx *exec_ctx, #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, const char *reason) { + if (workqueue == NULL) return; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p ref %d -> %d %s", workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1, reason); @@ -98,6 +99,7 @@ void grpc_workqueue_ref(grpc_workqueue *workqueue) { #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, const char *file, int line, const char *reason) { + if (workqueue == NULL) return; gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s", workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1, reason); -- cgit v1.2.3 From c69d27b67d16f635aa234f28cc51608b609e0d1d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 14 Jul 2016 13:20:22 -0700 Subject: Add timing data --- .../transport/chttp2/transport/chttp2_transport.c | 39 +++++++++++++++++++++- src/core/ext/transport/chttp2/transport/writing.c | 2 ++ src/core/lib/iomgr/combiner.c | 28 +++++++++++++++- src/core/lib/iomgr/workqueue_posix.c | 8 +++++ 4 files changed, 75 insertions(+), 2 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 705761d46b..23389047e4 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -494,6 +494,7 @@ static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_stream_refcount *refcount, const void *server_data) { + GPR_TIMER_BEGIN("init_stream", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; @@ -539,6 +540,8 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->init_stream, GRPC_ERROR_NONE); + GPR_TIMER_END("init_stream", 0); + return 0; } @@ -607,6 +610,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, void *and_free_memory) { + GPR_TIMER_BEGIN("destroy_stream", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; @@ -614,6 +618,7 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s); grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->destroy_stream, GRPC_ERROR_NONE); + GPR_TIMER_END("destroy_stream", 0); } grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( @@ -691,6 +696,7 @@ static void initiate_read_flush_locked(grpc_exec_ctx *exec_ctx, void *tp, void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, bool covered_by_poller, const char *reason) { + GPR_TIMER_BEGIN("grpc_chttp2_initiate_write", 0); grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); switch (t->executor.write_state) { case GRPC_CHTTP2_WRITES_CORKED: @@ -724,9 +730,11 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, } break; } + GPR_TIMER_END("grpc_chttp2_initiate_write", 0); } static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { + GPR_TIMER_BEGIN("start_writing", 0); GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED); if (!t->closed && grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) { @@ -744,6 +752,7 @@ static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write")); UNREF_TRANSPORT(exec_ctx, t, "writing"); } + GPR_TIMER_END("start_writing", 0); } void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, @@ -788,6 +797,7 @@ static void end_waiting_for_write(grpc_exec_ctx *exec_ctx, static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { + GPR_TIMER_BEGIN("terminate_writing_with_lock", 0); grpc_chttp2_transport *t = tp; allow_endpoint_shutdown_locked(exec_ctx, t); @@ -805,9 +815,11 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, case GRPC_CHTTP2_WRITE_SCHEDULED: GPR_UNREACHABLE_CODE(break); case GRPC_CHTTP2_WRITING: + GPR_TIMER_MARK("state=writing", 0); set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing"); break; case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: + GPR_TIMER_MARK("state=writing_stale_with_poller", 0); set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); REF_TRANSPORT(t, "writing"); grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, @@ -815,6 +827,7 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, true); break; case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: + GPR_TIMER_MARK("state=writing_stale_no_poller", 0); set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); REF_TRANSPORT(t, "writing"); grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, @@ -824,13 +837,16 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, } UNREF_TRANSPORT(exec_ctx, t, "writing"); + GPR_TIMER_END("terminate_writing_with_lock", 0); } void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, void *transport_writing, grpc_error *error) { + GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0); grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->terminate_writing, GRPC_ERROR_REF(error)); + GPR_TIMER_END("grpc_chttp2_terminate_writing", 0); } static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, @@ -1170,6 +1186,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_transport_stream_op *op) { + GPR_TIMER_BEGIN("perform_stream_op", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked, @@ -1179,6 +1196,7 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, GRPC_CHTTP2_STREAM_REF(&s->global, "perform_stream_op"); grpc_combiner_execute(exec_ctx, t->executor.combiner, &op->transport_private.closure, GRPC_ERROR_NONE); + GPR_TIMER_END("perform_stream_op", 0); } static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, @@ -1315,6 +1333,7 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, static void check_read_ops(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) { + GPR_TIMER_BEGIN("check_read_ops", 0); grpc_chttp2_stream_global *stream_global; grpc_byte_stream *bs; while ( @@ -1389,6 +1408,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx, } } } + GPR_TIMER_END("check_read_ops", 0); } static void decrement_active_streams_locked( @@ -1830,13 +1850,17 @@ static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, reading_action_locked -> (parse_unlocked -> post_parse_locked)? -> post_reading_action_locked */ + GPR_TIMER_BEGIN("reading_action", 0); grpc_chttp2_transport *t = tp; grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->reading_action_locked, GRPC_ERROR_REF(error)); + GPR_TIMER_END("reading_action", 0); } static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { + GPR_TIMER_BEGIN("reading_action_locked", 0); + grpc_chttp2_transport *t = tp; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; @@ -1853,6 +1877,8 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, } else { post_reading_action_locked(exec_ctx, t, error); } + + GPR_TIMER_END("reading_action_locked", 0); } static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, @@ -1905,13 +1931,14 @@ static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) { GRPC_ERROR_UNREF(errors[i]); } - GPR_TIMER_END("reading_action.parse", 0); grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->post_parse_locked, err); + GPR_TIMER_END("reading_action.parse", 0); } static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + GPR_TIMER_BEGIN("post_parse_locked", 0); grpc_chttp2_transport *t = arg; grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; @@ -1956,10 +1983,12 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, } post_reading_action_locked(exec_ctx, t, error); + GPR_TIMER_END("post_parse_locked", 0); } static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + GPR_TIMER_BEGIN("post_reading_action_locked", 0); grpc_chttp2_transport *t = arg; bool keep_reading = false; GRPC_ERROR_REF(error); @@ -1992,6 +2021,8 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, UNREF_TRANSPORT(exec_ctx, t, "reading_action"); } GRPC_ERROR_UNREF(error); + + GPR_TIMER_END("post_reading_action_locked", 0); } /******************************************************************************* @@ -2112,6 +2143,7 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream, gpr_slice *slice, size_t max_size_hint, grpc_closure *on_complete) { + GPR_TIMER_BEGIN("incoming_byte_stream_next", 0); grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; gpr_ref(&bs->refs); @@ -2122,6 +2154,7 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, bs); grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, &bs->next_action.closure, GRPC_ERROR_NONE); + GPR_TIMER_END("incoming_byte_stream_next", 0); return 0; } @@ -2140,12 +2173,14 @@ static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream) { + GPR_TIMER_BEGIN("incoming_byte_stream_destroy", 0); grpc_chttp2_incoming_byte_stream *bs = (grpc_chttp2_incoming_byte_stream *)byte_stream; grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked, bs); grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, &bs->destroy_action, GRPC_ERROR_NONE); + GPR_TIMER_END("incoming_byte_stream_destroy", 0); } typedef struct { @@ -2182,6 +2217,7 @@ static void incoming_byte_stream_finished_locked(grpc_exec_ctx *exec_ctx, void grpc_chttp2_incoming_byte_stream_finished( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, grpc_error *error, int from_parsing_thread) { + GPR_TIMER_BEGIN("grpc_chttp2_incoming_byte_stream_finished", 0); if (from_parsing_thread) { grpc_closure_init(&bs->finished_action, incoming_byte_stream_finished_locked, bs); @@ -2190,6 +2226,7 @@ void grpc_chttp2_incoming_byte_stream_finished( } else { incoming_byte_stream_finished_locked(exec_ctx, bs, error); } + GPR_TIMER_END("grpc_chttp2_incoming_byte_stream_finished", 0); } grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index e0d87725e9..ad3441cfeb 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -332,6 +332,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx, void grpc_chttp2_cleanup_writing( grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing) { + GPR_TIMER_BEGIN("grpc_chttp2_cleanup_writing", 0); grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_global *stream_global; @@ -370,4 +371,5 @@ void grpc_chttp2_cleanup_writing( GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); } gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); + GPR_TIMER_END("grpc_chttp2_cleanup_writing", 0); } diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 73347d5024..ebe9fd24ec 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -32,13 +32,15 @@ */ #include "src/core/lib/iomgr/combiner.h" -#include "src/core/lib/iomgr/workqueue.h" #include #include #include +#include "src/core/lib/iomgr/workqueue.h" +#include "src/core/lib/profiling/timers.h" + struct grpc_combiner { grpc_workqueue *optional_workqueue; gpr_mpscq queue; @@ -79,15 +81,18 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + GPR_TIMER_BEGIN("combiner.continue_executing_mainline", 0); grpc_combiner *lock = arg; GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); GPR_ASSERT(exec_ctx->active_combiner == lock); exec_ctx->active_combiner = NULL; + GPR_TIMER_END("combiner.continue_executing_mainline", 0); } static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + GPR_TIMER_BEGIN("combiner.execute_final", 0); grpc_closure *c = lock->final_list.head; grpc_closure_list_init(&lock->final_list); lock->take_async_break_before_final_list = false; @@ -98,10 +103,12 @@ static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GRPC_ERROR_UNREF(error); c = next; } + GPR_TIMER_END("combiner.execute_final", 0); } static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + GPR_TIMER_BEGIN("combiner.continue_executing_final", 0); grpc_combiner *lock = arg; GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; @@ -115,23 +122,28 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, } GPR_ASSERT(exec_ctx->active_combiner == lock); exec_ctx->active_combiner = NULL; + GPR_TIMER_END("combiner.continue_executing_final", 0); } static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + GPR_TIMER_BEGIN("combiner.start_execute_final", 0); GPR_ASSERT(exec_ctx->active_combiner == lock); if (lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); + GPR_TIMER_END("combiner.start_execute_final", 0); return false; } else { execute_final(exec_ctx, lock); + GPR_TIMER_END("combiner.start_execute_final", 0); return true; } } static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + GPR_TIMER_BEGIN("combiner.maybe_finish_one", 0); gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); GPR_ASSERT(exec_ctx->active_combiner == lock); if (n == NULL) { @@ -141,18 +153,21 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); + GPR_TIMER_END("combiner.maybe_finish_one", 0); return false; } grpc_closure *cl = (grpc_closure *)n; grpc_error *error = cl->error; cl->cb(exec_ctx, cl->cb_arg, error); GRPC_ERROR_UNREF(error); + GPR_TIMER_END("combiner.maybe_finish_one", 0); return true; } static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { bool (*executor)(grpc_exec_ctx * exec_ctx, grpc_combiner * lock) = maybe_finish_one; + GPR_TIMER_BEGIN("combiner.finish",0); do { switch (gpr_atm_full_fetch_add(&lock->state, -2)) { case 5: // we're down to one queued item: if it's the final list we @@ -162,9 +177,11 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } break; case 3: // had one count, one unorphaned --> unlocked unorphaned + GPR_TIMER_END("combiner.finish", 0); return; case 2: // and one count, one orphaned --> unlocked and orphaned really_destroy(exec_ctx, lock); + GPR_TIMER_END("combiner.finish", 0); return; case 1: case 0: @@ -173,15 +190,19 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_UNREACHABLE_CODE(return ); } } while (executor(exec_ctx, lock)); + GPR_TIMER_END("combiner.finish", 0); } void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *cl, grpc_error *error) { + GPR_TIMER_BEGIN("combiner.execute", 0); gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); GPR_ASSERT(last & 1); // ensure lock has not been destroyed if (last == 1) { exec_ctx->active_combiner = lock; + GPR_TIMER_BEGIN("combiner.execute_first_cb", 0); cl->cb(exec_ctx, cl->cb_arg, error); + GPR_TIMER_END("combiner.execute_first_cb", 0); GRPC_ERROR_UNREF(error); finish(exec_ctx, lock); GPR_ASSERT(exec_ctx->active_combiner == lock); @@ -190,6 +211,7 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, cl->error = error; gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); } + GPR_TIMER_END("combiner.execute", 0); } static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, @@ -201,9 +223,12 @@ static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool force_async_break) { + GPR_TIMER_BEGIN("combiner.execute_finally", 0); if (exec_ctx->active_combiner != lock) { + GPR_TIMER_MARK("slowpath", 0); grpc_combiner_execute(exec_ctx, lock, grpc_closure_create(enqueue_finally, closure), error); + GPR_TIMER_END("combiner.execute_finally", 0); return; } @@ -214,6 +239,7 @@ void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, gpr_atm_full_fetch_add(&lock->state, 2); } grpc_closure_list_append(&lock->final_list, closure, error); + GPR_TIMER_END("combiner.execute_finally", 0); } void grpc_combiner_force_async_finally(grpc_combiner *lock) { diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 801c097566..289c7a2fe2 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -43,6 +43,7 @@ #include #include +#include "src/core/lib/profiling/timers.h" #include "src/core/lib/iomgr/ev_posix.h" static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); @@ -121,6 +122,7 @@ static void drain(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { } static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + GPR_TIMER_MARK("workqueue.wakeup", 0); grpc_error *err = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); if (!GRPC_LOG_IF_ERROR("wakeupfd_wakeup", err)) { drain(exec_ctx, workqueue); @@ -128,6 +130,8 @@ static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { } static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + GPR_TIMER_BEGIN("workqueue.on_readable", 0); + grpc_workqueue *workqueue = arg; if (error != GRPC_ERROR_NONE) { @@ -172,10 +176,13 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GRPC_ERROR_UNREF(clerr); } } + + GPR_TIMER_END("workqueue.on_readable", 0); } void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, grpc_closure *closure, grpc_error *error) { + GPR_TIMER_BEGIN("workqueue.enqueue", 0); gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, 2); GPR_ASSERT(last & 1); closure->error = error; @@ -183,6 +190,7 @@ void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, if (last == 1) { wakeup(exec_ctx, workqueue); } + GPR_TIMER_END("workqueue.enqueue", 0); } #endif /* GPR_POSIX_SOCKET */ -- cgit v1.2.3 From 9d01848ef2a933d50e5d7ed95598788614d70bc8 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 18 Jul 2016 08:53:49 -0700 Subject: Fixes --- src/core/ext/client_config/subchannel_call_holder.c | 4 ++++ .../ext/transport/chttp2/transport/chttp2_transport.c | 4 ++-- src/core/ext/transport/chttp2/transport/writing.c | 19 ++++++++++--------- src/core/lib/iomgr/ev_epoll_linux.c | 4 ++++ src/core/lib/security/transport/client_auth_filter.c | 5 +++++ src/core/lib/security/transport/secure_endpoint.c | 5 +++++ src/core/lib/surface/channel_ping.c | 2 ++ src/core/lib/surface/lame_client.c | 6 +++--- src/core/lib/surface/server.c | 7 +++++-- test/core/surface/lame_client_test.c | 6 +++--- 10 files changed, 43 insertions(+), 19 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/client_config/subchannel_call_holder.c b/src/core/ext/client_config/subchannel_call_holder.c index 7eb17c713a..b10b204ff2 100644 --- a/src/core/ext/client_config/subchannel_call_holder.c +++ b/src/core/ext/client_config/subchannel_call_holder.c @@ -207,6 +207,10 @@ typedef struct { static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) { + if (holder->waiting_ops_count == 0) { + return; + } + retry_ops_args *a = gpr_malloc(sizeof(*a)); a->ops = holder->waiting_ops; a->nops = holder->waiting_ops_count; diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 98b01426a4..edb5346dbe 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -311,7 +311,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (is_client) { gpr_slice_buffer_add( - &t->global.qbuf, + &t->writing.outbuf, gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write"); } @@ -768,7 +768,7 @@ static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "start_writing:nothing_to_write"); } - end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write")); + end_waiting_for_write(exec_ctx, t, GRPC_ERROR_NONE); UNREF_TRANSPORT(exec_ctx, t, "writing"); } GPR_TIMER_END("start_writing", 0); diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index ad3441cfeb..9e6555cdd3 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -51,15 +51,6 @@ int grpc_chttp2_unlocking_check_writes( GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0); - /* simple writes are queued to qbuf, and flushed here */ - gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf); - GPR_ASSERT(transport_global->qbuf.count == 0); - - grpc_chttp2_hpack_compressor_set_max_table_size( - &transport_writing->hpack_compressor, - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); - if (transport_global->dirtied_local_settings && !transport_global->sent_local_settings) { gpr_slice_buffer_add( @@ -73,6 +64,16 @@ int grpc_chttp2_unlocking_check_writes( transport_global->sent_local_settings = 1; } + /* simple writes are queued to qbuf, and flushed here */ + gpr_slice_buffer_move_into(&transport_global->qbuf, + &transport_writing->outbuf); + GPR_ASSERT(transport_global->qbuf.count == 0); + + grpc_chttp2_hpack_compressor_set_max_table_size( + &transport_writing->hpack_compressor, + transport_global->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, transport_global, outgoing_window); if (transport_writing->outgoing_window > 0) { diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c index 6a63c4d1d1..57c26138be 100644 --- a/src/core/lib/iomgr/ev_epoll_linux.c +++ b/src/core/lib/iomgr/ev_epoll_linux.c @@ -1526,6 +1526,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_fd *fd) { + GPR_TIMER_BEGIN("pollset_add_fd", 0); + grpc_error *error = GRPC_ERROR_NONE; gpr_mu_lock(&pollset->mu); @@ -1638,6 +1640,8 @@ retry: gpr_mu_unlock(&pollset->mu); GRPC_LOG_IF_ERROR("pollset_add_fd", error); + + GPR_TIMER_END("pollset_add_fd", 0); } /******************************************************************************* diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c index ed7929aa27..b13bd55df1 100644 --- a/src/core/lib/security/transport/client_auth_filter.c +++ b/src/core/lib/security/transport/client_auth_filter.c @@ -40,6 +40,7 @@ #include #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/profiling/timers.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/transport/security_connector.h" @@ -218,6 +219,8 @@ static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data, static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { + GPR_TIMER_BEGIN("auth_start_transport_op", 0); + /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; @@ -258,12 +261,14 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_channel_security_connector_check_call_host( exec_ctx, chand->security_connector, call_host, chand->auth_context, on_host_checked, elem); + GPR_TIMER_END("auth_start_transport_op", 0); return; /* early exit */ } } /* pass control down the stack */ grpc_call_next_op(exec_ctx, elem, op); + GPR_TIMER_END("auth_start_transport_op", 0); } /* Constructor for call_data */ diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c index 0169ccd9ef..acb0113ea8 100644 --- a/src/core/lib/security/transport/secure_endpoint.c +++ b/src/core/lib/security/transport/secure_endpoint.c @@ -38,6 +38,7 @@ #include #include #include "src/core/lib/debug/trace.h" +#include "src/core/lib/profiling/timers.h" #include "src/core/lib/security/transport/tsi_error.h" #include "src/core/lib/support/string.h" #include "src/core/lib/tsi/transport_security_interface.h" @@ -248,6 +249,8 @@ static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, gpr_slice_buffer *slices, grpc_closure *cb) { + GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0); + unsigned i; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)secure_ep; @@ -323,10 +326,12 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, exec_ctx, cb, grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result), NULL); + GPR_TIMER_END("secure_endpoint.endpoint_write", 0); return; } grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb); + GPR_TIMER_END("secure_endpoint.endpoint_write", 0); } static void endpoint_shutdown(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c index 5f9f07f89a..0d2f01a649 100644 --- a/src/core/lib/surface/channel_ping.c +++ b/src/core/lib/surface/channel_ping.c @@ -61,6 +61,8 @@ static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq, void *tag, void *reserved) { + GRPC_API_TRACE("grpc_channel_ping(channel=%p, cq=%p, tag=%p, reserved=%p)", 4, + (channel, cq, tag, reserved)); grpc_transport_op *op = grpc_make_transport_op(NULL); ping_result *pr = gpr_malloc(sizeof(*pr)); grpc_channel_element *top_elem = diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c index 5ea4cba5d1..203d614b31 100644 --- a/src/core/lib/surface/lame_client.c +++ b/src/core/lib/surface/lame_client.c @@ -97,14 +97,14 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change, GRPC_ERROR_NONE, NULL); } - if (op->on_consumed != NULL) { - grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); - } if (op->send_ping != NULL) { grpc_exec_ctx_sched(exec_ctx, op->send_ping, GRPC_ERROR_CREATE("lame client channel"), NULL); } GRPC_ERROR_UNREF(op->disconnect_with_error); + if (op->on_consumed != NULL) { + grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); + } } static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index e0b5ed6297..b6f4b5e427 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -428,7 +428,8 @@ static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd, server_unref(exec_ctx, server); } -static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) { +static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, + grpc_error *error) { if (is_channel_orphaned(chand)) return; GPR_ASSERT(chand->server != NULL); orphan_channel(chand); @@ -444,6 +445,8 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) { grpc_channel_stack_element( grpc_channel_get_channel_stack(chand->channel), 0), op); + + GRPC_LOG_IF_ERROR("disconnecting client", error); } static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { @@ -845,7 +848,7 @@ static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd, op); } else { gpr_mu_lock(&server->mu_global); - destroy_channel(exec_ctx, chand); + destroy_channel(exec_ctx, chand, GRPC_ERROR_REF(error)); gpr_mu_unlock(&server->mu_global); GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity"); } diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c index cad45cc9fa..68c1e0eab0 100644 --- a/test/core/surface/lame_client_test.c +++ b/test/core/surface/lame_client_test.c @@ -49,8 +49,8 @@ static void *tag(intptr_t x) { return (void *)x; } void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_transport_op *op = arg; - GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *op->connectivity_state); + grpc_connectivity_state *state = arg; + GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *state); GPR_ASSERT(error == GRPC_ERROR_NONE); } @@ -62,7 +62,7 @@ void test_transport_op(grpc_channel *channel) { grpc_connectivity_state state = GRPC_CHANNEL_IDLE; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - grpc_closure_init(&transport_op_cb, verify_connectivity, &op); + grpc_closure_init(&transport_op_cb, verify_connectivity, &state); op = grpc_make_transport_op(NULL); op->on_connectivity_state_change = &transport_op_cb; -- cgit v1.2.3 From e7603b887eee0bbc21225fbae7231c0e5b629e24 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 18 Jul 2016 15:43:42 -0700 Subject: Fixes & debug --- .../transport/chttp2/transport/chttp2_transport.c | 14 ++++-- src/core/lib/iomgr/combiner.c | 50 ++++++++++++++++++---- src/core/lib/iomgr/tcp_posix.c | 9 ++++ src/core/lib/surface/server.c | 7 ++- 4 files changed, 66 insertions(+), 14 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index edb5346dbe..ced74dc8ff 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1019,6 +1019,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_stream_global *stream_global = &s->global; + if (grpc_http_trace) { + char *str = grpc_transport_stream_op_string(op); + gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s", str); + gpr_free(str); + } + grpc_closure *on_complete = op->on_complete; if (on_complete == NULL) { on_complete = grpc_closure_create(do_nothing, NULL); @@ -1821,6 +1827,10 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { + if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { + error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE); + } close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); end_all_the_calls(exec_ctx, t, error); } @@ -2015,10 +2025,6 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, error = GRPC_ERROR_CREATE("Transport closed"); } if (error != GRPC_ERROR_NONE) { - if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { - error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_UNAVAILABLE); - } drop_connection(exec_ctx, t, GRPC_ERROR_REF(error)); t->endpoint_reading = 0; if (grpc_http_write_state_trace) { diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index ebe9fd24ec..c3c32cb8a3 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -41,6 +41,13 @@ #include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/profiling/timers.h" +int grpc_combiner_trace = 0; + +#define COMBINER_TRACE(fn) \ + if (grpc_combiner_trace) { \ + fn \ + } + struct grpc_combiner { grpc_workqueue *optional_workqueue; gpr_mpscq queue; @@ -60,10 +67,12 @@ grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { gpr_mpscq_init(&lock->queue); lock->take_async_break_before_final_list = false; grpc_closure_list_init(&lock->final_list); + gpr_log(GPR_DEBUG, "C:%p create", lock); return lock; } static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + gpr_log(GPR_DEBUG, "C:%p really_destroy", lock); GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); @@ -71,7 +80,10 @@ static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - if (gpr_atm_full_fetch_add(&lock->state, -1) == 1) { + gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -1); + gpr_log(GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, + old_state); + if (old_state == 1) { really_destroy(exec_ctx, lock); } } @@ -83,6 +95,7 @@ static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("combiner.continue_executing_mainline", 0); grpc_combiner *lock = arg; + gpr_log(GPR_DEBUG, "C:%p continue_finishing_mainline", lock); GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); @@ -94,14 +107,18 @@ static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_TIMER_BEGIN("combiner.execute_final", 0); grpc_closure *c = lock->final_list.head; + GPR_ASSERT(c != NULL); grpc_closure_list_init(&lock->final_list); lock->take_async_break_before_final_list = false; + int loops = 0; while (c != NULL) { + gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c); grpc_closure *next = c->next_data.next; grpc_error *error = c->error; c->cb(exec_ctx, c->cb_arg, error); GRPC_ERROR_UNREF(error); c = next; + loops++; } GPR_TIMER_END("combiner.execute_final", 0); } @@ -110,6 +127,7 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("combiner.continue_executing_final", 0); grpc_combiner *lock = arg; + gpr_log(GPR_DEBUG, "C:%p continue_executing_final", lock); GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; // quick peek to see if new things have turned up on the queue: if so, go back @@ -128,6 +146,9 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_TIMER_BEGIN("combiner.start_execute_final", 0); GPR_ASSERT(exec_ctx->active_combiner == lock); + gpr_log(GPR_DEBUG, + "C:%p start_execute_final take_async_break_before_final_list=%d", + lock, lock->take_async_break_before_final_list); if (lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); @@ -145,6 +166,7 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_TIMER_BEGIN("combiner.maybe_finish_one", 0); gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); + gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n); GPR_ASSERT(exec_ctx->active_combiner == lock); if (n == NULL) { // queue is in an inconsistant state: use this as a cue that we should @@ -160,16 +182,21 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { grpc_error *error = cl->error; cl->cb(exec_ctx, cl->cb_arg, error); GRPC_ERROR_UNREF(error); - GPR_TIMER_END("combiner.maybe_finish_one", 0); + GPR_TIMER_END("combiner.maybe_finish_one", 0); return true; } static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - bool (*executor)(grpc_exec_ctx * exec_ctx, grpc_combiner * lock) = - maybe_finish_one; - GPR_TIMER_BEGIN("combiner.finish",0); + bool (*executor)(grpc_exec_ctx * exec_ctx, grpc_combiner * lock); + GPR_TIMER_BEGIN("combiner.finish", 0); + int loops = 0; do { - switch (gpr_atm_full_fetch_add(&lock->state, -2)) { + executor = maybe_finish_one; + gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2); + gpr_log(GPR_DEBUG, "C:%p finish[%d] old_state=%" PRIdPTR " cl=[%p,%p]", + lock, loops, old_state, lock->final_list.head, + lock->final_list.tail); + switch (old_state) { case 5: // we're down to one queued item: if it's the final list we case 4: // should do that if (!grpc_closure_list_empty(lock->final_list)) { @@ -189,12 +216,14 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { // deleted lock GPR_UNREACHABLE_CODE(return ); } + loops++; } while (executor(exec_ctx, lock)); - GPR_TIMER_END("combiner.finish", 0); + GPR_TIMER_END("combiner.finish", 0); } void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *cl, grpc_error *error) { + gpr_log(GPR_DEBUG, "C:%p grpc_combiner_execute c=%p", lock, cl); GPR_TIMER_BEGIN("combiner.execute", 0); gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); GPR_ASSERT(last & 1); // ensure lock has not been destroyed @@ -217,12 +246,15 @@ void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, grpc_error *error) { grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure, - GRPC_ERROR_REF(error), true); + GRPC_ERROR_REF(error), false); } void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool force_async_break) { + gpr_log(GPR_DEBUG, + "C:%p grpc_combiner_execute_finally c=%p force_async_break=%d; ac=%p", + lock, closure, force_async_break, exec_ctx->active_combiner); GPR_TIMER_BEGIN("combiner.execute_finally", 0); if (exec_ctx->active_combiner != lock) { GPR_TIMER_MARK("slowpath", 0); @@ -239,7 +271,7 @@ void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, gpr_atm_full_fetch_add(&lock->state, 2); } grpc_closure_list_append(&lock->final_list, closure, error); - GPR_TIMER_END("combiner.execute_finally", 0); + GPR_TIMER_END("combiner.execute_finally", 0); } void grpc_combiner_force_async_finally(grpc_combiner *lock) { diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c index ec21e03944..bf6e9b16b3 100644 --- a/src/core/lib/iomgr/tcp_posix.c +++ b/src/core/lib/iomgr/tcp_posix.c @@ -379,10 +379,15 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, } if (!tcp_flush(tcp, &error)) { + gpr_log(GPR_DEBUG, "write: delayed"); grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { cb = tcp->write_cb; tcp->write_cb = NULL; + const char *str = grpc_error_string(error); + gpr_log(GPR_DEBUG, "write: %s", str); + grpc_error_free_string(str); + GPR_TIMER_BEGIN("tcp_handle_write.cb", 0); cb->cb(exec_ctx, cb->cb_arg, error); GPR_TIMER_END("tcp_handle_write.cb", 0); @@ -425,8 +430,12 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); tcp->write_cb = cb; + gpr_log(GPR_DEBUG, "write: delayed"); grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { + const char *str = grpc_error_string(error); + gpr_log(GPR_DEBUG, "write: %s", str); + grpc_error_free_string(str); grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); } diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index b6f4b5e427..964333c57b 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -446,7 +446,12 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, grpc_channel_get_channel_stack(chand->channel), 0), op); - GRPC_LOG_IF_ERROR("disconnecting client", error); + if (error != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(error); + gpr_log(GPR_INFO, "Disconnected client: %s", msg); + grpc_error_free_string(msg); + } + GRPC_ERROR_UNREF(error); } static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { -- cgit v1.2.3 From c3df7b4924227d60589e5b1fc3d1f809815e88c2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 18 Jul 2016 15:51:26 -0700 Subject: Get traces around everything --- src/core/lib/iomgr/combiner.c | 53 ++++++++++++++++++++++++------------------ src/core/lib/iomgr/combiner.h | 2 ++ src/core/lib/iomgr/error.c | 2 +- src/core/lib/iomgr/tcp_posix.c | 24 ++++++++++++------- src/core/lib/surface/init.c | 2 ++ 5 files changed, 52 insertions(+), 31 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index c3c32cb8a3..eb476c0572 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -43,10 +43,12 @@ int grpc_combiner_trace = 0; -#define COMBINER_TRACE(fn) \ - if (grpc_combiner_trace) { \ - fn \ - } +#define GRPC_COMBINER_TRACE(fn) \ + do { \ + if (grpc_combiner_trace) { \ + fn; \ + } \ + } while (0) struct grpc_combiner { grpc_workqueue *optional_workqueue; @@ -67,12 +69,12 @@ grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { gpr_mpscq_init(&lock->queue); lock->take_async_break_before_final_list = false; grpc_closure_list_init(&lock->final_list); - gpr_log(GPR_DEBUG, "C:%p create", lock); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock)); return lock; } static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - gpr_log(GPR_DEBUG, "C:%p really_destroy", lock); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock)); GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); gpr_mpscq_destroy(&lock->queue); GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); @@ -81,8 +83,8 @@ static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -1); - gpr_log(GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, - old_state); + GRPC_COMBINER_TRACE(gpr_log( + GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state)); if (old_state == 1) { really_destroy(exec_ctx, lock); } @@ -95,7 +97,8 @@ static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("combiner.continue_executing_mainline", 0); grpc_combiner *lock = arg; - gpr_log(GPR_DEBUG, "C:%p continue_finishing_mainline", lock); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p continue_finishing_mainline", lock)); GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); @@ -112,7 +115,8 @@ static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { lock->take_async_break_before_final_list = false; int loops = 0; while (c != NULL) { - gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c)); grpc_closure *next = c->next_data.next; grpc_error *error = c->error; c->cb(exec_ctx, c->cb_arg, error); @@ -127,7 +131,8 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("combiner.continue_executing_final", 0); grpc_combiner *lock = arg; - gpr_log(GPR_DEBUG, "C:%p continue_executing_final", lock); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p continue_executing_final", lock)); GPR_ASSERT(exec_ctx->active_combiner == NULL); exec_ctx->active_combiner = lock; // quick peek to see if new things have turned up on the queue: if so, go back @@ -146,9 +151,10 @@ static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_TIMER_BEGIN("combiner.start_execute_final", 0); GPR_ASSERT(exec_ctx->active_combiner == lock); - gpr_log(GPR_DEBUG, - "C:%p start_execute_final take_async_break_before_final_list=%d", - lock, lock->take_async_break_before_final_list); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, + "C:%p start_execute_final take_async_break_before_final_list=%d", + lock, lock->take_async_break_before_final_list)); if (lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); @@ -166,7 +172,8 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { GPR_TIMER_BEGIN("combiner.maybe_finish_one", 0); gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); - gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n)); GPR_ASSERT(exec_ctx->active_combiner == lock); if (n == NULL) { // queue is in an inconsistant state: use this as a cue that we should @@ -193,9 +200,9 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { do { executor = maybe_finish_one; gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2); - gpr_log(GPR_DEBUG, "C:%p finish[%d] old_state=%" PRIdPTR " cl=[%p,%p]", - lock, loops, old_state, lock->final_list.head, - lock->final_list.tail); + GRPC_COMBINER_TRACE(gpr_log( + GPR_DEBUG, "C:%p finish[%d] old_state=%" PRIdPTR " cl=[%p,%p]", lock, + loops, old_state, lock->final_list.head, lock->final_list.tail)); switch (old_state) { case 5: // we're down to one queued item: if it's the final list we case 4: // should do that @@ -223,7 +230,8 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *cl, grpc_error *error) { - gpr_log(GPR_DEBUG, "C:%p grpc_combiner_execute c=%p", lock, cl); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p grpc_combiner_execute c=%p", lock, cl)); GPR_TIMER_BEGIN("combiner.execute", 0); gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); GPR_ASSERT(last & 1); // ensure lock has not been destroyed @@ -252,9 +260,10 @@ static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool force_async_break) { - gpr_log(GPR_DEBUG, - "C:%p grpc_combiner_execute_finally c=%p force_async_break=%d; ac=%p", - lock, closure, force_async_break, exec_ctx->active_combiner); + GRPC_COMBINER_TRACE(gpr_log( + GPR_DEBUG, + "C:%p grpc_combiner_execute_finally c=%p force_async_break=%d; ac=%p", + lock, closure, force_async_break, exec_ctx->active_combiner)); GPR_TIMER_BEGIN("combiner.execute_finally", 0); if (exec_ctx->active_combiner != lock) { GPR_TIMER_MARK("slowpath", 0); diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 5b94d5bd99..3eb9f34638 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -64,4 +64,6 @@ void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, bool hint_async_break); void grpc_combiner_force_async_finally(grpc_combiner *lock); +extern int grpc_combiner_trace; + #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c index 149c55663c..e366961936 100644 --- a/src/core/lib/iomgr/error.c +++ b/src/core/lib/iomgr/error.c @@ -332,7 +332,7 @@ grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) { return new; } -static const char *no_error_string = "null"; +static const char *no_error_string = "\"No Error\""; static const char *oom_error_string = "\"Out of memory\""; static const char *cancelled_error_string = "\"Cancelled\""; diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c index bf6e9b16b3..fa4b72acbb 100644 --- a/src/core/lib/iomgr/tcp_posix.c +++ b/src/core/lib/iomgr/tcp_posix.c @@ -379,14 +379,18 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, } if (!tcp_flush(tcp, &error)) { - gpr_log(GPR_DEBUG, "write: delayed"); + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "write: delayed"); + } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { cb = tcp->write_cb; tcp->write_cb = NULL; - const char *str = grpc_error_string(error); - gpr_log(GPR_DEBUG, "write: %s", str); - grpc_error_free_string(str); + if (grpc_tcp_trace) { + const char *str = grpc_error_string(error); + gpr_log(GPR_DEBUG, "write: %s", str); + grpc_error_free_string(str); + } GPR_TIMER_BEGIN("tcp_handle_write.cb", 0); cb->cb(exec_ctx, cb->cb_arg, error); @@ -430,12 +434,16 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); tcp->write_cb = cb; - gpr_log(GPR_DEBUG, "write: delayed"); + if (grpc_tcp_trace) { + gpr_log(GPR_DEBUG, "write: delayed"); + } grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure); } else { - const char *str = grpc_error_string(error); - gpr_log(GPR_DEBUG, "write: %s", str); - grpc_error_free_string(str); + if (grpc_tcp_trace) { + const char *str = grpc_error_string(error); + gpr_log(GPR_DEBUG, "write: %s", str); + grpc_error_free_string(str); + } grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); } diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c index 5397913a21..edda0c85fa 100644 --- a/src/core/lib/surface/init.c +++ b/src/core/lib/surface/init.c @@ -47,6 +47,7 @@ #include "src/core/lib/channel/http_server_filter.h" #include "src/core/lib/debug/trace.h" #include "src/core/lib/http/parser.h" +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/profiling/timers.h" @@ -165,6 +166,7 @@ void grpc_init(void) { grpc_register_tracer("http1", &grpc_http1_trace); grpc_register_tracer("compression", &grpc_compression_trace); grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace); + grpc_register_tracer("combiner", &grpc_combiner_trace); // Default pluck trace to 1 grpc_cq_pluck_trace = 1; grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace); -- cgit v1.2.3 From 2da58cf638805764e0ce4d2dfe484604c0cda343 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 19 Jul 2016 17:09:22 -0700 Subject: Force queuing to workqueue instead of relying on exec_ctx --- src/core/lib/iomgr/combiner.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index eb476c0572..25b2ec3d4c 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -155,11 +155,12 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_log(GPR_DEBUG, "C:%p start_execute_final take_async_break_before_final_list=%d", lock, lock->take_async_break_before_final_list)); - if (lock->take_async_break_before_final_list) { + if (lock->optional_workqueue != NULL && + lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); - grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); + grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, + &lock->continue_finishing, GRPC_ERROR_NONE); GPR_TIMER_END("combiner.start_execute_final", 0); return false; } else { -- cgit v1.2.3 From 292b7cb3e14fa7cf51e683deefb05267c01f3472 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 4 Aug 2016 11:34:01 -0700 Subject: clang-format --- src/core/ext/transport/chttp2/transport/parsing.c | 4 ++-- src/core/lib/iomgr/workqueue_posix.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c index cd128c3310..0e6d579ba9 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.c +++ b/src/core/ext/transport/chttp2/transport/parsing.c @@ -87,8 +87,8 @@ void grpc_chttp2_prepare_to_read( transport_global->settings[GRPC_SENT_SETTINGS], sizeof(transport_parsing->last_sent_settings)); transport_parsing->max_frame_size = - transport_global - ->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]; + transport_global->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]; /* update the parsing view of incoming window */ while (grpc_chttp2_list_pop_unannounced_incoming_window_available( diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c index 289c7a2fe2..ecfea68f56 100644 --- a/src/core/lib/iomgr/workqueue_posix.c +++ b/src/core/lib/iomgr/workqueue_posix.c @@ -43,8 +43,8 @@ #include #include -#include "src/core/lib/profiling/timers.h" #include "src/core/lib/iomgr/ev_posix.h" +#include "src/core/lib/profiling/timers.h" static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); @@ -131,7 +131,7 @@ static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GPR_TIMER_BEGIN("workqueue.on_readable", 0); - + grpc_workqueue *workqueue = arg; if (error != GRPC_ERROR_NONE) { @@ -176,7 +176,7 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GRPC_ERROR_UNREF(clerr); } } - + GPR_TIMER_END("workqueue.on_readable", 0); } -- cgit v1.2.3 From 427d7d71dc963e32d04120479b6e0ad53ae726a7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 4 Aug 2016 12:11:08 -0700 Subject: Fix tsan reported error in trace --- src/core/lib/iomgr/combiner.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 25b2ec3d4c..eb5ad634bd 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -155,12 +155,11 @@ static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_log(GPR_DEBUG, "C:%p start_execute_final take_async_break_before_final_list=%d", lock, lock->take_async_break_before_final_list)); - if (lock->optional_workqueue != NULL && - lock->take_async_break_before_final_list) { + if (lock->take_async_break_before_final_list) { grpc_closure_init(&lock->continue_finishing, continue_executing_final, lock); - grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, - &lock->continue_finishing, GRPC_ERROR_NONE); + grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, + GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); GPR_TIMER_END("combiner.start_execute_final", 0); return false; } else { @@ -201,9 +200,9 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { do { executor = maybe_finish_one; gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2); - GRPC_COMBINER_TRACE(gpr_log( - GPR_DEBUG, "C:%p finish[%d] old_state=%" PRIdPTR " cl=[%p,%p]", lock, - loops, old_state, lock->final_list.head, lock->final_list.tail)); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, + "C:%p finish[%d] old_state=%" PRIdPTR, lock, + loops, old_state)); switch (old_state) { case 5: // we're down to one queued item: if it's the final list we case 4: // should do that -- cgit v1.2.3 From 23aff2e0cd188c0ce6e7949a1b0ff253e3eebf8f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 2 Sep 2016 09:18:27 -0700 Subject: Improve comment --- src/core/lib/iomgr/combiner.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 3eb9f34638..57df8f0ba8 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -54,14 +54,16 @@ void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); // Execute \a action within the lock just prior to unlocking. -// if \a hint_async_break is additionally set, the combiner is tries to trip -// through the workqueue between finishing the primary queue of combined -// closures and executing the finally list. +// if \a hint_async_break is true, the combiner is tries to hand execution to +// another thread before finishing the primary queue of combined closures and +// executing the finally list. +// Deprecation warning: \a hint_async_break will be removed in a future version // Takes a very slow and round-about path if not called from a -// grpc_combiner_execute closure +// grpc_combiner_execute closure. void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, bool hint_async_break); +// Deprecated: force the finally list execution onto another thread void grpc_combiner_force_async_finally(grpc_combiner *lock); extern int grpc_combiner_trace; -- cgit v1.2.3 From f6b6d2984157cc24ee69afb9b025b5d250a5a9ad Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 2 Sep 2016 09:27:26 -0700 Subject: Address review comments --- src/core/lib/iomgr/combiner.c | 9 +++++++-- src/core/lib/iomgr/combiner.h | 2 +- src/core/lib/support/mpscq.c | 11 +++++++---- src/core/lib/support/mpscq.h | 4 ++-- test/core/iomgr/combiner_test.c | 3 ++- 5 files changed, 19 insertions(+), 10 deletions(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index eb5ad634bd..831bdb4aff 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -176,8 +176,10 @@ static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n)); GPR_ASSERT(exec_ctx->active_combiner == lock); if (n == NULL) { - // queue is in an inconsistant state: use this as a cue that we should - // go off and do something else for a while (and come back later) + // Queue is in an transiently inconsistent state: a new item is being queued + // but is not visible to this thread yet. + // Use this as a cue that we should go off and do something else for a while + // (and come back later) grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, lock); grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, @@ -204,6 +206,9 @@ static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { "C:%p finish[%d] old_state=%" PRIdPTR, lock, loops, old_state)); switch (old_state) { + default: + // we have multiple queued work items: just continue executing them + break; case 5: // we're down to one queued item: if it's the final list we case 4: // should do that if (!grpc_closure_list_empty(lock->final_list)) { diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 57df8f0ba8..08acbb7441 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -41,7 +41,7 @@ #include "src/core/lib/support/mpscq.h" // Provides serialized access to some resource. -// Each action queued on an aelock is executed serially in a borrowed thread. +// Each action queued on a combiner is executed serially in a borrowed thread. // The actual thread executing actions may change over time (but there will only // every be one at a time). diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c index 25b055b172..cdd6335f82 100644 --- a/src/core/lib/support/mpscq.c +++ b/src/core/lib/support/mpscq.c @@ -38,7 +38,7 @@ void gpr_mpscq_init(gpr_mpscq *q) { gpr_atm_no_barrier_store(&q->head, (gpr_atm)&q->stub); q->tail = &q->stub; - gpr_atm_no_barrier_store(&q->stub.next, 0); + gpr_atm_no_barrier_store(&q->stub.next, (gpr_atm)NULL); } void gpr_mpscq_destroy(gpr_mpscq *q) { @@ -47,16 +47,17 @@ void gpr_mpscq_destroy(gpr_mpscq *q) { } void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) { - gpr_atm_no_barrier_store(&n->next, 0); + gpr_atm_no_barrier_store(&n->next, (gpr_atm)NULL); gpr_mpscq_node *prev = (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n); - gpr_atm_rel_store(&prev->next, (gpr_atm)n); + gpr_atm_no_barrier_store(&prev->next, (gpr_atm)n); } gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { gpr_mpscq_node *tail = q->tail; gpr_mpscq_node *next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); if (tail == &q->stub) { + // indicates the list is actually (ephemerally) empty if (next == NULL) return NULL; q->tail = next; tail = next; @@ -68,7 +69,8 @@ gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { } gpr_mpscq_node *head = (gpr_mpscq_node *)gpr_atm_acq_load(&q->head); if (tail != head) { - return 0; + // indicates a retry is in order: we're still adding + return NULL; } gpr_mpscq_push(q, &q->stub); next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next); @@ -76,5 +78,6 @@ gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { q->tail = next; return tail; } + // indicates a retry is in order: we're still adding return NULL; } diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h index 1201edceb1..977a117952 100644 --- a/src/core/lib/support/mpscq.h +++ b/src/core/lib/support/mpscq.h @@ -41,8 +41,8 @@ // implementation from Dmitry Vyukov here: // http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue -// List node (include this in a data structure and dangle the rest of the -// interesting bits off the end) +// List node (include this in a data structure at the top, and add application +// fields after it - to simulate inheritance) typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node; // Actual queue type diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c index 7cf016d82c..197998c1e5 100644 --- a/test/core/iomgr/combiner_test.c +++ b/test/core/iomgr/combiner_test.c @@ -80,7 +80,6 @@ typedef struct { static void check_one(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) { ex_args *args = a; - // gpr_log(GPR_DEBUG, "*%p=%d; step %d", args->ctr, *args->ctr, args->value); GPR_ASSERT(*args->ctr == args->value - 1); *args->ctr = args->value; gpr_free(a); @@ -99,6 +98,8 @@ static void execute_many_loop(void *a) { grpc_closure_create(check_one, c), GRPC_ERROR_NONE); grpc_exec_ctx_flush(&exec_ctx); } + // sleep for a little bit, to test a combiner draining and another thread + // picking it up gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100)); } grpc_exec_ctx_finish(&exec_ctx); -- cgit v1.2.3 From 62622970cd0a38507f71dde73d1f2c75e413306f Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 2 Sep 2016 10:18:03 -0700 Subject: Fix typo --- src/core/lib/iomgr/combiner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/lib') diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 08acbb7441..1409db24b9 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -54,7 +54,7 @@ void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error); // Execute \a action within the lock just prior to unlocking. -// if \a hint_async_break is true, the combiner is tries to hand execution to +// if \a hint_async_break is true, the combiner tries to hand execution to // another thread before finishing the primary queue of combined closures and // executing the finally list. // Deprecation warning: \a hint_async_break will be removed in a future version -- cgit v1.2.3 From 78dc25e86b090c7fa26e77ce6521a30002d150be Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 2 Sep 2016 14:36:56 -0700 Subject: Revert barrier change to restore TSAN passing --- src/core/lib/support/mpscq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/lib') diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c index cdd6335f82..5b9323275a 100644 --- a/src/core/lib/support/mpscq.c +++ b/src/core/lib/support/mpscq.c @@ -50,7 +50,7 @@ void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) { gpr_atm_no_barrier_store(&n->next, (gpr_atm)NULL); gpr_mpscq_node *prev = (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n); - gpr_atm_no_barrier_store(&prev->next, (gpr_atm)n); + gpr_atm_rel_store(&prev->next, (gpr_atm)n); } gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) { -- cgit v1.2.3