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 <string.h>
20
21 #include <cstdint>
22 #include <limits>
23
24 #include <grpc/grpc.h>
25 #include <grpc/support/log.h>
26
27 #include "src/core/lib/debug/trace.h"
28 #include "src/core/lib/gprpp/crash.h"
29 #include "src/core/lib/gprpp/time.h"
30 #include "src/core/lib/iomgr/iomgr_internal.h"
31 #include "src/core/lib/iomgr/port.h"
32 #include "src/core/lib/iomgr/timer.h"
33 #include "test/core/util/test_config.h"
34 #include "test/core/util/tracer_util.h"
35
36 #define MAX_CB 30
37
38 extern grpc_core::TraceFlag grpc_timer_trace;
39 extern grpc_core::TraceFlag grpc_timer_check_trace;
40
41 static int cb_called[MAX_CB][2];
42 static const int64_t kHoursIn25Days = 25 * 24;
43 static const grpc_core::Duration k25Days =
44 grpc_core::Duration::Hours(kHoursIn25Days);
45
cb(void * arg,grpc_error_handle error)46 static void cb(void* arg, grpc_error_handle error) {
47 cb_called[reinterpret_cast<intptr_t>(arg)][error.ok()]++;
48 }
49
add_test(void)50 static void add_test(void) {
51 int i;
52 grpc_timer timers[20];
53 grpc_core::ExecCtx exec_ctx;
54
55 gpr_log(GPR_INFO, "add_test");
56
57 grpc_timer_list_init();
58 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_trace);
59 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_check_trace);
60 memset(cb_called, 0, sizeof(cb_called));
61
62 grpc_core::Timestamp start = grpc_core::Timestamp::Now();
63
64 // 10 ms timers. will expire in the current epoch
65 for (i = 0; i < 10; i++) {
66 grpc_timer_init(
67 &timers[i], start + grpc_core::Duration::Milliseconds(10),
68 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)i, grpc_schedule_on_exec_ctx));
69 }
70
71 // 1010 ms timers. will expire in the next epoch
72 for (i = 10; i < 20; i++) {
73 grpc_timer_init(
74 &timers[i], start + grpc_core::Duration::Milliseconds(1010),
75 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)i, grpc_schedule_on_exec_ctx));
76 }
77
78 // collect timers. Only the first batch should be ready.
79 grpc_core::ExecCtx::Get()->TestOnlySetNow(
80 start + grpc_core::Duration::Milliseconds(500));
81 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_FIRED);
82 grpc_core::ExecCtx::Get()->Flush();
83 for (i = 0; i < 20; i++) {
84 GPR_ASSERT(cb_called[i][1] == (i < 10));
85 GPR_ASSERT(cb_called[i][0] == 0);
86 }
87
88 grpc_core::ExecCtx::Get()->TestOnlySetNow(
89 start + grpc_core::Duration::Milliseconds(600));
90 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_CHECKED_AND_EMPTY);
91 grpc_core::ExecCtx::Get()->Flush();
92 for (i = 0; i < 30; i++) {
93 GPR_ASSERT(cb_called[i][1] == (i < 10));
94 GPR_ASSERT(cb_called[i][0] == 0);
95 }
96
97 // collect the rest of the timers
98 grpc_core::ExecCtx::Get()->TestOnlySetNow(
99 start + grpc_core::Duration::Milliseconds(1500));
100 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_FIRED);
101 grpc_core::ExecCtx::Get()->Flush();
102 for (i = 0; i < 30; i++) {
103 GPR_ASSERT(cb_called[i][1] == (i < 20));
104 GPR_ASSERT(cb_called[i][0] == 0);
105 }
106
107 grpc_core::ExecCtx::Get()->TestOnlySetNow(
108 start + grpc_core::Duration::Milliseconds(1600));
109 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_CHECKED_AND_EMPTY);
110 for (i = 0; i < 30; i++) {
111 GPR_ASSERT(cb_called[i][1] == (i < 20));
112 GPR_ASSERT(cb_called[i][0] == 0);
113 }
114
115 grpc_timer_list_shutdown();
116 }
117
118 // Cleaning up a list with pending timers.
destruction_test(void)119 void destruction_test(void) {
120 grpc_timer timers[5];
121 grpc_core::ExecCtx exec_ctx;
122
123 gpr_log(GPR_INFO, "destruction_test");
124
125 grpc_core::ExecCtx::Get()->TestOnlySetNow(
126 grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(0));
127 grpc_timer_list_init();
128 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_trace);
129 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_check_trace);
130 memset(cb_called, 0, sizeof(cb_called));
131
132 grpc_timer_init(
133 &timers[0], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(100),
134 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)0, grpc_schedule_on_exec_ctx));
135 grpc_timer_init(
136 &timers[1], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(3),
137 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)1, grpc_schedule_on_exec_ctx));
138 grpc_timer_init(
139 &timers[2], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(100),
140 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)2, grpc_schedule_on_exec_ctx));
141 grpc_timer_init(
142 &timers[3], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(3),
143 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)3, grpc_schedule_on_exec_ctx));
144 grpc_timer_init(
145 &timers[4], grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(1),
146 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)4, grpc_schedule_on_exec_ctx));
147 grpc_core::ExecCtx::Get()->TestOnlySetNow(
148 grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(2));
149 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_FIRED);
150 grpc_core::ExecCtx::Get()->Flush();
151 GPR_ASSERT(1 == cb_called[4][1]);
152 grpc_timer_cancel(&timers[0]);
153 grpc_timer_cancel(&timers[3]);
154 grpc_core::ExecCtx::Get()->Flush();
155 GPR_ASSERT(1 == cb_called[0][0]);
156 GPR_ASSERT(1 == cb_called[3][0]);
157
158 grpc_timer_list_shutdown();
159 grpc_core::ExecCtx::Get()->Flush();
160 GPR_ASSERT(1 == cb_called[1][0]);
161 GPR_ASSERT(1 == cb_called[2][0]);
162 }
163
164 // Cleans up a list with pending timers that simulate long-running-services.
165 // This test does the following:
166 // 1) Simulates grpc server start time to 25 days in the past (completed in
167 // `main` using TestOnlyGlobalInit())
168 // 2) Creates 4 timers - one with a deadline 25 days in the future, one just
169 // 3 milliseconds in future, one way out in the future, and one using the
170 // grpc_timespec_to_millis_round_up function to compute a deadline of 25
171 // days in the future
172 // 3) Simulates 4 milliseconds of elapsed time by changing `now` (cached at
173 // step 1) to `now+4`
174 // 4) Shuts down the timer list
175 // https://github.com/grpc/grpc/issues/15904
long_running_service_cleanup_test(void)176 void long_running_service_cleanup_test(void) {
177 grpc_timer timers[4];
178 grpc_core::ExecCtx exec_ctx;
179
180 gpr_log(GPR_INFO, "long_running_service_cleanup_test");
181
182 grpc_core::Timestamp now = grpc_core::Timestamp::Now();
183 GPR_ASSERT(now.milliseconds_after_process_epoch() >= k25Days.millis());
184 grpc_timer_list_init();
185 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_trace);
186 grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_check_trace);
187 memset(cb_called, 0, sizeof(cb_called));
188
189 grpc_timer_init(
190 &timers[0], now + k25Days,
191 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)0, grpc_schedule_on_exec_ctx));
192 grpc_timer_init(
193 &timers[1], now + grpc_core::Duration::Milliseconds(3),
194 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)1, grpc_schedule_on_exec_ctx));
195 grpc_timer_init(
196 &timers[2],
197 grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
198 std::numeric_limits<int64_t>::max() - 1),
199 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)2, grpc_schedule_on_exec_ctx));
200
201 gpr_timespec deadline_spec =
202 (now + k25Days).as_timespec(gpr_clock_type::GPR_CLOCK_MONOTONIC);
203
204 // grpc_timespec_to_millis_round_up is how users usually compute a millisecond
205 // input value into grpc_timer_init, so we mimic that behavior here
206 grpc_timer_init(
207 &timers[3], grpc_core::Timestamp::FromTimespecRoundUp(deadline_spec),
208 GRPC_CLOSURE_CREATE(cb, (void*)(intptr_t)3, grpc_schedule_on_exec_ctx));
209
210 grpc_core::ExecCtx::Get()->TestOnlySetNow(
211 now + grpc_core::Duration::Milliseconds(4));
212 GPR_ASSERT(grpc_timer_check(nullptr) == GRPC_TIMERS_FIRED);
213 grpc_core::ExecCtx::Get()->Flush();
214 GPR_ASSERT(0 == cb_called[0][0]); // Timer 0 not called
215 GPR_ASSERT(0 == cb_called[0][1]);
216 GPR_ASSERT(0 == cb_called[1][0]);
217 GPR_ASSERT(1 == cb_called[1][1]); // Timer 1 fired
218 GPR_ASSERT(0 == cb_called[2][0]); // Timer 2 not called
219 GPR_ASSERT(0 == cb_called[2][1]);
220 GPR_ASSERT(0 == cb_called[3][0]); // Timer 3 not called
221 GPR_ASSERT(0 == cb_called[3][1]);
222
223 grpc_timer_list_shutdown();
224 grpc_core::ExecCtx::Get()->Flush();
225 // Timers 0, 2, and 3 were fired with an error during cleanup
226 GPR_ASSERT(1 == cb_called[0][0]);
227 GPR_ASSERT(0 == cb_called[1][0]);
228 GPR_ASSERT(1 == cb_called[2][0]);
229 GPR_ASSERT(1 == cb_called[3][0]);
230 }
231
main(int argc,char ** argv)232 int main(int argc, char** argv) {
233 gpr_time_init();
234
235 // Tests with default g_start_time
236 {
237 grpc::testing::TestEnvironment env(&argc, argv);
238 grpc_core::ExecCtx exec_ctx;
239 grpc_set_default_iomgr_platform();
240 grpc_iomgr_platform_init();
241 gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
242 add_test();
243 destruction_test();
244 grpc_iomgr_platform_shutdown();
245 }
246
247 // Begin long running service tests
248 {
249 grpc::testing::TestEnvironment env(&argc, argv);
250 // Set g_start_time back 25 days.
251 // We set g_start_time here in case there are any initialization
252 // dependencies that use g_start_time.
253 grpc_core::TestOnlySetProcessEpoch(gpr_time_sub(
254 gpr_now(gpr_clock_type::GPR_CLOCK_MONOTONIC),
255 gpr_time_add(gpr_time_from_hours(kHoursIn25Days, GPR_TIMESPAN),
256 gpr_time_from_seconds(10, GPR_TIMESPAN))));
257 grpc_core::ExecCtx exec_ctx;
258 grpc_set_default_iomgr_platform();
259 grpc_iomgr_platform_init();
260 gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
261 long_running_service_cleanup_test();
262 add_test();
263 destruction_test();
264 grpc_iomgr_platform_shutdown();
265 }
266
267 return 0;
268 }
269