|
|
@ -338,55 +338,46 @@ void resolver_enqueue_long(grpc_closure* closure, grpc_error* error) { |
|
|
|
false /* is_short */); |
|
|
|
false /* is_short */); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const grpc_closure_scheduler_vtable vtables_[] = { |
|
|
|
static const grpc_closure_scheduler_vtable |
|
|
|
{&default_enqueue_short, &default_enqueue_short, "def-ex-short"}, |
|
|
|
vtables_[GRPC_NUM_EXECUTORS][GRPC_NUM_EXECUTOR_JOB_TYPES] = { |
|
|
|
{&default_enqueue_long, &default_enqueue_long, "def-ex-long"}, |
|
|
|
{{&default_enqueue_short, &default_enqueue_short, "def-ex-short"}, |
|
|
|
{&resolver_enqueue_short, &resolver_enqueue_short, "res-ex-short"}, |
|
|
|
{&default_enqueue_long, &default_enqueue_long, "def-ex-long"}}, |
|
|
|
{&resolver_enqueue_long, &resolver_enqueue_long, "res-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_[] = { |
|
|
|
|
|
|
|
{&vtables_[0]}, // Default short
|
|
|
|
static grpc_closure_scheduler |
|
|
|
{&vtables_[1]}, // Default long
|
|
|
|
schedulers_[GRPC_NUM_EXECUTORS][GRPC_NUM_EXECUTOR_JOB_TYPES] = { |
|
|
|
{&vtables_[2]}, // Resolver short
|
|
|
|
{{&vtables_[GRPC_DEFAULT_EXECUTOR][GRPC_EXECUTOR_SHORT]}, |
|
|
|
{&vtables_[3]} // Resolver long
|
|
|
|
{&vtables_[GRPC_DEFAULT_EXECUTOR][GRPC_EXECUTOR_LONG]}}, |
|
|
|
}; |
|
|
|
{{&vtables_[GRPC_RESOLVER_EXECUTOR][GRPC_EXECUTOR_SHORT]}, |
|
|
|
|
|
|
|
{&vtables_[GRPC_RESOLVER_EXECUTOR][GRPC_EXECUTOR_LONG]}}}; |
|
|
|
const char* executor_name(GrpcExecutorType executor_type) { |
|
|
|
|
|
|
|
switch (executor_type) { |
|
|
|
|
|
|
|
case GRPC_DEFAULT_EXECUTOR: |
|
|
|
|
|
|
|
return "default-executor"; |
|
|
|
|
|
|
|
case GRPC_RESOLVER_EXECUTOR: |
|
|
|
|
|
|
|
return "resolver-executor"; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
GPR_UNREACHABLE_CODE(return "unknown"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// grpc_executor_init() and grpc_executor_shutdown() functions are called in the
|
|
|
|
// 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
|
|
|
|
// 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
|
|
|
|
// global mutex. So it is okay to assume that these functions are thread-safe
|
|
|
|
void grpc_executor_init() { |
|
|
|
void grpc_executor_init() { |
|
|
|
EXECUTOR_TRACE0("grpc_executor_init() enter"); |
|
|
|
EXECUTOR_TRACE0("grpc_executor_init() enter"); |
|
|
|
for (int i = 0; i < GRPC_NUM_EXECUTORS; i++) { |
|
|
|
|
|
|
|
// Return if grpc_executor_init() already called earlier
|
|
|
|
|
|
|
|
if (executors[i] != nullptr) { |
|
|
|
|
|
|
|
// Ideally we should also assert that all executors i.e executor[0] to
|
|
|
|
|
|
|
|
// executor[GRPC_NUM_EXECUTORS-1] are != nullptr too.
|
|
|
|
|
|
|
|
GPR_ASSERT(i == 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
executors[i] = grpc_core::New<GrpcExecutor>( |
|
|
|
// Return if grpc_executor_init() is already called earlier
|
|
|
|
executor_name(static_cast<GrpcExecutorType>(i))); |
|
|
|
if (executors[GRPC_DEFAULT_EXECUTOR] != nullptr) { |
|
|
|
executors[i]->Init(); |
|
|
|
GPR_ASSERT(executors[GRPC_RESOLVER_EXECUTOR] != nullptr); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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"); |
|
|
|
EXECUTOR_TRACE0("grpc_executor_init() done"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorType executor_type, |
|
|
|
grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorType executor_type, |
|
|
|
GrpcExecutorJobType job_type) { |
|
|
|
GrpcExecutorJobType job_type) { |
|
|
|
return &schedulers_[(executor_type * GRPC_NUM_EXECUTORS) + job_type]; |
|
|
|
return &schedulers_[executor_type][job_type]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type) { |
|
|
|
grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type) { |
|
|
@ -395,32 +386,33 @@ grpc_closure_scheduler* grpc_executor_scheduler(GrpcExecutorJobType job_type) { |
|
|
|
|
|
|
|
|
|
|
|
void grpc_executor_shutdown() { |
|
|
|
void grpc_executor_shutdown() { |
|
|
|
EXECUTOR_TRACE0("grpc_executor_shutdown() enter"); |
|
|
|
EXECUTOR_TRACE0("grpc_executor_shutdown() enter"); |
|
|
|
for (int i = 0; i < GRPC_NUM_EXECUTORS; i++) { |
|
|
|
|
|
|
|
// Return if grpc_executor_shutdown() is already called earlier
|
|
|
|
// Return if grpc_executor_shutdown() is already called earlier
|
|
|
|
if (executors[i] == nullptr) { |
|
|
|
if (executors[GRPC_DEFAULT_EXECUTOR] == nullptr) { |
|
|
|
// Ideally we should also assert that all executors i.e executor[0] to
|
|
|
|
GPR_ASSERT(executors[GRPC_RESOLVER_EXECUTOR] == nullptr); |
|
|
|
// executor[GRPC_NUM_EXECUTORS-1] are nullptr too.
|
|
|
|
return; |
|
|
|
GPR_ASSERT(i == 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
executors[i]->Shutdown(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
executors[GRPC_DEFAULT_EXECUTOR]->Shutdown(); |
|
|
|
|
|
|
|
executors[GRPC_RESOLVER_EXECUTOR]->Shutdown(); |
|
|
|
|
|
|
|
|
|
|
|
// Delete the executor objects.
|
|
|
|
// Delete the executor objects.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// NOTE: It is important to do this in a separate loop (i.e ONLY after all the
|
|
|
|
// NOTE: It is important to call Shutdown() on all executors first before
|
|
|
|
// executors are 'Shutdown' first) because it is possible for one executor
|
|
|
|
// calling Delete() because it is possible for one executor (that is not
|
|
|
|
// (that is not shutdown yet) to call Enqueue() on a different executor which
|
|
|
|
// shutdown yet) to call Enqueue() on a different executor which is already
|
|
|
|
// is already shutdown. This is legal and in such cases, the Enqueue()
|
|
|
|
// shutdown. This is legal and in such cases, the Enqueue() operation
|
|
|
|
// operation effectively "fails" and enqueues that closure on the calling
|
|
|
|
// effectively "fails" and enqueues that closure on the calling thread's
|
|
|
|
// thread's exec_ctx.
|
|
|
|
// exec_ctx.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// By ensuring that all executors are shutdown first, we are also ensuring
|
|
|
|
// By ensuring that all executors are shutdown first, we are also ensuring
|
|
|
|
// that no thread is active across all executors.
|
|
|
|
// that no thread is active across all executors.
|
|
|
|
for (int i = 0; i < GRPC_NUM_EXECUTORS; i++) { |
|
|
|
|
|
|
|
grpc_core::Delete<GrpcExecutor>(executors[i]); |
|
|
|
grpc_core::Delete<GrpcExecutor>(executors[GRPC_DEFAULT_EXECUTOR]); |
|
|
|
executors[i] = nullptr; |
|
|
|
grpc_core::Delete<GrpcExecutor>(executors[GRPC_RESOLVER_EXECUTOR]); |
|
|
|
} |
|
|
|
executors[GRPC_DEFAULT_EXECUTOR] = nullptr; |
|
|
|
|
|
|
|
executors[GRPC_RESOLVER_EXECUTOR] = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
EXECUTOR_TRACE0("grpc_executor_shutdown() done"); |
|
|
|
EXECUTOR_TRACE0("grpc_executor_shutdown() done"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|