/* * * 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. * */ #include #include "src/core/lib/event_engine/posix_engine/timer_heap.h" #include #include #include "src/core/lib/event_engine/posix_engine/timer.h" namespace grpc_event_engine { namespace posix_engine { /* Adjusts a heap so as to move a hole at position i closer to the root, until a suitable position is found for element t. Then, copies t into that position. This functor is called each time immediately after modifying a value in the underlying container, with the offset of the modified element as its argument. */ void TimerHeap::AdjustUpwards(size_t i, Timer* t) { while (i > 0) { size_t parent = (i - 1) / 2; if (timers_[parent]->deadline <= t->deadline) break; timers_[i] = timers_[parent]; timers_[i]->heap_index = i; i = parent; } timers_[i] = t; t->heap_index = i; } /* Adjusts a heap so as to move a hole at position i farther away from the root, until a suitable position is found for element t. Then, copies t into that position. */ void TimerHeap::AdjustDownwards(size_t i, Timer* t) { for (;;) { size_t left_child = 1 + 2 * i; if (left_child >= timers_.size()) break; size_t right_child = left_child + 1; size_t next_i = right_child < timers_.size() && timers_[left_child]->deadline > timers_[right_child]->deadline ? right_child : left_child; if (t->deadline <= timers_[next_i]->deadline) break; timers_[i] = timers_[next_i]; timers_[i]->heap_index = i; i = next_i; } timers_[i] = t; t->heap_index = i; } void TimerHeap::NoteChangedPriority(Timer* timer) { uint32_t i = timer->heap_index; uint32_t parent = static_cast((static_cast(i) - 1) / 2); if (timers_[parent]->deadline > timer->deadline) { AdjustUpwards(i, timer); } else { AdjustDownwards(i, timer); } } bool TimerHeap::Add(Timer* timer) { timer->heap_index = timers_.size(); timers_.push_back(timer); AdjustUpwards(timer->heap_index, timer); return timer->heap_index == 0; } void TimerHeap::Remove(Timer* timer) { uint32_t i = timer->heap_index; if (i == timers_.size() - 1) { timers_.pop_back(); return; } timers_[i] = timers_[timers_.size() - 1]; timers_[i]->heap_index = i; timers_.pop_back(); NoteChangedPriority(timers_[i]); } bool TimerHeap::is_empty() { return timers_.empty(); } Timer* TimerHeap::Top() { return timers_[0]; } void TimerHeap::Pop() { Remove(Top()); } } // namespace posix_engine } // namespace grpc_event_engine