xref: /aosp_15_r20/external/grpc-grpc/test/core/iomgr/timer_list_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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