aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/iomgr/exec_ctx.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib/iomgr/exec_ctx.h')
-rw-r--r--src/core/lib/iomgr/exec_ctx.h182
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 */