• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/iomgr/port.h"
22 
23 #include "src/core/lib/iomgr/timer_heap.h"
24 
25 #include <string.h>
26 
27 #include <grpc/support/alloc.h>
28 
29 #include "src/core/lib/gpr/useful.h"
30 
31 /* Adjusts a heap so as to move a hole at position i closer to the root,
32    until a suitable position is found for element t. Then, copies t into that
33    position. This functor is called each time immediately after modifying a
34    value in the underlying container, with the offset of the modified element as
35    its argument. */
adjust_upwards(grpc_timer ** first,uint32_t i,grpc_timer * t)36 static void adjust_upwards(grpc_timer** first, uint32_t i, grpc_timer* t) {
37   while (i > 0) {
38     uint32_t parent = static_cast<uint32_t>((static_cast<int>(i) - 1) / 2);
39     if (first[parent]->deadline <= t->deadline) break;
40     first[i] = first[parent];
41     first[i]->heap_index = i;
42     i = parent;
43   }
44   first[i] = t;
45   t->heap_index = i;
46 }
47 
48 /* Adjusts a heap so as to move a hole at position i farther away from the root,
49    until a suitable position is found for element t.  Then, copies t into that
50    position. */
adjust_downwards(grpc_timer ** first,uint32_t i,uint32_t length,grpc_timer * t)51 static void adjust_downwards(grpc_timer** first, uint32_t i, uint32_t length,
52                              grpc_timer* t) {
53   for (;;) {
54     uint32_t left_child = 1u + 2u * i;
55     if (left_child >= length) break;
56     uint32_t right_child = left_child + 1;
57     uint32_t next_i = right_child < length && first[left_child]->deadline >
58                                                   first[right_child]->deadline
59                           ? right_child
60                           : left_child;
61     if (t->deadline <= first[next_i]->deadline) break;
62     first[i] = first[next_i];
63     first[i]->heap_index = i;
64     i = next_i;
65   }
66   first[i] = t;
67   t->heap_index = i;
68 }
69 
70 #define SHRINK_MIN_ELEMS 8
71 #define SHRINK_FULLNESS_FACTOR 2
72 
maybe_shrink(grpc_timer_heap * heap)73 static void maybe_shrink(grpc_timer_heap* heap) {
74   if (heap->timer_count >= 8 &&
75       heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) {
76     heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR;
77     heap->timers = static_cast<grpc_timer**>(
78         gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer*)));
79   }
80 }
81 
note_changed_priority(grpc_timer_heap * heap,grpc_timer * timer)82 static void note_changed_priority(grpc_timer_heap* heap, grpc_timer* timer) {
83   uint32_t i = timer->heap_index;
84   uint32_t parent = static_cast<uint32_t>((static_cast<int>(i) - 1) / 2);
85   if (heap->timers[parent]->deadline > timer->deadline) {
86     adjust_upwards(heap->timers, i, timer);
87   } else {
88     adjust_downwards(heap->timers, i, heap->timer_count, timer);
89   }
90 }
91 
grpc_timer_heap_init(grpc_timer_heap * heap)92 void grpc_timer_heap_init(grpc_timer_heap* heap) {
93   memset(heap, 0, sizeof(*heap));
94 }
95 
grpc_timer_heap_destroy(grpc_timer_heap * heap)96 void grpc_timer_heap_destroy(grpc_timer_heap* heap) { gpr_free(heap->timers); }
97 
grpc_timer_heap_add(grpc_timer_heap * heap,grpc_timer * timer)98 int grpc_timer_heap_add(grpc_timer_heap* heap, grpc_timer* timer) {
99   if (heap->timer_count == heap->timer_capacity) {
100     heap->timer_capacity =
101         GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2);
102     heap->timers = static_cast<grpc_timer**>(
103         gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer*)));
104   }
105   timer->heap_index = heap->timer_count;
106   adjust_upwards(heap->timers, heap->timer_count, timer);
107   heap->timer_count++;
108   return timer->heap_index == 0;
109 }
110 
grpc_timer_heap_remove(grpc_timer_heap * heap,grpc_timer * timer)111 void grpc_timer_heap_remove(grpc_timer_heap* heap, grpc_timer* timer) {
112   uint32_t i = timer->heap_index;
113   if (i == heap->timer_count - 1) {
114     heap->timer_count--;
115     maybe_shrink(heap);
116     return;
117   }
118   heap->timers[i] = heap->timers[heap->timer_count - 1];
119   heap->timers[i]->heap_index = i;
120   heap->timer_count--;
121   maybe_shrink(heap);
122   note_changed_priority(heap, heap->timers[i]);
123 }
124 
grpc_timer_heap_is_empty(grpc_timer_heap * heap)125 int grpc_timer_heap_is_empty(grpc_timer_heap* heap) {
126   return heap->timer_count == 0;
127 }
128 
grpc_timer_heap_top(grpc_timer_heap * heap)129 grpc_timer* grpc_timer_heap_top(grpc_timer_heap* heap) {
130   return heap->timers[0];
131 }
132 
grpc_timer_heap_pop(grpc_timer_heap * heap)133 void grpc_timer_heap_pop(grpc_timer_heap* heap) {
134   grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap));
135 }
136