aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/iomgr/exec_ctx.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib/iomgr/exec_ctx.cc')
-rw-r--r--src/core/lib/iomgr/exec_ctx.cc173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc
new file mode 100644
index 0000000000..3d17afcb8f
--- /dev/null
+++ b/src/core/lib/iomgr/exec_ctx.cc
@@ -0,0 +1,173 @@
+/*
+ *
+ * Copyright 2015 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 "src/core/lib/iomgr/exec_ctx.h"
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+
+#include "src/core/lib/iomgr/combiner.h"
+#include "src/core/lib/profiling/timers.h"
+
+bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) {
+ if ((exec_ctx->flags & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0) {
+ if (exec_ctx->check_ready_to_finish(exec_ctx,
+ exec_ctx->check_ready_to_finish_arg)) {
+ exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED;
+ return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) {
+ return false;
+}
+
+bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) {
+ return true;
+}
+
+bool grpc_exec_ctx_has_work(grpc_exec_ctx *exec_ctx) {
+ return exec_ctx->active_combiner != NULL ||
+ !grpc_closure_list_empty(exec_ctx->closure_list);
+}
+
+void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
+ exec_ctx->flags |= GRPC_EXEC_CTX_FLAG_IS_FINISHED;
+ grpc_exec_ctx_flush(exec_ctx);
+}
+
+static void exec_ctx_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+ grpc_error *error) {
+#ifndef NDEBUG
+ closure->scheduled = false;
+ if (GRPC_TRACER_ON(grpc_trace_closure)) {
+ gpr_log(GPR_DEBUG, "running closure %p: created [%s:%d]: %s [%s:%d]",
+ closure, closure->file_created, closure->line_created,
+ closure->run ? "run" : "scheduled", closure->file_initiated,
+ closure->line_initiated);
+ }
+#endif
+ closure->cb(exec_ctx, closure->cb_arg, error);
+#ifndef NDEBUG
+ if (GRPC_TRACER_ON(grpc_trace_closure)) {
+ gpr_log(GPR_DEBUG, "closure %p finished", closure);
+ }
+#endif
+ GRPC_ERROR_UNREF(error);
+}
+
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
+ bool did_something = 0;
+ GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
+ for (;;) {
+ if (!grpc_closure_list_empty(exec_ctx->closure_list)) {
+ grpc_closure *c = exec_ctx->closure_list.head;
+ exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
+ while (c != NULL) {
+ grpc_closure *next = c->next_data.next;
+ grpc_error *error = c->error_data.error;
+ did_something = true;
+ exec_ctx_run(exec_ctx, c, error);
+ c = next;
+ }
+ } else if (!grpc_combiner_continue_exec_ctx(exec_ctx)) {
+ break;
+ }
+ }
+ GPR_ASSERT(exec_ctx->active_combiner == NULL);
+ GPR_TIMER_END("grpc_exec_ctx_flush", 0);
+ return did_something;
+}
+
+static void exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+ grpc_error *error) {
+ grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
+}
+
+static gpr_timespec
+ g_start_time[GPR_TIMESPAN + 1]; // assumes GPR_TIMESPAN is the
+ // last enum value in
+ // gpr_clock_type
+
+void grpc_exec_ctx_global_init(void) {
+ for (int i = 0; i < GPR_TIMESPAN; i++) {
+ g_start_time[i] = gpr_now((gpr_clock_type)i);
+ }
+ // allows uniform treatment in conversion functions
+ g_start_time[GPR_TIMESPAN] = gpr_time_0(GPR_TIMESPAN);
+}
+
+void grpc_exec_ctx_global_shutdown(void) {}
+
+static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
+ ts = gpr_time_sub(ts, g_start_time[ts.clock_type]);
+ double x =
+ GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
+ if (x < 0) return 0;
+ if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+ return (gpr_atm)x;
+}
+
+static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
+ ts = gpr_time_sub(ts, g_start_time[ts.clock_type]);
+ double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
+ (double)ts.tv_nsec / GPR_NS_PER_MS +
+ (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
+ if (x < 0) return 0;
+ if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+ return (gpr_atm)x;
+}
+
+grpc_millis grpc_exec_ctx_now(grpc_exec_ctx *exec_ctx) {
+ if (!exec_ctx->now_is_valid) {
+ exec_ctx->now = timespec_to_atm_round_down(gpr_now(GPR_CLOCK_MONOTONIC));
+ exec_ctx->now_is_valid = true;
+ }
+ return exec_ctx->now;
+}
+
+void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx) {
+ exec_ctx->now_is_valid = false;
+}
+
+gpr_timespec grpc_millis_to_timespec(grpc_millis millis,
+ gpr_clock_type clock_type) {
+ if (clock_type == GPR_TIMESPAN) {
+ return gpr_time_from_millis(millis, GPR_TIMESPAN);
+ }
+ return gpr_time_add(g_start_time[clock_type],
+ gpr_time_from_millis(millis, GPR_TIMESPAN));
+}
+
+grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec ts) {
+ return timespec_to_atm_round_down(ts);
+}
+
+grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec ts) {
+ return timespec_to_atm_round_up(ts);
+}
+
+static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
+ exec_ctx_run, exec_ctx_sched, "exec_ctx"};
+static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable};
+grpc_closure_scheduler *grpc_schedule_on_exec_ctx = &exec_ctx_scheduler;