blob: 4919720130202067fb8332d31bfe3e929b150a81 [file] [log] [blame]
Primiano Tuccidac91702021-04-30 15:47:51 +01001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/ext/base/periodic_task.h"
18
19#include "perfetto/ext/base/file_utils.h"
20#include "src/base/test/test_task_runner.h"
21#include "test/gtest_and_gmock.h"
22
23#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
24 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
25#include <unistd.h>
26#endif
27
28namespace perfetto {
29namespace base {
30
31namespace {
32
33TEST(PeriodicTaskTest, PostDelayedTaskMode) {
34 TestTaskRunner task_runner;
35 PeriodicTask pt(&task_runner);
36 uint32_t num_callbacks = 0;
37 auto quit_closure = task_runner.CreateCheckpoint("all_timers_done");
38
39 PeriodicTask::Args args;
40 args.task = [&] {
41 if (++num_callbacks == 3)
42 quit_closure();
43 };
44 args.period_ms = 1;
45 args.start_first_task_immediately = true;
46 pt.Start(std::move(args));
47 EXPECT_EQ(num_callbacks, 1u);
48 task_runner.RunUntilCheckpoint("all_timers_done");
49 EXPECT_EQ(num_callbacks, 3u);
50}
51
52// Call Reset() from a callback, ensure no further calls are made.
53TEST(PeriodicTaskTest, ResetFromCallback) {
54 TestTaskRunner task_runner;
55 PeriodicTask pt(&task_runner);
56 uint32_t num_callbacks = 0;
57 PeriodicTask::Args args;
58 auto quit_closure = task_runner.CreateCheckpoint("quit_closure");
59 args.task = [&] {
60 ++num_callbacks;
61 pt.Reset();
62 task_runner.PostDelayedTask(quit_closure, 5);
63 };
64 args.period_ms = 1;
65 pt.Start(std::move(args));
66 EXPECT_EQ(num_callbacks, 0u); // No immediate execution.
67
68 task_runner.RunUntilCheckpoint("quit_closure");
69 EXPECT_EQ(num_callbacks, 1u);
70}
71
72// Invalidates the timerfd, by replacing it with /dev/null, in the middle of
73// the periodic ticks. That causes the next read() to fail and fall back on
74// PostDelayedTask().
75// On Mac and other systems where timerfd is not supported this will fall back
76// on PostDelayedTask() immediately (and work).
77TEST(PeriodicTaskTest, FallbackIfTimerfdFails) {
78 TestTaskRunner task_runner;
79 PeriodicTask pt(&task_runner);
80 uint32_t num_callbacks = 0;
81 auto quit_closure = task_runner.CreateCheckpoint("all_timers_done");
82
83 PeriodicTask::Args args;
84 args.task = [&] {
85 ++num_callbacks;
86#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
87 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
88 if (num_callbacks == 3 && pt.timer_fd_for_testing() > 0) {
89 ScopedFile dev_null = OpenFile("/dev/null", O_RDONLY);
90 dup2(*dev_null, pt.timer_fd_for_testing());
91 }
92#else
Lalit Maganti442d3ef2021-05-05 14:25:20 +010093 EXPECT_FALSE(base::ScopedPlatformHandle::ValidityChecker::IsValid(
94 pt.timer_fd_for_testing()));
Primiano Tuccidac91702021-04-30 15:47:51 +010095#endif
96 if (num_callbacks == 6)
97 quit_closure();
98 };
99 args.period_ms = 1;
100 args.use_suspend_aware_timer = true;
101 pt.Start(std::move(args));
102 task_runner.RunUntilCheckpoint("all_timers_done");
103 EXPECT_EQ(num_callbacks, 6u);
104}
105
106TEST(PeriodicTaskTest, DestroyedFromCallback) {
107 TestTaskRunner task_runner;
108 std::unique_ptr<PeriodicTask> pt(new PeriodicTask(&task_runner));
109 uint32_t num_callbacks = 0;
110 PeriodicTask::Args args;
111 auto quit_closure = task_runner.CreateCheckpoint("quit_closure");
112 args.task = [&] {
113 ++num_callbacks;
114 pt.reset();
115 task_runner.PostDelayedTask(quit_closure, 5);
116 };
117 args.period_ms = 1;
118 args.use_suspend_aware_timer = true;
119 pt->Start(std::move(args));
120
121 task_runner.RunUntilCheckpoint("quit_closure");
122 EXPECT_EQ(num_callbacks, 1u);
123 EXPECT_FALSE(pt);
124}
125
126TEST(PeriodicTaskTest, DestroyedFromAnotherTask) {
127 TestTaskRunner task_runner;
128 std::unique_ptr<PeriodicTask> pt(new PeriodicTask(&task_runner));
129 uint32_t num_callbacks = 0;
130 PeriodicTask::Args args;
131 auto quit_closure = task_runner.CreateCheckpoint("quit_closure");
132 args.task = [&] {
133 if (++num_callbacks == 2) {
134 task_runner.PostTask([&] {
135 pt.reset();
136 task_runner.PostDelayedTask(quit_closure, 5);
137 });
138 }
139 };
140 args.period_ms = 1;
141 args.use_suspend_aware_timer = true;
142 pt->Start(std::move(args));
143
144 task_runner.RunUntilCheckpoint("quit_closure");
145 EXPECT_EQ(num_callbacks, 2u);
146 EXPECT_FALSE(pt);
147}
148
149// Checks the generation logic.
150TEST(PeriodicTaskTest, RestartWhileRunning) {
151 TestTaskRunner task_runner;
152 PeriodicTask pt(&task_runner);
153 uint32_t num_callbacks_a = 0;
154 uint32_t num_callbacks_b = 0;
155 auto quit_closure = task_runner.CreateCheckpoint("quit_closure");
156
157 auto reuse = [&] {
158 PeriodicTask::Args args;
159 args.period_ms = 1;
160 args.task = [&] {
161 if (++num_callbacks_b == 3)
162 quit_closure();
163 };
164 pt.Start(std::move(args));
165 };
166
167 PeriodicTask::Args args;
168 args.task = [&] {
169 if (++num_callbacks_a == 2)
170 task_runner.PostTask(reuse);
171 };
172 args.period_ms = 1;
173 args.use_suspend_aware_timer = true;
174 pt.Start(std::move(args));
175
176 task_runner.RunUntilCheckpoint("quit_closure");
177 EXPECT_EQ(num_callbacks_a, 2u);
178 EXPECT_EQ(num_callbacks_b, 3u);
179}
180
181TEST(PeriodicTaskTest, ImmediateExecution) {
182 TestTaskRunner task_runner;
183 PeriodicTask pt(&task_runner);
184 uint32_t num_callbacks = 0;
185
186 PeriodicTask::Args args;
187 args.task = [&] { ++num_callbacks; };
188 args.period_ms = 1;
189 pt.Start(args);
190 EXPECT_EQ(num_callbacks, 0u); // No immediate execution.
191
192 args.start_first_task_immediately = true;
193 pt.Start(args);
194 EXPECT_EQ(num_callbacks, 1u);
195}
196
197} // namespace
198} // namespace base
199} // namespace perfetto