// // // 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_TIMER_H #define GRPC_SRC_CORE_LIB_IOMGR_TIMER_H #include #include #include #include #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/port.h" typedef struct grpc_timer { int64_t deadline; // Uninitialized if not using heap, or INVALID_HEAP_INDEX if not in heap. uint32_t heap_index; bool pending; struct grpc_timer* next; struct grpc_timer* prev; grpc_closure* closure; #ifndef NDEBUG struct grpc_timer* hash_table_next; #endif // Optional field used by custom timers union { void* custom_timer; grpc_event_engine::experimental::EventEngine::TaskHandle ee_task_handle; }; } grpc_timer; static_assert(std::is_trivial::value, "grpc_timer is expected to be a trivial type"); typedef enum { GRPC_TIMERS_NOT_CHECKED, GRPC_TIMERS_CHECKED_AND_EMPTY, GRPC_TIMERS_FIRED, } grpc_timer_check_result; typedef struct grpc_timer_vtable { void (*init)(grpc_timer* timer, grpc_core::Timestamp, grpc_closure* closure); void (*cancel)(grpc_timer* timer); // Internal API grpc_timer_check_result (*check)(grpc_core::Timestamp* next); void (*list_init)(); void (*list_shutdown)(void); void (*consume_kick)(void); } grpc_timer_vtable; // Initialize *timer. When expired or canceled, closure will be called with // error set to indicate if it expired (absl::OkStatus()) or was canceled // (absl::CancelledError()). *closure is guaranteed to be called exactly once, // and application code should check the error to determine how it was invoked. // The application callback is also responsible for maintaining information // about when to free up any user-level state. Behavior is undefined for a // deadline of grpc_core::Timestamp::InfFuture(). void grpc_timer_init(grpc_timer* timer, grpc_core::Timestamp deadline, grpc_closure* closure); // Initialize *timer without setting it. This can later be passed through // the regular init or cancel void grpc_timer_init_unset(grpc_timer* timer); // Note that there is no timer destroy function. This is because the // timer is a one-time occurrence with a guarantee that the callback will // be called exactly once, either at expiration or cancellation. Thus, all // the internal timer event management state is destroyed just before // that callback is invoked. If the user has additional state associated with // the timer, the user is responsible for determining when it is safe to // destroy that state. // Cancel an *timer. // There are three cases: // 1. We normally cancel the timer // 2. The timer has already run // 3. We can't cancel the timer because it is "in flight". // In all of these cases, the cancellation is still considered successful. // They are essentially distinguished in that the timer_cb will be run // exactly once from either the cancellation (with error absl::CancelledError()) // or from the activation (with error absl::OkStatus()). // Note carefully that the callback function MAY occur in the same callstack // as grpc_timer_cancel. It's expected that most timers will be cancelled (their // primary use is to implement deadlines), and so this code is optimized such // that cancellation costs as little as possible. Making callbacks run inline // matches this aim. // Requires: cancel() must happen after init() on a given timer void grpc_timer_cancel(grpc_timer* timer); // iomgr internal api for dealing with timers // Check for timers to be run, and run them. // Return true if timer callbacks were executed. // If next is non-null, TRY to update *next with the next running timer // IF that timer occurs before *next current value. // *next is never guaranteed to be updated on any given execution; however, // with high probability at least one thread in the system will see an update // at any time slice. grpc_timer_check_result grpc_timer_check(grpc_core::Timestamp* next); void grpc_timer_list_init(); void grpc_timer_list_shutdown(); // Consume a kick issued by grpc_kick_poller void grpc_timer_consume_kick(void); // the following must be implemented by each iomgr implementation void grpc_kick_poller(void); // Sets the timer implementation void grpc_set_timer_impl(grpc_timer_vtable* vtable); #endif // GRPC_SRC_CORE_LIB_IOMGR_TIMER_H