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