[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / unittests / Host / AlarmTest.cpp
blob94e72af3ffe8d1710c71e7c755af73b0382cf100
1 //===-- AlarmTest.cpp -----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/Alarm.h"
10 #include "gtest/gtest.h"
12 #include <chrono>
13 #include <thread>
15 using namespace lldb_private;
16 using namespace std::chrono_literals;
18 // Increase the timeout tenfold when running under ASan as it can have about the
19 // same performance overhead.
20 #if __has_feature(address_sanitizer)
21 static constexpr auto TEST_TIMEOUT = 10000ms;
22 #else
23 static constexpr auto TEST_TIMEOUT = 1000ms;
24 #endif
26 // The time between scheduling a callback and it getting executed. This should
27 // NOT be increased under ASan.
28 static constexpr auto ALARM_TIMEOUT = 500ms;
30 // If there are any pending callbacks, make sure they run before the Alarm
31 // object is destroyed.
32 static constexpr bool RUN_CALLBACKS_ON_EXIT = true;
34 TEST(AlarmTest, Create) {
35 std::mutex m;
37 std::vector<Alarm::TimePoint> callbacks_actual;
38 std::vector<Alarm::TimePoint> callbacks_expected;
40 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT);
42 // Create 5 alarms some time apart.
43 for (size_t i = 0; i < 5; ++i) {
44 callbacks_actual.emplace_back();
45 callbacks_expected.emplace_back(std::chrono::system_clock::now() +
46 ALARM_TIMEOUT);
48 alarm.Create([&callbacks_actual, &m, i]() {
49 std::lock_guard<std::mutex> guard(m);
50 callbacks_actual[i] = std::chrono::system_clock::now();
51 });
53 std::this_thread::sleep_for(ALARM_TIMEOUT / 5);
56 // Leave plenty of time for all the alarms to fire.
57 std::this_thread::sleep_for(TEST_TIMEOUT);
59 // Acquire the lock to check the callbacks.
60 std::lock_guard<std::mutex> guard(m);
62 // Make sure all the alarms fired around the expected time.
63 for (size_t i = 0; i < 5; ++i)
64 EXPECT_GE(callbacks_actual[i], callbacks_expected[i]);
67 TEST(AlarmTest, Exit) {
68 std::mutex m;
70 std::vector<Alarm::Handle> handles;
71 std::vector<bool> callbacks;
74 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT);
76 // Create 5 alarms.
77 for (size_t i = 0; i < 5; ++i) {
78 callbacks.emplace_back(false);
80 handles.push_back(alarm.Create([&callbacks, &m, i]() {
81 std::lock_guard<std::mutex> guard(m);
82 callbacks[i] = true;
83 }));
86 // Let the alarm go out of scope before any alarm had a chance to fire.
89 // Acquire the lock to check the callbacks.
90 std::lock_guard<std::mutex> guard(m);
92 // Make sure none of the alarms fired.
93 for (bool callback : callbacks)
94 EXPECT_TRUE(callback);
97 TEST(AlarmTest, Cancel) {
98 std::mutex m;
100 std::vector<Alarm::Handle> handles;
101 std::vector<bool> callbacks;
103 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT);
105 // Create 5 alarms.
106 for (size_t i = 0; i < 5; ++i) {
107 callbacks.emplace_back(false);
109 handles.push_back(alarm.Create([&callbacks, &m, i]() {
110 std::lock_guard<std::mutex> guard(m);
111 callbacks[i] = true;
112 }));
115 // Make sure we can cancel the first 4 alarms.
116 for (size_t i = 0; i < 4; ++i)
117 EXPECT_TRUE(alarm.Cancel(handles[i]));
119 // Leave plenty of time for all the alarms to fire.
120 std::this_thread::sleep_for(TEST_TIMEOUT);
122 // Acquire the lock to check the callbacks.
123 std::lock_guard<std::mutex> guard(m);
125 // Make sure none of the first 4 alarms fired.
126 for (size_t i = 0; i < 4; ++i)
127 EXPECT_FALSE(callbacks[i]);
129 // Make sure the fifth alarm still fired.
130 EXPECT_TRUE(callbacks[4]);
133 TEST(AlarmTest, Restart) {
134 std::mutex m;
136 std::vector<Alarm::Handle> handles;
137 std::vector<Alarm::TimePoint> callbacks_actual;
138 std::vector<Alarm::TimePoint> callbacks_expected;
140 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT);
142 // Create 5 alarms some time apart.
143 for (size_t i = 0; i < 5; ++i) {
144 callbacks_actual.emplace_back();
145 callbacks_expected.emplace_back(std::chrono::system_clock::now() +
146 ALARM_TIMEOUT);
148 handles.push_back(alarm.Create([&callbacks_actual, &m, i]() {
149 std::lock_guard<std::mutex> guard(m);
150 callbacks_actual[i] = std::chrono::system_clock::now();
151 }));
153 std::this_thread::sleep_for(ALARM_TIMEOUT / 5);
156 // Update the last 2 alarms.
157 for (size_t i = 3; i < 5; ++i) {
158 std::lock_guard<std::mutex> guard(m);
159 callbacks_expected[i] = std::chrono::system_clock::now() + ALARM_TIMEOUT;
160 EXPECT_TRUE(alarm.Restart(handles[i]));
163 // Leave plenty of time for all the alarms to fire.
164 std::this_thread::sleep_for(TEST_TIMEOUT);
166 // Acquire the lock to check the callbacks.
167 std::lock_guard<std::mutex> guard(m);
169 // Make sure all the alarms around the expected time.
170 for (size_t i = 0; i < 5; ++i)
171 EXPECT_GE(callbacks_actual[i], callbacks_expected[i]);