diff options
author | 2017-10-13 16:07:13 -0700 | |
---|---|---|
committer | 2017-10-18 17:12:19 -0700 | |
commit | 0ee7574732a06e8cace4e099a678f4bd5dbff679 (patch) | |
tree | e43d5de442fdcc3d39cd5af687f319fa39612d3f /src/core/lib/iomgr/exec_ctx.h | |
parent | 6bf5f833efe2cb9e2ecc14358dd9699cd5d05263 (diff) |
Removing instances of exec_ctx being passed around in functions in
src/core. exec_ctx is now a thread_local pointer of type ExecCtx instead of
grpc_exec_ctx which is initialized whenever ExecCtx is instantiated. ExecCtx
also keeps track of the previous exec_ctx so that nesting of exec_ctx is
allowed. This means that there is only one exec_ctx being used at any
time. Also, grpc_exec_ctx_finish is called in the destructor of the
object, and the previous exec_ctx is restored to avoid breaking current
functionality. The code still explicitly calls grpc_exec_ctx_finish
because removing all such instances causes the code to break.
Diffstat (limited to 'src/core/lib/iomgr/exec_ctx.h')
-rw-r--r-- | src/core/lib/iomgr/exec_ctx.h | 76 |
1 files changed, 54 insertions, 22 deletions
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index 44b9be7aa9..f79c7ae89a 100644 --- a/src/core/lib/iomgr/exec_ctx.h +++ b/src/core/lib/iomgr/exec_ctx.h @@ -21,6 +21,7 @@ #include <grpc/support/atm.h> #include <grpc/support/cpu.h> +#include <grpc/support/log.h> #include "src/core/lib/iomgr/closure.h" @@ -74,56 +75,87 @@ struct grpc_exec_ctx { uintptr_t flags; unsigned starting_cpu; void *check_ready_to_finish_arg; - bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg); + bool (*check_ready_to_finish)(void *arg); bool now_is_valid; grpc_millis now; + const char *creator; }; -/* initializer for grpc_exec_ctx: - prefer to use GRPC_EXEC_CTX_INIT whenever possible */ -#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \ - { \ - GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, gpr_cpu_current_cpu(), \ - finish_check_arg, finish_check, false, 0 \ - } - -/* initialize an execution context at the top level of an API call into grpc - (this is safe to use elsewhere, though possibly not as efficient) */ -#define GRPC_EXEC_CTX_INIT \ - GRPC_EXEC_CTX_INITIALIZER(GRPC_EXEC_CTX_FLAG_IS_FINISHED, NULL, NULL) - extern grpc_closure_scheduler *grpc_schedule_on_exec_ctx; -bool grpc_exec_ctx_has_work(grpc_exec_ctx *exec_ctx); +bool grpc_exec_ctx_has_work(); /** Flush any work that has been enqueued onto this grpc_exec_ctx. * Caller must guarantee that no interfering locks are held. * Returns true if work was performed, false otherwise. */ -bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx); +bool grpc_exec_ctx_flush(); /** Finish any pending work for a grpc_exec_ctx. Must be called before * the instance is destroyed, or work may be lost. */ -void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx); +void grpc_exec_ctx_finish(); /** Returns true if we'd like to leave this execution context as soon as possible: useful for deciding whether to do something more or not depending on outside context */ -bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx); +bool grpc_exec_ctx_ready_to_finish(); /** A finish check that is never ready to finish */ -bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored); +bool grpc_never_ready_to_finish(void *arg_ignored); /** A finish check that is always ready to finish */ -bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored); +bool grpc_always_ready_to_finish(void *arg_ignored); void grpc_exec_ctx_global_init(void); void grpc_exec_ctx_global_init(void); void grpc_exec_ctx_global_shutdown(void); -grpc_millis grpc_exec_ctx_now(grpc_exec_ctx *exec_ctx); -void grpc_exec_ctx_invalidate_now(grpc_exec_ctx *exec_ctx); +grpc_millis grpc_exec_ctx_now(); +void grpc_exec_ctx_invalidate_now(); gpr_timespec grpc_millis_to_timespec(grpc_millis millis, gpr_clock_type clock); grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec timespec); grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec timespec); +inline grpc_exec_ctx make_exec_ctx(grpc_exec_ctx r) { + grpc_exec_ctx_flush(); + return r; +} + +class ExecCtx { + public: + ExecCtx(); + ExecCtx(uintptr_t fl, bool (*finish_check)(void *arg), + void *finish_check_arg); + ~ExecCtx(); + + grpc_closure_list closure_list; + /** currently active combiner: updated only via combiner.c */ + grpc_combiner *active_combiner; + /** last active combiner in the active combiner list */ + grpc_combiner *last_combiner; + uintptr_t flags; + unsigned starting_cpu; + void *check_ready_to_finish_arg; + bool (*check_ready_to_finish)(void *arg); + + bool now_is_valid; + grpc_millis now; + + private: + ExecCtx *last_exec_ctx; +}; + +extern thread_local ExecCtx *exec_ctx; + +/* initializer for grpc_exec_ctx: + * prefer to use GRPC_EXEC_CTX_INIT whenever possible */ +#define GRPC_EXEC_CTX_INITIALIZER(flags, finish_check, finish_check_arg) \ + make_exec_ctx(grpc_exec_ctx{GRPC_CLOSURE_LIST_INIT, NULL, NULL, flags, \ + gpr_cpu_current_cpu(), finish_check_arg, \ + finish_check, false, 0, __PRETTY_FUNCTION__}) + +/* initialize an execution context at the top level of an API call into grpc + (this is safe to use elsewhere, though possibly not as efficient) */ +#define GRPC_EXEC_CTX_INIT \ + GRPC_EXEC_CTX_INITIALIZER(GRPC_EXEC_CTX_FLAG_IS_FINISHED, NULL, NULL) + #ifdef __cplusplus } #endif |