aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/lib/channel/channel_stack.h2
-rw-r--r--src/core/lib/gpr/arena.cc88
-rw-r--r--src/core/lib/iomgr/executor.cc220
-rw-r--r--src/core/lib/iomgr/executor.h45
-rw-r--r--src/core/lib/iomgr/resolve_address_posix.cc5
-rw-r--r--src/core/lib/iomgr/resolve_address_windows.cc5
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc5
-rw-r--r--src/core/lib/security/security_connector/security_connector.cc9
-rw-r--r--src/core/lib/surface/call.cc3
-rw-r--r--src/core/lib/surface/version.cc2
-rw-r--r--src/cpp/common/version_cc.cc2
-rw-r--r--src/cpp/server/channelz/channelz_service.cc57
-rw-r--r--src/cpp/server/channelz/channelz_service.h43
-rw-r--r--src/cpp/server/channelz/channelz_service_plugin.cc79
-rwxr-xr-xsrc/csharp/Grpc.Core/Grpc.Core.csproj26
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeExtension.cs24
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs19
-rw-r--r--src/csharp/Grpc.Core/Internal/PlatformApis.cs34
-rwxr-xr-xsrc/csharp/Grpc.Core/Version.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rw-r--r--src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets21
-rw-r--r--src/csharp/Grpc.Core/build/Xamarin.iOS/Grpc.Core.targets15
-rw-r--r--src/csharp/Grpc.Core/build/net45/Grpc.Core.targets (renamed from src/csharp/Grpc.Core/Grpc.Core.targets)0
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat2
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.sh6
-rw-r--r--src/csharp/doc/docfx.json2
-rwxr-xr-xsrc/csharp/experimental/build_native_ext_for_android.sh25
-rwxr-xr-xsrc/csharp/experimental/build_native_ext_for_ios.sh62
-rw-r--r--src/objective-c/!ProtoCompiler-gRPCPlugin.podspec2
-rw-r--r--src/objective-c/GRPCClient/private/version.h2
-rw-r--r--src/objective-c/tests/version.h2
-rw-r--r--src/php/composer.json2
-rw-r--r--src/php/ext/grpc/version.h2
-rw-r--r--src/proto/grpc/testing/echo_messages.proto1
-rw-r--r--src/python/grpcio/grpc/_grpcio_metadata.py2
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio_health_checking/grpc_version.py2
-rw-r--r--src/python/grpcio_reflection/grpc_version.py2
-rw-r--r--src/python/grpcio_testing/grpc_version.py2
-rw-r--r--src/python/grpcio_tests/grpc_version.py2
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rw-r--r--src/ruby/tools/version.rb2
42 files changed, 682 insertions, 152 deletions
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 7581f937b6..35c3fb01ea 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -82,7 +82,7 @@ typedef struct {
typedef struct {
grpc_call_stats stats;
grpc_status_code final_status;
- const char** error_string;
+ const char* error_string;
} grpc_call_final_info;
/* Channel filters specify:
diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc
index 141de69426..e30b297aea 100644
--- a/src/core/lib/gpr/arena.cc
+++ b/src/core/lib/gpr/arena.cc
@@ -25,6 +25,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
#include "src/core/lib/gpr/alloc.h"
@@ -36,8 +37,6 @@
#ifdef SIMPLE_ARENA_FOR_DEBUGGING
-#include <grpc/support/sync.h>
-
struct gpr_arena {
gpr_mu mu;
void** ptrs;
@@ -78,14 +77,17 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
// would allow us to use the alignment actually needed by the caller.
typedef struct zone {
- size_t size_begin;
- size_t size_end;
- gpr_atm next_atm;
+ size_t size_begin; // All the space we have set aside for allocations up
+ // until this zone.
+ size_t size_end; // size_end = size_begin plus all the space we set aside for
+ // allocations in zone z itself.
+ zone* next;
} zone;
struct gpr_arena {
gpr_atm size_so_far;
zone initial_zone;
+ gpr_mu arena_growth_mutex;
};
static void* zalloc_aligned(size_t size) {
@@ -99,15 +101,17 @@ gpr_arena* gpr_arena_create(size_t initial_size) {
gpr_arena* a = static_cast<gpr_arena*>(zalloc_aligned(
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size));
a->initial_zone.size_end = initial_size;
+ gpr_mu_init(&a->arena_growth_mutex);
return a;
}
size_t gpr_arena_destroy(gpr_arena* arena) {
+ gpr_mu_destroy(&arena->arena_growth_mutex);
gpr_atm size = gpr_atm_no_barrier_load(&arena->size_so_far);
- zone* z = (zone*)gpr_atm_no_barrier_load(&arena->initial_zone.next_atm);
+ zone* z = arena->initial_zone.next;
gpr_free_aligned(arena);
while (z) {
- zone* next_z = (zone*)gpr_atm_no_barrier_load(&z->next_atm);
+ zone* next_z = z->next;
gpr_free_aligned(z);
z = next_z;
}
@@ -116,37 +120,55 @@ size_t gpr_arena_destroy(gpr_arena* arena) {
void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size);
- size_t start = static_cast<size_t>(
+ size_t previous_size_of_arena_allocations = static_cast<size_t>(
gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size));
+ size_t updated_size_of_arena_allocations =
+ previous_size_of_arena_allocations + size;
zone* z = &arena->initial_zone;
- while (start > z->size_end) {
- zone* next_z = (zone*)gpr_atm_acq_load(&z->next_atm);
- if (next_z == nullptr) {
- size_t next_z_size =
- static_cast<size_t>(gpr_atm_no_barrier_load(&arena->size_so_far));
- next_z = static_cast<zone*>(zalloc_aligned(
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + next_z_size));
- next_z->size_begin = z->size_end;
- next_z->size_end = z->size_end + next_z_size;
- if (!gpr_atm_rel_cas(&z->next_atm, static_cast<gpr_atm>(NULL),
- (gpr_atm)next_z)) {
- gpr_free_aligned(next_z);
- next_z = (zone*)gpr_atm_acq_load(&z->next_atm);
+ // Check to see if the allocation isn't able to end in the initial zone.
+ // This statement is true only in the uncommon case because of our arena
+ // sizing historesis (that is, most calls should have a large enough initial
+ // zone and will not need to grow the arena).
+ if (updated_size_of_arena_allocations > z->size_end) {
+ // Find a zone to fit this allocation
+ gpr_mu_lock(&arena->arena_growth_mutex);
+ while (updated_size_of_arena_allocations > z->size_end) {
+ if (z->next == nullptr) {
+ // Note that we do an extra increment of size_so_far to prevent multiple
+ // simultaneous callers from stepping on each other. However, this extra
+ // increment means some space in the arena is wasted.
+ // So whenever we need to allocate x bytes and there are x - n (where
+ // n > 0) remaining in the current zone, we will waste x bytes (x - n
+ // in the current zone and n in the new zone).
+ previous_size_of_arena_allocations = static_cast<size_t>(
+ gpr_atm_no_barrier_fetch_add(&arena->size_so_far, size));
+ updated_size_of_arena_allocations =
+ previous_size_of_arena_allocations + size;
+ size_t next_z_size = updated_size_of_arena_allocations;
+ z->next = static_cast<zone*>(zalloc_aligned(
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + next_z_size));
+ z->next->size_begin = z->size_end;
+ z->next->size_end = z->size_end + next_z_size;
}
+ z = z->next;
}
- z = next_z;
- }
- if (start + size > z->size_end) {
- return gpr_arena_alloc(arena, size);
+ gpr_mu_unlock(&arena->arena_growth_mutex);
}
- GPR_ASSERT(start >= z->size_begin);
- GPR_ASSERT(start + size <= z->size_end);
- char* ptr = (z == &arena->initial_zone)
- ? reinterpret_cast<char*>(arena) +
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena))
- : reinterpret_cast<char*>(z) +
- GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
- return ptr + start - z->size_begin;
+ GPR_ASSERT(previous_size_of_arena_allocations >= z->size_begin);
+ GPR_ASSERT(updated_size_of_arena_allocations <= z->size_end);
+ // Skip the first part of the zone, which just contains tracking information.
+ // For the initial zone, this is the gpr_arena struct and for any other zone,
+ // it's the zone struct.
+ char* start_of_allocation_space =
+ (z == &arena->initial_zone)
+ ? reinterpret_cast<char*>(arena) +
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena))
+ : reinterpret_cast<char*>(z) +
+ GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
+ // previous_size_of_arena_allocations - size_begin is how many bytes have been
+ // allocated into the current zone
+ return start_of_allocation_space + previous_size_of_arena_allocations -
+ z->size_begin;
}
#endif // SIMPLE_ARENA_FOR_DEBUGGING
diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc
index 1ad13b831d..45d96b80eb 100644
--- a/src/core/lib/iomgr/executor.cc
+++ b/src/core/lib/iomgr/executor.cc
@@ -40,19 +40,25 @@
gpr_log(GPR_INFO, "EXECUTOR " format, __VA_ARGS__); \
}
+#define EXECUTOR_TRACE0(str) \
+ if (executor_trace.enabled()) { \
+ gpr_log(GPR_INFO, "EXECUTOR " str); \
+ }
+
grpc_core::TraceFlag executor_trace(false, "executor");
GPR_TLS_DECL(g_this_thread_state);
-GrpcExecutor::GrpcExecutor(const char* executor_name) : name_(executor_name) {
+GrpcExecutor::GrpcExecutor(const char* name) : name_(name) {
adding_thread_lock_ = GPR_SPINLOCK_STATIC_INITIALIZER;
- gpr_atm_no_barrier_store(&num_threads_, 0);
+ gpr_atm_rel_store(&num_threads_, 0);
max_threads_ = GPR_MAX(1, 2 * gpr_cpu_num_cores());
}
void GrpcExecutor::Init() { SetThreading(true); }
-size_t GrpcExecutor::RunClosures(grpc_closure_list list) {
+size_t GrpcExecutor::RunClosures(const char* executor_name,
+ grpc_closure_list list) {
size_t n = 0;
grpc_closure* c = list.head;
@@ -60,11 +66,11 @@ size_t GrpcExecutor::RunClosures(grpc_closure_list list) {
grpc_closure* next = c->next_data.next;
grpc_error* error = c->error_data.error;
#ifndef NDEBUG
- EXECUTOR_TRACE("run %p [created by %s:%d]", c, c->file_created,
- c->line_created);
+ EXECUTOR_TRACE("(%s) run %p [created by %s:%d]", executor_name, c,
+ c->file_created, c->line_created);
c->scheduled = false;
#else
- EXECUTOR_TRACE("run %p", c);
+ EXECUTOR_TRACE("(%s) run %p", executor_name, c);
#endif
c->cb(c->cb_arg, error);
GRPC_ERROR_UNREF(error);
@@ -77,17 +83,21 @@ size_t GrpcExecutor::RunClosures(grpc_closure_list list) {
}
bool GrpcExecutor::IsThreaded() const {
- return gpr_atm_no_barrier_load(&num_threads_) > 0;
+ return gpr_atm_acq_load(&num_threads_) > 0;
}
void GrpcExecutor::SetThreading(bool threading) {
- gpr_atm curr_num_threads = gpr_atm_no_barrier_load(&num_threads_);
+ gpr_atm curr_num_threads = gpr_atm_acq_load(&num_threads_);
+ EXECUTOR_TRACE("(%s) SetThreading(%d) begin", name_, threading);
if (threading) {
- if (curr_num_threads > 0) return;
+ if (curr_num_threads > 0) {
+ EXECUTOR_TRACE("(%s) SetThreading(true). curr_num_threads == 0", name_);
+ return;
+ }
GPR_ASSERT(num_threads_ == 0);
- gpr_atm_no_barrier_store(&num_threads_, 1);
+ gpr_atm_rel_store(&num_threads_, 1);
gpr_tls_init(&g_this_thread_state);
thd_state_ = static_cast<ThreadState*>(
gpr_zalloc(sizeof(ThreadState) * max_threads_));
@@ -96,6 +106,7 @@ void GrpcExecutor::SetThreading(bool threading) {
gpr_mu_init(&thd_state_[i].mu);
gpr_cv_init(&thd_state_[i].cv);
thd_state_[i].id = i;
+ thd_state_[i].name = name_;
thd_state_[i].thd = grpc_core::Thread();
thd_state_[i].elems = GRPC_CLOSURE_LIST_INIT;
}
@@ -104,7 +115,10 @@ void GrpcExecutor::SetThreading(bool threading) {
grpc_core::Thread(name_, &GrpcExecutor::ThreadMain, &thd_state_[0]);
thd_state_[0].thd.Start();
} else { // !threading
- if (curr_num_threads == 0) return;
+ if (curr_num_threads == 0) {
+ EXECUTOR_TRACE("(%s) SetThreading(false). curr_num_threads == 0", name_);
+ return;
+ }
for (size_t i = 0; i < max_threads_; i++) {
gpr_mu_lock(&thd_state_[i].mu);
@@ -121,20 +135,22 @@ void GrpcExecutor::SetThreading(bool threading) {
curr_num_threads = gpr_atm_no_barrier_load(&num_threads_);
for (gpr_atm i = 0; i < curr_num_threads; i++) {
thd_state_[i].thd.Join();
- EXECUTOR_TRACE(" Thread %" PRIdPTR " of %" PRIdPTR " joined", i,
- curr_num_threads);
+ EXECUTOR_TRACE("(%s) Thread %" PRIdPTR " of %" PRIdPTR " joined", name_,
+ i + 1, curr_num_threads);
}
- gpr_atm_no_barrier_store(&num_threads_, 0);
+ gpr_atm_rel_store(&num_threads_, 0);
for (size_t i = 0; i < max_threads_; i++) {
gpr_mu_destroy(&thd_state_[i].mu);
gpr_cv_destroy(&thd_state_[i].cv);
- RunClosures(thd_state_[i].elems);
+ RunClosures(thd_state_[i].name, thd_state_[i].elems);
}
gpr_free(thd_state_);
gpr_tls_destroy(&g_this_thread_state);
}
+
+ EXECUTOR_TRACE("(%s) SetThreading(%d) done", name_, threading);
}
void GrpcExecutor::Shutdown() { SetThreading(false); }
@@ -147,8 +163,8 @@ void GrpcExecutor::ThreadMain(void* arg) {
size_t subtract_depth = 0;
for (;;) {
- EXECUTOR_TRACE("[%" PRIdPTR "]: step (sub_depth=%" PRIdPTR ")", ts->id,
- subtract_depth);
+ EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: step (sub_depth=%" PRIdPTR ")",
+ ts->name, ts->id, subtract_depth);
gpr_mu_lock(&ts->mu);
ts->depth -= subtract_depth;
@@ -159,7 +175,7 @@ void GrpcExecutor::ThreadMain(void* arg) {
}
if (ts->shutdown) {
- EXECUTOR_TRACE("[%" PRIdPTR "]: shutdown", ts->id);
+ EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: shutdown", ts->name, ts->id);
gpr_mu_unlock(&ts->mu);
break;
}
@@ -169,10 +185,10 @@ void GrpcExecutor::ThreadMain(void* arg) {
ts->elems = GRPC_CLOSURE_LIST_INIT;
gpr_mu_unlock(&ts->mu);
- EXECUTOR_TRACE("[%" PRIdPTR "]: execute", ts->id);
+ EXECUTOR_TRACE("(%s) [%" PRIdPTR "]: execute", ts->name, ts->id);
grpc_core::ExecCtx::Get()->InvalidateNow();
- subtract_depth = RunClosures(closures);
+ subtract_depth = RunClosures(ts->name, closures);
}
}
@@ -188,16 +204,16 @@ void GrpcExecutor::Enqueue(grpc_closure* closure, grpc_error* error,
do {
retry_push = false;
size_t cur_thread_count =
- static_cast<size_t>(gpr_atm_no_barrier_load(&num_threads_));
+ static_cast<size_t>(gpr_atm_acq_load(&num_threads_));
// If the number of threads is zero(i.e either the executor is not threaded
// or already shutdown), then queue the closure on the exec context itself
if (cur_thread_count == 0) {
#ifndef NDEBUG
- EXECUTOR_TRACE("schedule %p (created %s:%d) inline", closure,
+ EXECUTOR_TRACE("(%s) schedule %p (created %s:%d) inline", name_, closure,
closure->file_created, closure->line_created);
#else
- EXECUTOR_TRACE("schedule %p inline", closure);
+ EXECUTOR_TRACE("(%s) schedule %p inline", name_, closure);
#endif
grpc_closure_list_append(grpc_core::ExecCtx::Get()->closure_list(),
closure, error);
@@ -213,18 +229,18 @@ void GrpcExecutor::Enqueue(grpc_closure* closure, grpc_error* error,
}
ThreadState* orig_ts = ts;
-
bool try_new_thread = false;
+
for (;;) {
#ifndef NDEBUG
EXECUTOR_TRACE(
- "try to schedule %p (%s) (created %s:%d) to thread "
+ "(%s) try to schedule %p (%s) (created %s:%d) to thread "
"%" PRIdPTR,
- closure, is_short ? "short" : "long", closure->file_created,
+ name_, closure, is_short ? "short" : "long", closure->file_created,
closure->line_created, ts->id);
#else
- EXECUTOR_TRACE("try to schedule %p (%s) to thread %" PRIdPTR, closure,
- is_short ? "short" : "long", ts->id);
+ EXECUTOR_TRACE("(%s) try to schedule %p (%s) to thread %" PRIdPTR, name_,
+ closure, is_short ? "short" : "long", ts->id);
#endif
gpr_mu_lock(&ts->mu);
@@ -236,18 +252,22 @@ void GrpcExecutor::Enqueue(grpc_closure* closure, grpc_error* error,
size_t idx = ts->id;
ts = &thd_state_[(idx + 1) % cur_thread_count];
if (ts == orig_ts) {
- // We cycled through all the threads. Retry enqueue again (by creating
- // a new thread)
+ // We cycled through all the threads. Retry enqueue again by creating
+ // a new thread
+ //
+ // TODO (sreek): There is a potential issue here. We are
+ // unconditionally setting try_new_thread to true here. What if the
+ // executor is shutdown OR if cur_thread_count is already equal to
+ // max_threads ?
+ // (Fortunately, this is not an issue yet (as of july 2018) because
+ // there is only one instance of long job in gRPC and hence we will
+ // not hit this code path)
retry_push = true;
- // TODO (sreek): What if the executor is shutdown OR if
- // cur_thread_count is already equal to max_threads ? (currently - as
- // of July 2018, we do not run in to this issue because there is only
- // one instance of long job in gRPC. This has to be fixed soon)
try_new_thread = true;
break;
}
- continue;
+ continue; // Try the next thread-state
}
// == Found the thread state (i.e thread) to enqueue this closure! ==
@@ -277,13 +297,11 @@ void GrpcExecutor::Enqueue(grpc_closure* closure, grpc_error* error,
}
if (try_new_thread && gpr_spinlock_trylock(&adding_thread_lock_)) {
- cur_thread_count =
- static_cast<size_t>(gpr_atm_no_barrier_load(&num_threads_));
+ cur_thread_count = static_cast<size_t>(gpr_atm_acq_load(&num_threads_));
if (cur_thread_count < max_threads_) {
- // Increment num_threads (Safe to do a no_barrier_store instead of a
- // cas because we always increment num_threads under the
- // 'adding_thread_lock')
- gpr_atm_no_barrier_store(&num_threads_, cur_thread_count + 1);
+ // Increment num_threads (safe to do a store instead of a cas because we
+ // always increment num_threads under the 'adding_thread_lock')
+ gpr_atm_rel_store(&num_threads_, cur_thread_count + 1);
thd_state_[cur_thread_count].thd = grpc_core::Thread(
name_, &GrpcExecutor::ThreadMain, &thd_state_[cur_thread_count]);
@@ -298,60 +316,118 @@ void GrpcExecutor::Enqueue(grpc_closure* closure, grpc_error* error,
} while (retry_push);
}
-static GrpcExecutor* global_executor;
+static GrpcExecutor* executors[GRPC_NUM_EXECUTORS];
-void enqueue_long(grpc_closure* closure, grpc_error* error) {
- global_executor->Enqueue(closure, error, false /* is_short */);
+void default_enqueue_short(grpc_closure* closure, grpc_error* error) {
+ executors[GRPC_DEFAULT_EXECUTOR]->Enqueue(closure, error,
+ true /* is_short */);
}
-void enqueue_short(grpc_closure* closure, grpc_error* error) {
- global_executor->Enqueue(closure, error, true /* is_short */);
+void default_enqueue_long(grpc_closure* closure, grpc_error* error) {
+ executors[GRPC_DEFAULT_EXECUTOR]->Enqueue(closure, error,
+ false /* is_short */);
}
-// Short-Job executor scheduler
-static const grpc_closure_scheduler_vtable global_executor_vtable_short = {
- enqueue_short, enqueue_short, "executor-short"};
-static grpc_closure_scheduler global_scheduler_short = {
- &global_executor_vtable_short};
+void resolver_enqueue_short(grpc_closure* closure, grpc_error* error) {
+ executors[GRPC_RESOLVER_EXECUTOR]->Enqueue(closure, error,
+ true /* is_short */);
+}
-// Long-job executor scheduler
-static const grpc_closure_scheduler_vtable global_executor_vtable_long = {
- enqueue_long, enqueue_long, "executor-long"};
-static grpc_closure_scheduler global_scheduler_long = {
- &global_executor_vtable_long};
+void resolver_enqueue_long(grpc_closure* closure, grpc_error* error) {
+ executors[GRPC_RESOLVER_EXECUTOR]->Enqueue(closure, error,
+ false /* is_short */);
+}
+
+static const grpc_closure_scheduler_vtable
+ vtables_[GRPC_NUM_EXECUTORS][GRPC_NUM_EXECUTOR_JOB_TYPES] = {
+ {{&default_enqueue_short, &default_enqueue_short, "def-ex-short"},
+ {&default_enqueue_long, &default_enqueue_long, "def-ex-long"}},
+ {{&resolver_enqueue_short, &resolver_enqueue_short, "res-ex-short"},
+ {&resolver_enqueue_long, &resolver_enqueue_long, "res-ex-long"}}};
+
+static grpc_closure_scheduler
+ schedulers_[GRPC_NUM_EXECUTORS][GRPC_NUM_EXECUTOR_JOB_TYPES] = {
+ {{&vtables_[GRPC_DEFAULT_EXECUTOR][GRPC_EXECUTOR_SHORT]},
+ {&vtables_[GRPC_DEFAULT_EXECUTOR][GRPC_EXECUTOR_LONG]}},
+ {{&vtables_[GRPC_RESOLVER_EXECUTOR][GRPC_EXECUTOR_SHORT]},
+ {&vtables_[GRPC_RESOLVER_EXECUTOR][GRPC_EXECUTOR_LONG]}}};
// grpc_executor_init() and grpc_executor_shutdown() functions are called in the
// the grpc_init() and grpc_shutdown() code paths which are protected by a
// global mutex. So it is okay to assume that these functions are thread-safe
void grpc_executor_init() {
- if (global_executor != nullptr) {
- // grpc_executor_init() already called once (and grpc_executor_shutdown()
- // wasn't called)
+ EXECUTOR_TRACE0("grpc_executor_init() enter");
+
+ // Return if grpc_executor_init() is already called earlier
+ if (executors[GRPC_DEFAULT_EXECUTOR] != nullptr) {
+ GPR_ASSERT(executors[GRPC_RESOLVER_EXECUTOR] != nullptr);
return;
}
- global_executor = grpc_core::New<GrpcExecutor>("global-executor");
- global_executor->Init();
+ executors[GRPC_DEFAULT_EXECUTOR] =
+ grpc_core::New<GrpcExecutor>("default-executor");
+ executors[GRPC_RESOLVER_EXECUTOR] =
+ grpc_core::New<GrpcExecutor>("resolver-executor");
+
+ executors[GRPC_DEFAULT_EXECUTOR]->Init();
+ executors[GRPC_RESOLVER_EXECUTOR]->Init();
+
+ EXECUTOR_TRACE0("grpc_executor_init() done");
+}
+
+grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorType executor_type,
+ GrpcExecutorJobType job_type) {
+ return &schedulers_[executor_type][job_type];
+}
+
+grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type) {
+ return grpc_executor_scheduler(GRPC_DEFAULT_EXECUTOR, job_type);
}
void grpc_executor_shutdown() {
- // Shutdown already called
- if (global_executor == nullptr) {
+ EXECUTOR_TRACE0("grpc_executor_shutdown() enter");
+
+ // Return if grpc_executor_shutdown() is already called earlier
+ if (executors[GRPC_DEFAULT_EXECUTOR] == nullptr) {
+ GPR_ASSERT(executors[GRPC_RESOLVER_EXECUTOR] == nullptr);
return;
}
- global_executor->Shutdown();
- grpc_core::Delete<GrpcExecutor>(global_executor);
- global_executor = nullptr;
+ executors[GRPC_DEFAULT_EXECUTOR]->Shutdown();
+ executors[GRPC_RESOLVER_EXECUTOR]->Shutdown();
+
+ // Delete the executor objects.
+ //
+ // NOTE: It is important to call Shutdown() on all executors first before
+ // calling Delete() because it is possible for one executor (that is not
+ // shutdown yet) to call Enqueue() on a different executor which is already
+ // shutdown. This is legal and in such cases, the Enqueue() operation
+ // effectively "fails" and enqueues that closure on the calling thread's
+ // exec_ctx.
+ //
+ // By ensuring that all executors are shutdown first, we are also ensuring
+ // that no thread is active across all executors.
+
+ grpc_core::Delete<GrpcExecutor>(executors[GRPC_DEFAULT_EXECUTOR]);
+ grpc_core::Delete<GrpcExecutor>(executors[GRPC_RESOLVER_EXECUTOR]);
+ executors[GRPC_DEFAULT_EXECUTOR] = nullptr;
+ executors[GRPC_RESOLVER_EXECUTOR] = nullptr;
+
+ EXECUTOR_TRACE0("grpc_executor_shutdown() done");
}
-bool grpc_executor_is_threaded() { return global_executor->IsThreaded(); }
+bool grpc_executor_is_threaded(GrpcExecutorType executor_type) {
+ GPR_ASSERT(executor_type < GRPC_NUM_EXECUTORS);
+ return executors[executor_type]->IsThreaded();
+}
-void grpc_executor_set_threading(bool enable) {
- global_executor->SetThreading(enable);
+bool grpc_executor_is_threaded() {
+ return grpc_executor_is_threaded(GRPC_DEFAULT_EXECUTOR);
}
-grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type) {
- return job_type == GRPC_EXECUTOR_SHORT ? &global_scheduler_short
- : &global_scheduler_long;
+void grpc_executor_set_threading(bool enable) {
+ EXECUTOR_TRACE("grpc_executor_set_threading(%d) called", enable);
+ for (int i = 0; i < GRPC_NUM_EXECUTORS; i++) {
+ executors[i]->SetThreading(enable);
+ }
}
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
index 395fc52863..8829138c5f 100644
--- a/src/core/lib/iomgr/executor.h
+++ b/src/core/lib/iomgr/executor.h
@@ -27,7 +27,8 @@
typedef struct {
gpr_mu mu;
- size_t id; // For debugging purposes
+ size_t id; // For debugging purposes
+ const char* name; // Thread state name
gpr_cv cv;
grpc_closure_list elems;
size_t depth; // Number of closures in the closure list
@@ -36,7 +37,11 @@ typedef struct {
grpc_core::Thread thd;
} ThreadState;
-typedef enum { GRPC_EXECUTOR_SHORT, GRPC_EXECUTOR_LONG } GrpcExecutorJobType;
+typedef enum {
+ GRPC_EXECUTOR_SHORT = 0,
+ GRPC_EXECUTOR_LONG,
+ GRPC_NUM_EXECUTOR_JOB_TYPES // Add new values above this
+} GrpcExecutorJobType;
class GrpcExecutor {
public:
@@ -58,7 +63,7 @@ class GrpcExecutor {
void Enqueue(grpc_closure* closure, grpc_error* error, bool is_short);
private:
- static size_t RunClosures(grpc_closure_list list);
+ static size_t RunClosures(const char* executor_name, grpc_closure_list list);
static void ThreadMain(void* arg);
const char* name_;
@@ -70,14 +75,42 @@ class GrpcExecutor {
// == Global executor functions ==
+typedef enum {
+ GRPC_DEFAULT_EXECUTOR = 0,
+ GRPC_RESOLVER_EXECUTOR,
+
+ GRPC_NUM_EXECUTORS // Add new values above this
+} GrpcExecutorType;
+
+// TODO(sreek): Currently we have two executors (available globally): The
+// default executor and the resolver executor.
+//
+// Some of the functions below operate on the DEFAULT executor only while some
+// operate of ALL the executors. This is a bit confusing and should be cleaned
+// up in future (where we make all the following functions take executor_type
+// and/or job_type)
+
+// Initialize ALL the executors
void grpc_executor_init();
+// Shutdown ALL the executors
+void grpc_executor_shutdown();
+
+// Set the threading mode for ALL the executors
+void grpc_executor_set_threading(bool enable);
+
+// Get the DEFAULT executor scheduler for the given job_type
grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type);
-void grpc_executor_shutdown();
+// Get the executor scheduler for a given executor_type and a job_type
+grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorType executor_type,
+ GrpcExecutorJobType job_type);
-bool grpc_executor_is_threaded();
+// Return if a given executor is running in threaded mode (i.e if
+// grpc_executor_set_threading(true) was called previously on that executor)
+bool grpc_executor_is_threaded(GrpcExecutorType executor_type);
-void grpc_executor_set_threading(bool enable);
+// Return if the DEFAULT executor is threaded
+bool grpc_executor_is_threaded();
#endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */
diff --git a/src/core/lib/iomgr/resolve_address_posix.cc b/src/core/lib/iomgr/resolve_address_posix.cc
index 7a825643e1..c285d7eca6 100644
--- a/src/core/lib/iomgr/resolve_address_posix.cc
+++ b/src/core/lib/iomgr/resolve_address_posix.cc
@@ -166,8 +166,9 @@ static void posix_resolve_address(const char* name, const char* default_port,
grpc_closure* on_done,
grpc_resolved_addresses** addrs) {
request* r = static_cast<request*>(gpr_malloc(sizeof(request)));
- GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
- grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
+ GRPC_CLOSURE_INIT(
+ &r->request_closure, do_request_thread, r,
+ grpc_executor_scheduler(GRPC_RESOLVER_EXECUTOR, GRPC_EXECUTOR_SHORT));
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
r->on_done = on_done;
diff --git a/src/core/lib/iomgr/resolve_address_windows.cc b/src/core/lib/iomgr/resolve_address_windows.cc
index 71c92615ad..3e977dca2d 100644
--- a/src/core/lib/iomgr/resolve_address_windows.cc
+++ b/src/core/lib/iomgr/resolve_address_windows.cc
@@ -151,8 +151,9 @@ static void windows_resolve_address(const char* name, const char* default_port,
grpc_closure* on_done,
grpc_resolved_addresses** addresses) {
request* r = (request*)gpr_malloc(sizeof(request));
- GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
- grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
+ GRPC_CLOSURE_INIT(
+ &r->request_closure, do_request_thread, r,
+ grpc_executor_scheduler(GRPC_RESOLVER_EXECUTOR, GRPC_EXECUTOR_SHORT));
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
r->on_done = on_done;
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
index 7c4d7a71cd..8454fd7558 100644
--- a/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
@@ -41,8 +41,9 @@ namespace internal {
bool check_bios_data(const char* bios_data_file) {
char* bios_data = read_bios_file(bios_data_file);
- bool result = (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE)) ||
- (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GCE));
+ bool result =
+ bios_data && ((!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE)) ||
+ (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GCE)));
gpr_free(bios_data);
return result;
}
diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc
index cc72bb6164..59cf3a0af1 100644
--- a/src/core/lib/security/security_connector/security_connector.cc
+++ b/src/core/lib/security/security_connector/security_connector.cc
@@ -57,6 +57,10 @@ static const char* installed_roots_path =
INSTALL_PREFIX "/share/grpc/roots.pem";
#endif
+#ifndef TSI_OPENSSL_ALPN_SUPPORT
+#define TSI_OPENSSL_ALPN_SUPPORT 1
+#endif
+
/* -- Overridden default roots. -- */
static grpc_ssl_roots_override_callback ssl_roots_override_cb = nullptr;
@@ -850,7 +854,8 @@ grpc_auth_context* grpc_ssl_peer_to_auth_context(const tsi_peer* peer) {
static grpc_error* ssl_check_peer(grpc_security_connector* sc,
const char* peer_name, const tsi_peer* peer,
grpc_auth_context** auth_context) {
- /* Check the ALPN. */
+#if TSI_OPENSSL_ALPN_SUPPORT
+ /* Check the ALPN if ALPN is supported. */
const tsi_peer_property* p =
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
if (p == nullptr) {
@@ -861,7 +866,7 @@ static grpc_error* ssl_check_peer(grpc_security_connector* sc,
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Cannot check peer: invalid ALPN value.");
}
-
+#endif /* TSI_OPENSSL_ALPN_SUPPORT */
/* Check the peer name if specified. */
if (peer_name != nullptr && !grpc_ssl_host_matches_name(peer, peer_name)) {
char* msg;
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 88e015ce22..847bb87f7e 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -561,7 +561,7 @@ static void destroy_call(void* call, grpc_error* error) {
}
get_final_status(c, set_status_value_directly, &c->final_info.final_status,
- nullptr, c->final_info.error_string);
+ nullptr, &(c->final_info.error_string));
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
@@ -573,6 +573,7 @@ static void destroy_call(void* call, grpc_error* error) {
grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c), &c->final_info,
GRPC_CLOSURE_INIT(&c->release_call, release_call, c,
grpc_schedule_on_exec_ctx));
+ gpr_free(static_cast<void*>(const_cast<char*>(c->final_info.error_string)));
}
void grpc_call_ref(grpc_call* c) { gpr_ref(&c->ext_ref); }
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index ac8cec2980..e92fe2c5a1 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -25,4 +25,4 @@
const char* grpc_version_string(void) { return "6.0.0-dev"; }
-const char* grpc_g_stands_for(void) { return "gladiolus"; }
+const char* grpc_g_stands_for(void) { return "glider"; }
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index a7b093dfd2..b8fca9a6ee 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
#include <grpcpp/grpcpp.h>
namespace grpc {
-grpc::string Version() { return "1.14.0-dev"; }
+grpc::string Version() { return "1.15.0-dev"; }
} // namespace grpc
diff --git a/src/cpp/server/channelz/channelz_service.cc b/src/cpp/server/channelz/channelz_service.cc
new file mode 100644
index 0000000000..77c175e5b8
--- /dev/null
+++ b/src/cpp/server/channelz/channelz_service.cc
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/cpp/server/channelz/channelz_service.h"
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/json_util.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+namespace grpc {
+
+Status ChannelzService::GetTopChannels(
+ ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request,
+ channelz::v1::GetTopChannelsResponse* response) {
+ char* json_str = grpc_channelz_get_top_channels(request->start_channel_id());
+ google::protobuf::util::Status s =
+ google::protobuf::util::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (s != google::protobuf::util::Status::OK) {
+ return Status(INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+Status ChannelzService::GetChannel(
+ ServerContext* unused, const channelz::v1::GetChannelRequest* request,
+ channelz::v1::GetChannelResponse* response) {
+ char* json_str = grpc_channelz_get_channel(request->channel_id());
+ google::protobuf::util::Status s =
+ google::protobuf::util::JsonStringToMessage(json_str, response);
+ gpr_free(json_str);
+ if (s != google::protobuf::util::Status::OK) {
+ return Status(INTERNAL, s.ToString());
+ }
+ return Status::OK;
+}
+
+} // namespace grpc
diff --git a/src/cpp/server/channelz/channelz_service.h b/src/cpp/server/channelz/channelz_service.h
new file mode 100644
index 0000000000..f619ea49e0
--- /dev/null
+++ b/src/cpp/server/channelz/channelz_service.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_SERVER_CHANNELZ_SERVICE_H
+#define GRPC_INTERNAL_CPP_SERVER_CHANNELZ_SERVICE_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpcpp/grpcpp.h>
+#include "src/proto/grpc/channelz/channelz.grpc.pb.h"
+
+namespace grpc {
+
+class ChannelzService final : public channelz::v1::Channelz::Service {
+ private:
+ // implementation of GetTopChannels rpc
+ Status GetTopChannels(
+ ServerContext* unused, const channelz::v1::GetTopChannelsRequest* request,
+ channelz::v1::GetTopChannelsResponse* response) override;
+ // implementation of GetChannel rpc
+ Status GetChannel(ServerContext* unused,
+ const channelz::v1::GetChannelRequest* request,
+ channelz::v1::GetChannelResponse* response) override;
+};
+
+} // namespace grpc
+
+#endif // GRPC_INTERNAL_CPP_SERVER_CHANNELZ_SERVICE_H
diff --git a/src/cpp/server/channelz/channelz_service_plugin.cc b/src/cpp/server/channelz/channelz_service_plugin.cc
new file mode 100644
index 0000000000..b93e5b551e
--- /dev/null
+++ b/src/cpp/server/channelz/channelz_service_plugin.cc
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpcpp/ext/channelz_service_plugin.h>
+#include <grpcpp/impl/server_builder_plugin.h>
+#include <grpcpp/impl/server_initializer.h>
+#include <grpcpp/server.h>
+
+#include "src/cpp/server/channelz/channelz_service.h"
+
+namespace grpc {
+namespace channelz {
+namespace experimental {
+
+class ChannelzServicePlugin : public ::grpc::ServerBuilderPlugin {
+ public:
+ ChannelzServicePlugin() : channelz_service_(new grpc::ChannelzService()) {}
+
+ grpc::string name() override { return "channelz_service"; }
+
+ void InitServer(grpc::ServerInitializer* si) override {
+ si->RegisterService(channelz_service_);
+ }
+
+ void Finish(grpc::ServerInitializer* si) override {}
+
+ void ChangeArguments(const grpc::string& name, void* value) override {}
+
+ bool has_sync_methods() const override {
+ if (channelz_service_) {
+ return channelz_service_->has_synchronous_methods();
+ }
+ return false;
+ }
+
+ bool has_async_methods() const override {
+ if (channelz_service_) {
+ return channelz_service_->has_async_methods();
+ }
+ return false;
+ }
+
+ private:
+ std::shared_ptr<grpc::ChannelzService> channelz_service_;
+};
+
+static std::unique_ptr< ::grpc::ServerBuilderPlugin>
+CreateChannelzServicePlugin() {
+ return std::unique_ptr< ::grpc::ServerBuilderPlugin>(
+ new ChannelzServicePlugin());
+}
+
+void InitChannelzService() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ ::grpc::ServerBuilder::InternalAddPluginFactory(&CreateChannelzServicePlugin);
+}
+
+} // namespace experimental
+} // namespace channelz
+} // namespace grpc
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 6d44be7ddd..c4db3a3a87 100755
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -46,10 +46,34 @@
<PackagePath>runtimes/win/native/grpc_csharp_ext.x86.dll</PackagePath>
<Pack>true</Pack>
</Content>
- <Content Include="Grpc.Core.targets">
+ <Content Include="..\nativelibs\csharp_ext_linux_android_armeabi-v7a\libgrpc_csharp_ext.so">
+ <PackagePath>runtimes/monoandroid/armeabi-v7a/libgrpc_csharp_ext.so</PackagePath>
+ <Pack>true</Pack>
+ </Content>
+ <Content Include="..\nativelibs\csharp_ext_linux_android_arm64-v8a\libgrpc_csharp_ext.so">
+ <PackagePath>runtimes/monoandroid/arm64-v8a/libgrpc_csharp_ext.so</PackagePath>
+ <Pack>true</Pack>
+ </Content>
+ <Content Include="..\nativelibs\csharp_ext_macos_ios\libgrpc_csharp_ext.a">
+ <PackagePath>runtimes/ios/native/libgrpc_csharp_ext.a</PackagePath>
+ <Pack>true</Pack>
+ </Content>
+ <Content Include="..\nativelibs\csharp_ext_macos_ios\libgrpc.a">
+ <PackagePath>runtimes/ios/native/libgrpc.a</PackagePath>
+ <Pack>true</Pack>
+ </Content>
+ <Content Include="build\net45\Grpc.Core.targets">
<PackagePath>build/net45/</PackagePath>
<Pack>true</Pack>
</Content>
+ <Content Include="build\MonoAndroid\Grpc.Core.targets">
+ <PackagePath>build/MonoAndroid/</PackagePath>
+ <Pack>true</Pack>
+ </Content>
+ <Content Include="build\Xamarin.iOS\Grpc.Core.targets">
+ <PackagePath>build/Xamarin.iOS/</PackagePath>
+ <Pack>true</Pack>
+ </Content>
</ItemGroup>
<ItemGroup>
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index d5ec998bbd..f526b913af 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -106,7 +106,15 @@ namespace Grpc.Core.Internal
/// </summary>
private static NativeMethods LoadNativeMethods()
{
- return PlatformApis.IsUnity ? LoadNativeMethodsUnity() : new NativeMethods(LoadUnmanagedLibrary());
+ if (PlatformApis.IsUnity)
+ {
+ return LoadNativeMethodsUnity();
+ }
+ if (PlatformApis.IsXamarin)
+ {
+ return LoadNativeMethodsXamarin();
+ }
+ return new NativeMethods(LoadUnmanagedLibrary());
}
/// <summary>
@@ -128,6 +136,20 @@ namespace Grpc.Core.Internal
}
}
+ /// <summary>
+ /// Return native method delegates when running on the Xamarin platform.
+ /// WARNING: Xamarin support is experimental and work-in-progress. Don't expect it to work.
+ /// </summary>
+ private static NativeMethods LoadNativeMethodsXamarin()
+ {
+ if (PlatformApis.IsXamarinAndroid)
+ {
+ return new NativeMethods(new NativeMethods.DllImportsFromSharedLib());
+ }
+ // not tested yet
+ return new NativeMethods(new NativeMethods.DllImportsFromStaticLib());
+ }
+
private static string GetAssemblyPath()
{
var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
diff --git a/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
index bf6440123a..30264acb10 100644
--- a/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs
@@ -51,6 +51,7 @@ namespace Grpc.Core.Internal
}
}
+ [MonoPInvokeCallback(typeof(GprLogDelegate))]
private static void HandleWrite(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr)
{
try
@@ -86,4 +87,22 @@ namespace Grpc.Core.Internal
}
}
}
+
+ /// <summary>
+ /// Use this attribute to mark methods that will be called back from P/Invoke calls.
+ /// iOS (and probably other AOT platforms) needs to have delegates registered.
+ /// Instead of depending on Xamarin.iOS for this, we can just create our own,
+ /// the iOS runtime just checks for the type name.
+ /// See: https://docs.microsoft.com/en-gb/xamarin/ios/internals/limitations#reverse-callbacks
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method)]
+ internal sealed class MonoPInvokeCallbackAttribute : Attribute
+ {
+ public MonoPInvokeCallbackAttribute(Type type)
+ {
+ Type = type;
+ }
+
+ public Type Type { get; private set; }
+ }
}
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index b90fbccb2b..c501aa89fb 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -33,12 +33,18 @@ namespace Grpc.Core.Internal
internal static class PlatformApis
{
const string UnityEngineApplicationClassName = "UnityEngine.Application, UnityEngine";
+ const string XamarinAndroidObjectClassName = "Java.Lang.Object, Mono.Android";
+ const string XamarinIOSObjectClassName = "Foundation.NSObject, Xamarin.iOS";
+
static readonly bool isLinux;
static readonly bool isMacOSX;
static readonly bool isWindows;
static readonly bool isMono;
static readonly bool isNetCore;
static readonly bool isUnity;
+ static readonly bool isXamarin;
+ static readonly bool isXamarinIOS;
+ static readonly bool isXamarinAndroid;
static PlatformApis()
{
@@ -58,6 +64,9 @@ namespace Grpc.Core.Internal
#endif
isMono = Type.GetType("Mono.Runtime") != null;
isUnity = Type.GetType(UnityEngineApplicationClassName) != null;
+ isXamarinIOS = Type.GetType(XamarinIOSObjectClassName) != null;
+ isXamarinAndroid = Type.GetType(XamarinAndroidObjectClassName) != null;
+ isXamarin = isXamarinIOS || isXamarinAndroid;
}
public static bool IsLinux
@@ -89,6 +98,31 @@ namespace Grpc.Core.Internal
}
/// <summary>
+ /// true if running on a Xamarin platform (either Xamarin.Android or Xamarin.iOS),
+ /// false otherwise.
+ /// </summary>
+ public static bool IsXamarin
+ {
+ get { return isXamarin; }
+ }
+
+ /// <summary>
+ /// true if running on Xamarin.iOS, false otherwise.
+ /// </summary>
+ public static bool IsXamarinIOS
+ {
+ get { return isXamarinIOS; }
+ }
+
+ /// <summary>
+ /// true if running on Xamarin.Android, false otherwise.
+ /// </summary>
+ public static bool IsXamarinAndroid
+ {
+ get { return isXamarinAndroid; }
+ }
+
+ /// <summary>
/// true if running on .NET Core (CoreCLR), false otherwise.
/// </summary>
public static bool IsNetCore
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 2b45e7ae20..1a746acdd4 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
- <GrpcCsharpVersion>1.14.0-dev</GrpcCsharpVersion>
+ <GrpcCsharpVersion>1.15.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.5.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index c4531e5275..295e0f2577 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.14.0.0";
+ public const string CurrentAssemblyFileVersion = "1.15.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.14.0-dev";
+ public const string CurrentVersion = "1.15.0-dev";
}
}
diff --git a/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets b/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets
new file mode 100644
index 0000000000..f764f4cae1
--- /dev/null
+++ b/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <_GrpcCoreNugetNativePath Condition="'$(_GrpcCoreNugetNativePath)' == ''">$(MSBuildThisFileDirectory)..\..\</_GrpcCoreNugetNativePath>
+ </PropertyGroup>
+
+ <ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
+ <AndroidNativeLibrary Include="$(_GrpcCoreNugetNativePath)runtimes\monoandroid\arm64-v8a\libgrpc_csharp_ext.so">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ <Abi>arm64-v8a</Abi>
+ </AndroidNativeLibrary>
+ </ItemGroup>
+
+ <ItemGroup Condition="'$(TargetFrameworkIdentifier)' == 'MonoAndroid'">
+ <AndroidNativeLibrary Include="$(_GrpcCoreNugetNativePath)runtimes\monoandroid\armeabi-v7a\libgrpc_csharp_ext.so">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ <Abi>armeabi-v7a</Abi>
+ </AndroidNativeLibrary>
+ </ItemGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Core/build/Xamarin.iOS/Grpc.Core.targets b/src/csharp/Grpc.Core/build/Xamarin.iOS/Grpc.Core.targets
new file mode 100644
index 0000000000..658158f6ea
--- /dev/null
+++ b/src/csharp/Grpc.Core/build/Xamarin.iOS/Grpc.Core.targets
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <ItemGroup>
+ <NativeReference Include="$(MSBuildThisFileDirectory)..\..\runtimes\ios\native\libgrpc_csharp_ext.a">
+ <Kind>Static</Kind>
+ <ForceLoad>True</ForceLoad>
+ </NativeReference>
+ <NativeReference Include="$(MSBuildThisFileDirectory)..\..\runtimes\ios\native\libgrpc.a">
+ <Kind>Static</Kind>
+ <ForceLoad>True</ForceLoad>
+ </NativeReference>
+ </ItemGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.targets b/src/csharp/Grpc.Core/build/net45/Grpc.Core.targets
index cce53db82b..cce53db82b 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.targets
+++ b/src/csharp/Grpc.Core/build/net45/Grpc.Core.targets
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 394b859e0b..67af258354 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.14.0-dev
+set VERSION=1.15.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 273d745f17..88b4d63538 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -45,8 +45,8 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
-nuget pack Grpc.nuspec -Version "1.14.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.14.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.14.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.15.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Core.NativeDebug.nuspec -Version "1.15.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.15.0-dev" -OutputDirectory ../../artifacts
(cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/csharp/doc/docfx.json b/src/csharp/doc/docfx.json
index 7219d0e7a6..0ce5f7262a 100644
--- a/src/csharp/doc/docfx.json
+++ b/src/csharp/doc/docfx.json
@@ -24,7 +24,7 @@
"dest": "api"
},
{
- "files": [ "toc.yml"],
+ "files": [ "toc.yml"]
}
],
"globalMetadata": {
diff --git a/src/csharp/experimental/build_native_ext_for_android.sh b/src/csharp/experimental/build_native_ext_for_android.sh
index 8197df7c53..6518e03c53 100755
--- a/src/csharp/experimental/build_native_ext_for_android.sh
+++ b/src/csharp/experimental/build_native_ext_for_android.sh
@@ -23,17 +23,30 @@ mkdir -p build
cd build
# set to the location where Android SDK is installed
-# e.g. ANDROID_NDK_PATH="$HOME/android-ndk-r16b"
+# e.g. ANDROID_SDK_PATH="$HOME/Android/Sdk"
-cmake ../.. \
- -DCMAKE_SYSTEM_NAME=Android \
- -DCMAKE_SYSTEM_VERSION=15 \
- -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a \
+# set to location where Android NDK is installed, usually a subfolder of Android SDK
+# to install the Android NKD, use the "sdkmanager" tool
+# e.g. ANDROID_NDK_PATH=${ANDROID_SDK_PATH}/ndk-bundle
+
+# set to location of the cmake executable from the Android SDK
+# to install cmake, use the "sdkmanager" tool
+# e.g. ANDROID_SDK_CMAKE=${ANDROID_SDK_PATH}/cmake/3.6.4111459/bin/cmake
+
+# ANDROID_ABI in ('arm64-v8a', 'armeabi-v7a')
+# e.g. ANDROID_ABI=armeabi-v7a
+
+# android-19 corresponds to Kitkat 4.4
+${ANDROID_SDK_CMAKE} ../.. \
+ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake" \
-DCMAKE_ANDROID_NDK="${ANDROID_NDK_PATH}" \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DRUN_HAVE_POSIX_REGEX=0 \
-DRUN_HAVE_STD_REGEX=0 \
-DRUN_HAVE_STEADY_CLOCK=0 \
- -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_PLATFORM=android-19 \
+ -DANDROID_ABI="${ANDROID_ABI}" \
+ -DANDROID_NDK="${ANDROID_NDK_PATH}"
make -j4 grpc_csharp_ext
diff --git a/src/csharp/experimental/build_native_ext_for_ios.sh b/src/csharp/experimental/build_native_ext_for_ios.sh
new file mode 100755
index 0000000000..69c9cdf021
--- /dev/null
+++ b/src/csharp/experimental/build_native_ext_for_ios.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# Copyright 2018 The gRPC Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script to crosscompile grpc_csharp_ext native extension for Android.
+
+set -ex
+
+cd "$(dirname "$0")/../../.."
+
+# Usage: build <iphoneos|iphonesimulator> <arm64|x86_64|...>
+function build {
+ SDK="$1"
+ ARCH="$2"
+
+ PATH_AR="$(xcrun --sdk $SDK --find ar)"
+ PATH_CC="$(xcrun --sdk $SDK --find clang)"
+ PATH_CXX="$(xcrun --sdk $SDK --find clang++)"
+
+ # TODO(jtattermusch): add -mios-version-min=6.0 and -Wl,ios_version_min=6.0
+ CPPFLAGS="-O2 -Wframe-larger-than=16384 -arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path) -DPB_NO_PACKED_STRUCTS=1"
+ LDFLAGS="-arch $ARCH -isysroot $(xcrun --sdk $SDK --show-sdk-path)"
+
+ # TODO(jtattermusch): revisit the build arguments
+ make -j4 static_csharp \
+ VALID_CONFIG_ios_$ARCH="1" \
+ CC_ios_$ARCH="$PATH_CC" \
+ CXX_ios_$ARCH="$PATH_CXX" \
+ LD_ios_$ARCH="$PATH_CC" \
+ LDXX_ios_$ARCH="$PATH_CXX" \
+ CPPFLAGS_ios_$ARCH="$CPPFLAGS" \
+ LDFLAGS_ios_$ARCH="$LDFLAGS" \
+ DEFINES_ios_$ARCH="NDEBUG" \
+ CONFIG="ios_$ARCH"
+}
+
+# Usage: fatten <grpc_csharp_ext|...>
+function fatten {
+ LIB_NAME="$1"
+
+ mkdir -p libs/ios
+ lipo -create -output libs/ios/lib$LIB_NAME.a \
+ libs/ios_arm64/lib$LIB_NAME.a \
+ libs/ios_x86_64/lib$LIB_NAME.a
+}
+
+build iphoneos arm64
+build iphonesimulator x86_64
+
+fatten grpc
+fatten grpc_csharp_ext
diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
index 28dfffd863..6ad9166b32 100644
--- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
+++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
@@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
- v = '1.14.0-dev'
+ v = '1.15.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index 60571b1f43..52fe0dd050 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -22,4 +22,4 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.14.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev"
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index fafcac6507..d532eed245 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -22,5 +22,5 @@
// instead. This file can be regenerated from the template by running
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.14.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.15.0-dev"
#define GRPC_C_VERSION_STRING @"6.0.0-dev"
diff --git a/src/php/composer.json b/src/php/composer.json
index 94918417d9..b6716b8b4c 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Developement use only",
"license": "Apache-2.0",
- "version": "1.14.0",
+ "version": "1.15.0",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index c985863cb5..99dd9d68f0 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define PHP_GRPC_VERSION "1.14.0dev"
+#define PHP_GRPC_VERSION "1.15.0dev"
#endif /* VERSION_H */
diff --git a/src/proto/grpc/testing/echo_messages.proto b/src/proto/grpc/testing/echo_messages.proto
index 5396a2fd39..2f935304ab 100644
--- a/src/proto/grpc/testing/echo_messages.proto
+++ b/src/proto/grpc/testing/echo_messages.proto
@@ -46,6 +46,7 @@ message RequestParams {
string binary_error_details = 13;
ErrorStatus expected_error = 14;
int32 server_sleep_us = 15; // Amount to sleep when invoking server
+ int32 backend_channel_idx = 16; // which backend to send request to
}
message EchoRequest {
diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index b336e6aae5..c33911ebc1 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
-__version__ = """1.14.0.dev0"""
+__version__ = """1.15.0.dev0"""
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 2eeaabc8b8..9337800a33 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION = '1.14.0.dev0'
+VERSION = '1.15.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index f36de8d0fa..3b84f7a4c5 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
-VERSION = '1.14.0.dev0'
+VERSION = '1.15.0.dev0'
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 2249b07d9d..7b0e48ea23 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
-VERSION = '1.14.0.dev0'
+VERSION = '1.15.0.dev0'
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index a5b275aff6..df9953fa25 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
-VERSION = '1.14.0.dev0'
+VERSION = '1.15.0.dev0'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 816dfb55bc..b2cf129e4f 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
-VERSION = '1.14.0.dev0'
+VERSION = '1.15.0.dev0'
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 902d59bd71..5c21a5b168 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '1.14.0.dev'
+ VERSION = '1.15.0.dev'
end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index dad09bb965..1b5e2c362b 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
module GRPC
module Tools
- VERSION = '1.14.0.dev'
+ VERSION = '1.15.0.dev'
end
end