diff options
Diffstat (limited to 'src/core/lib/iomgr/exec_ctx.h')
-rw-r--r-- | src/core/lib/iomgr/exec_ctx.h | 182 |
1 files changed, 129 insertions, 53 deletions
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index b415d2c255..b0c1740155 100644 --- a/src/core/lib/iomgr/exec_ctx.h +++ b/src/core/lib/iomgr/exec_ctx.h @@ -21,6 +21,8 @@ #include <grpc/support/atm.h> #include <grpc/support/cpu.h> +#include <grpc/support/log.h> +#include <grpc/support/tls.h> #include "src/core/lib/iomgr/closure.h" @@ -41,6 +43,13 @@ typedef struct grpc_combiner grpc_combiner; should be given to not delete said call/channel from this exec_ctx */ #define GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP 2 +extern grpc_closure_scheduler* grpc_schedule_on_exec_ctx; + +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); + +namespace grpc_core { /** Execution context. * A bag of data that collects information along a callstack. * Generally created at public API entry points, and passed down as @@ -61,63 +70,130 @@ typedef struct grpc_combiner grpc_combiner; * - Instances are always passed as the first argument to a function that * takes it, and always as a pointer (grpc_exec_ctx is never copied). */ -struct grpc_exec_ctx { - 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)(grpc_exec_ctx* exec_ctx, void* arg); - - bool now_is_valid; - grpc_millis now; -}; +class ExecCtx { + public: + /** Default Constructor */ + + ExecCtx() : flags_(GRPC_EXEC_CTX_FLAG_IS_FINISHED) { Set(this); } -/* 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 \ + /** Parameterised Constructor */ + ExecCtx(uintptr_t fl) : flags_(fl) { Set(this); } + + /** Destructor */ + ~ExecCtx() { + flags_ |= GRPC_EXEC_CTX_FLAG_IS_FINISHED; + Flush(); + Set(last_exec_ctx_); } -/* 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) + /** Disallow copy and assignment operators */ + ExecCtx(const ExecCtx&) = delete; + ExecCtx& operator=(const ExecCtx&) = delete; -extern grpc_closure_scheduler* grpc_schedule_on_exec_ctx; + /** Return starting_cpu */ + unsigned starting_cpu() const { return starting_cpu_; } -bool grpc_exec_ctx_has_work(grpc_exec_ctx* exec_ctx); - -/** 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); -/** 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); -/** 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); -/** A finish check that is never ready to finish */ -bool grpc_never_ready_to_finish(grpc_exec_ctx* exec_ctx, 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); - -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); -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); + struct CombinerData { + /* currently active combiner: updated only via combiner.c */ + grpc_combiner* active_combiner; + /* last active combiner in the active combiner list */ + grpc_combiner* last_combiner; + }; + + /** Only to be used by grpc-combiner code */ + CombinerData* combiner_data() { return &combiner_data_; } + + /** Return pointer to grpc_closure_list */ + grpc_closure_list* closure_list() { return &closure_list_; } + + /** Return flags */ + uintptr_t flags() { return flags_; } + + /** Checks if there is work to be done */ + bool HasWork() { + return combiner_data_.active_combiner != NULL || + !grpc_closure_list_empty(closure_list_); + } + + /** 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 Flush(); + + /** 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 IsReadyToFinish() { + if ((flags_ & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0) { + if (CheckReadyToFinish()) { + flags_ |= GRPC_EXEC_CTX_FLAG_IS_FINISHED; + return true; + } + return false; + } else { + return true; + } + } + + /** Returns the stored current time relative to start if valid, + * otherwise refreshes the stored time, sets it valid and returns the new + * value */ + grpc_millis Now(); + + /** Invalidates the stored time value. A new time value will be set on calling + * Now() */ + void InvalidateNow() { now_is_valid_ = false; } + + /** To be used only by shutdown code in iomgr */ + void SetNowIomgrShutdown() { + now_ = GRPC_MILLIS_INF_FUTURE; + now_is_valid_ = true; + } + + /** To be used only for testing. + * Sets the now value + */ + void TestOnlySetNow(grpc_millis new_val) { + now_ = new_val; + now_is_valid_ = true; + } + + /** Finish any pending work for a grpc_exec_ctx. Must be called before + * the instance is destroyed, or work may be lost. */ + void Finish(); + + /** Global initialization for ExecCtx. Called by iomgr */ + static void GlobalInit(void); + + /** Global shutdown for ExecCtx. Called by iomgr */ + static void GlobalShutdown(void) { gpr_tls_destroy(&exec_ctx_); } + + /** Gets pointer to current exec_ctx */ + static ExecCtx* Get() { + return reinterpret_cast<ExecCtx*>(gpr_tls_get(&exec_ctx_)); + } + + protected: + /** Check if ready to finish */ + virtual bool CheckReadyToFinish() { return false; } + + private: + /** Set exec_ctx_ to exec_ctx */ + void Set(ExecCtx* exec_ctx) { + gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx)); + } + + grpc_closure_list closure_list_ = GRPC_CLOSURE_LIST_INIT; + CombinerData combiner_data_ = {nullptr, nullptr}; + uintptr_t flags_; + unsigned starting_cpu_ = gpr_cpu_current_cpu(); + + bool now_is_valid_ = false; + grpc_millis now_ = 0; + + GPR_TLS_CLASS_DECL(exec_ctx_); + ExecCtx* last_exec_ctx_ = Get(); +}; +} // namespace grpc_core #endif /* GRPC_CORE_LIB_IOMGR_EXEC_CTX_H */ |