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 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Host/Alarm.h" 10 #include "gtest/gtest.h" 11 12 #include <chrono> 13 #include <thread> 14 15 using namespace lldb_private; 16 using namespace std::chrono_literals; 17 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 25 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; 29 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; 33 34 TEST(AlarmTest, Create) { 35 std::mutex m; 36 37 std::vector<Alarm::TimePoint> callbacks_actual; 38 std::vector<Alarm::TimePoint> callbacks_expected; 39 40 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); 41 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); 47 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 }); 52 53 std::this_thread::sleep_for(ALARM_TIMEOUT / 5); 54 } 55 56 // Leave plenty of time for all the alarms to fire. 57 std::this_thread::sleep_for(TEST_TIMEOUT); 58 59 // Acquire the lock to check the callbacks. 60 std::lock_guard<std::mutex> guard(m); 61 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]); 65 } 66 67 TEST(AlarmTest, Exit) { 68 std::mutex m; 69 70 std::vector<Alarm::Handle> handles; 71 std::vector<bool> callbacks; 72 73 { 74 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); 75 76 // Create 5 alarms. 77 for (size_t i = 0; i < 5; ++i) { 78 callbacks.emplace_back(false); 79 80 handles.push_back(alarm.Create([&callbacks, &m, i]() { 81 std::lock_guard<std::mutex> guard(m); 82 callbacks[i] = true; 83 })); 84 } 85 86 // Let the alarm go out of scope before any alarm had a chance to fire. 87 } 88 89 // Acquire the lock to check the callbacks. 90 std::lock_guard<std::mutex> guard(m); 91 92 // Make sure none of the alarms fired. 93 for (bool callback : callbacks) 94 EXPECT_TRUE(callback); 95 } 96 97 TEST(AlarmTest, Cancel) { 98 std::mutex m; 99 100 std::vector<Alarm::Handle> handles; 101 std::vector<bool> callbacks; 102 103 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); 104 105 // Create 5 alarms. 106 for (size_t i = 0; i < 5; ++i) { 107 callbacks.emplace_back(false); 108 109 handles.push_back(alarm.Create([&callbacks, &m, i]() { 110 std::lock_guard<std::mutex> guard(m); 111 callbacks[i] = true; 112 })); 113 } 114 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])); 118 119 // Leave plenty of time for all the alarms to fire. 120 std::this_thread::sleep_for(TEST_TIMEOUT); 121 122 // Acquire the lock to check the callbacks. 123 std::lock_guard<std::mutex> guard(m); 124 125 // Make sure none of the first 4 alarms fired. 126 for (size_t i = 0; i < 4; ++i) 127 EXPECT_FALSE(callbacks[i]); 128 129 // Make sure the fifth alarm still fired. 130 EXPECT_TRUE(callbacks[4]); 131 } 132 133 TEST(AlarmTest, Restart) { 134 std::mutex m; 135 136 std::vector<Alarm::Handle> handles; 137 std::vector<Alarm::TimePoint> callbacks_actual; 138 std::vector<Alarm::TimePoint> callbacks_expected; 139 140 Alarm alarm(ALARM_TIMEOUT, RUN_CALLBACKS_ON_EXIT); 141 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); 147 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 })); 152 153 std::this_thread::sleep_for(ALARM_TIMEOUT / 5); 154 } 155 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])); 161 } 162 163 // Leave plenty of time for all the alarms to fire. 164 std::this_thread::sleep_for(TEST_TIMEOUT); 165 166 // Acquire the lock to check the callbacks. 167 std::lock_guard<std::mutex> guard(m); 168 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]); 172 } 173