// // // 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. // // #ifndef GRPC_SRC_CORE_LIB_IOMGR_EXEC_CTX_H #define GRPC_SRC_CORE_LIB_IOMGR_EXEC_CTX_H #include <grpc/support/port_platform.h> #include <limits> #include <grpc/impl/grpc_types.h> #include <grpc/support/atm.h> #include <grpc/support/cpu.h> #include <grpc/support/log.h> #include <grpc/support/time.h> #include "src/core/lib/gpr/time_precise.h" #include "src/core/lib/gprpp/crash.h" #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/fork.h" #include "src/core/lib/gprpp/time.h" #include "src/core/lib/iomgr/closure.h" /// A combiner represents a list of work to be executed later. /// Forward declared here to avoid a circular dependency with combiner.h. grpc_combiner; // This exec_ctx is ready to return: either pre-populated, or cached as soon as // the finish_check returns true #define GRPC_EXEC_CTX_FLAG_IS_FINISHED … // The exec_ctx's thread is (potentially) owned by a call or channel: care // should be given to not delete said call/channel from this exec_ctx #define GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP … // This exec ctx was initialized by an internal thread, and should not // be counted by fork handlers #define GRPC_EXEC_CTX_FLAG_IS_INTERNAL_THREAD … // This application callback exec ctx was initialized by an internal thread, and // should not be counted by fork handlers #define GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD … namespace grpc_core { class Combiner; /// Execution context. /// A bag of data that collects information along a callstack. /// It is created on the stack at core entry points (public API or iomgr), and /// stored internally as a thread-local variable. /// /// Generally, to create an exec_ctx instance, add the following line at the top /// of the public API entry point or at the start of a thread's work function : /// /// ExecCtx exec_ctx; /// /// Access the created ExecCtx instance using : /// ExecCtx::Get() /// /// Specific responsibilities (this may grow in the future): /// - track a list of core work that needs to be delayed until the base of the /// call stack (this provides a convenient mechanism to run callbacks /// without worrying about locking issues) /// - provide a decision maker (via IsReadyToFinish) that provides a /// signal as to whether a borrowed thread should continue to do work or /// should actively try to finish up and get this thread back to its owner /// /// CONVENTIONS: /// - Instance of this must ALWAYS be constructed on the stack, never /// heap allocated. /// - Do not pass exec_ctx as a parameter to a function. Always access it using /// ExecCtx::Get(). /// - NOTE: In the future, the convention is likely to change to allow only one /// ExecCtx on a thread's stack at the same time. The TODO below /// discusses this plan in more detail. /// /// TODO(yashykt): Only allow one "active" ExecCtx on a thread at the same time. /// Stage 1: If a new one is created on the stack, it should just /// pass-through to the underlying ExecCtx deeper in the thread's /// stack. /// Stage 2: Assert if a 2nd one is ever created on the stack /// since that implies a core re-entry outside of application /// callbacks. /// class ExecCtx { … }; /// Application-callback execution context. /// A bag of data that collects information along a callstack. /// It is created on the stack at core entry points, and stored internally /// as a thread-local variable. /// /// There are three key differences between this structure and ExecCtx: /// 1. ApplicationCallbackExecCtx builds a list of application-level /// callbacks, but ExecCtx builds a list of internal callbacks to invoke. /// 2. ApplicationCallbackExecCtx invokes its callbacks only at destruction; /// there is no explicit Flush method. /// 3. If more than one ApplicationCallbackExecCtx is created on the thread's /// stack, only the one closest to the base of the stack is actually /// active and this is the only one that enqueues application callbacks. /// (Unlike ExecCtx, it is not feasible to prevent multiple of these on the /// stack since the executing application callback may itself enter core. /// However, the new one created will just pass callbacks through to the /// base one and those will not be executed until the return to the /// destructor of the base one, preventing unlimited stack growth.) /// /// This structure exists because application callbacks may themselves cause a /// core re-entry (e.g., through a public API call) and if that call in turn /// causes another application-callback, there could be arbitrarily growing /// stacks of core re-entries. Instead, any application callbacks instead should /// not be invoked until other core work is done and other application callbacks /// have completed. To accomplish this, any application callback should be /// enqueued using ApplicationCallbackExecCtx::Enqueue . /// /// CONVENTIONS: /// - Instances of this must ALWAYS be constructed on the stack, never /// heap allocated. /// - Instances of this are generally constructed before ExecCtx when needed. /// The only exception is for ExecCtx's that are explicitly flushed and /// that survive beyond the scope of the function that can cause application /// callbacks to be invoked (e.g., in the timer thread). /// /// Generally, core entry points that may trigger application-level callbacks /// will have the following declarations: /// /// ApplicationCallbackExecCtx callback_exec_ctx; /// ExecCtx exec_ctx; /// /// This ordering is important to make sure that the ApplicationCallbackExecCtx /// is destroyed after the ExecCtx (to prevent the re-entry problem described /// above, as well as making sure that ExecCtx core callbacks are invoked first) /// /// class ApplicationCallbackExecCtx { … }; } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_IOMGR_EXEC_CTX_H