From b0bfe970752e84493e2e79c7244372dad32c29cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodor=20Sp=C3=A6ren?= Date: Sun, 14 Apr 2024 22:08:38 +0200 Subject: [PATCH 4/4] Add tests for atomic integral --- .../atomic_integral/extended_wait.cc | 656 ++++++++++++++++++ 1 file changed, 656 insertions(+) create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/extended_wait.cc diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/extended_wait.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/extended_wait.cc new file mode 100644 index 00000000000..6b91440f8bd --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/extended_wait.cc @@ -0,0 +1,656 @@ +#include +#include +#include + +// { dg-do run { target c++20 } } +// { dg-require-gthreads "" } +// { dg-add-options libatomic } +// { dg-additional-options "-pthread" { target pthread } } + +// Copyright (C) 2020-2024 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include + +struct Timer +{ + std::chrono::steady_clock::time_point start{ + std::chrono::steady_clock::now() + }; + + [[nodiscard]] auto + duration() const + { + return std::chrono::steady_clock::now() - start; + } +}; + + +template +void check() +{ + using namespace std::chrono_literals; + + inline constexpr auto ms_buffer = 60ms; + + // Wait value should return immidiatly when it has the right value + { + const Timer t; + std::atomic wow = 34; + const auto next = wow.wait_value(100); + VERIFY(next == 34); + VERIFY(t.duration() < 1ms); + } + + // "Wait value should wait until notified atleast" + { + std::atomic wow = 34; + const Timer t; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102, std::memory_order::release); + wow.notify_all(); + }); + + auto res = wow.wait_value(34); + VERIFY(res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < ms_buffer); + } + + // "Wait value should not return on unchanged value." + { + const Timer t; + std::atomic wow = 34; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + std::this_thread::sleep_for(40ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_value(34); + const auto dur = t.duration(); + VERIFY(res == 102); + VERIFY(60ms <= dur); + VERIFY(dur < ms_buffer); + } + + // "try wait should return right away when it's correct + { + const Timer t; + std::atomic wow = 34; + auto res = wow.try_wait(100); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // "try wait should return after a little while when it's not correct + { + const Timer t; + std::atomic wow = 34; + auto res = wow.try_wait(34); + VERIFY(!res); + VERIFY(t.duration() < 100ms); + } + + // "WaitFor: No waiting if it's good + { + const Timer t; + std::atomic wow = 34; + auto res = wow.wait_for(100, 10s); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // "WaitFor: Max waiting if it doesn't change + { + const Timer t; + std::atomic wow = 34; + auto res = wow.wait_for(34, 50ms); + VERIFY(!res); + VERIFY(t.duration() < 60ms); + VERIFY(50ms <= t.duration()); + } + + // "WaitFor: Will wakeup if changed. + { + const Timer t; + std::atomic wow = 34; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_for(34, 5s); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < 70ms); + } + + // "WaitFor: Will not return if value is changed to same value. + { + const Timer t; + std::atomic wow = 34; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_for(34, 50ms); + auto taken = t.duration(); + VERIFY(!res); + VERIFY(50ms <= taken); + VERIFY(taken < 100ms); + } + + // "WaitUntil: Will return right away if the value is the same. + { + std::atomic wow = 34; + + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until(102, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(finished <= deadLine); + } + + // "WaitUntil: Will not return before deadline, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until(34, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadLine <= finished); + VERIFY(finished < deadLine + 40ms); + } + + // "WaitUntil: Will return if changed, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(102); + wow.notify_all(); + }); + auto res = wow.wait_until(34, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(finished < deadLine); + } + + // "WaitUntil: Will not return if not changed, if not hit + { + std::atomic wow = 34; + const auto deadline = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_until(34, deadline); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadline <= finished); + VERIFY(finished < deadline + 40ms); + } + + // "Wait value should return immidiatly when it has the right value + { + std::atomic wow = 34; + const Timer t; + const auto next = wow.wait_value(100); + VERIFY(next == 34); + VERIFY(t.duration() < 1ms); + } + + // "Wait value should wait until notified atleast + { + std::atomic wow = 34; + const Timer t; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102, std::memory_order::release); + wow.notify_all(); + }); + + auto res = wow.wait_value(34); + VERIFY(res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < 60ms); + } + + // "Wait value should not return on unchanged value. + { + std::atomic wow = 34; + const Timer t; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + std::this_thread::sleep_for(40ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_value(34); + const auto dur = t.duration(); + VERIFY(res == 102); + VERIFY(60ms <= dur); + VERIFY(dur < 70ms); + } + + // "try wait should return right away when it's correct + { + std::atomic wow = 34; + const Timer t; + auto res = wow.try_wait(100); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // "try wait should return after a little while when it's not correct + { + std::atomic wow = 34; + const Timer t; + auto res = wow.try_wait(34); + VERIFY(!res); + VERIFY(t.duration() < 100ms); + } + + // "WaitFor: No waiting if it's good + { + std::atomic wow = 34; + const Timer t; + auto res = wow.wait_for(100, 10s); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // "WaitFor: Max waiting if it doesn't change + { + std::atomic wow = 34; + const Timer t; + auto res = wow.wait_for(34, 50ms); + VERIFY(!res); + VERIFY(t.duration() < 60ms); + VERIFY(50ms <= t.duration()); + } + + // "WaitFor: Will wakeup if changed. + { + std::atomic wow = 34; + const Timer t; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_for(34, 5s); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < 70ms); + } + + // "WaitFor: Will not return if value is changed to same value. + { + std::atomic wow = 34; + const Timer t; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_for(34, 50ms); + auto taken = t.duration(); + VERIFY(!res); + VERIFY(50ms <= taken); + VERIFY(taken < 100ms); + } + + // "WaitUntil: Will return right away if the value is the same. + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until(102, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(finished <= deadLine); + } + + // "WaitUntil: Will not return before deadline, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until(34, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadLine <= finished); + VERIFY(finished < deadLine + 40ms); + } + + // "WaitUntil: Will return if changed, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(102); + wow.notify_all(); + }); + auto res = wow.wait_until(34, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(finished < deadLine); + } + + // "WaitUntil: Will not return if not changed, if not hit + { + std::atomic wow = 34; + const auto deadline = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_until(34, deadline); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadline <= finished); + VERIFY(finished < deadline + 40ms); + } + + // Predicate api + + + // Wait predicate should return immidiatly when it has the right value + { + std::atomic wow = 34; + const Timer t; + const auto next + = wow.wait_with_predicate([](const auto in) { return in < 40; }); + VERIFY(next == 34); + VERIFY(t.duration() < 1ms); + } + + // "Wait predicate should wait until notified atleast + { + std::atomic wow = 34; + const Timer t; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102, std::memory_order::release); + wow.notify_all(); + }); + + auto res = wow.wait_with_predicate([](const auto in) { return 100 < in; }); + VERIFY(res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < 60ms); + } + + // "Wait predicate should not return on unchanged value. + { + std::atomic wow = 34; + + const Timer t; + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + std::this_thread::sleep_for(40ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_with_predicate([](const auto in) { return in != 34; }); + const auto dur = t.duration(); + VERIFY(res == 102); + VERIFY(60ms <= dur); + VERIFY(dur < 70ms); + } + + // "try wait predicate should return right away when it's correct + { + std::atomic wow = 34; + const Timer t; + auto res + = wow.try_wait_with_predicate([](const auto in) { return in != 100; }); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // "try wait predicate should return after a little while when it's not correct + { + std::atomic wow = 34; + const Timer t; + auto res + = wow.try_wait_with_predicate([](const auto in) { return in != 34; }); + VERIFY(!res); + VERIFY(t.duration() < 100ms); + } + + // WaitFor predicate : No waiting if it's good + { + std::atomic wow = 34; + const Timer t; + auto res = wow.wait_for_with_predicate( + [](const auto in) { return in != 100; }, 10s); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(t.duration() < 1ms); + } + + // WaitFor predicate : Max waiting if it doesn't change + { + std::atomic wow = 34; + const Timer t; + auto res = wow.wait_for_with_predicate( + [](const auto in) { return 50 < in; }, 50ms); + VERIFY(!res); + VERIFY(t.duration() < 60ms); + VERIFY(50ms <= t.duration()); + } + + // WaitFor predicate : Will wakeup if changed. + { + std::atomic wow = 34; + const Timer t; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(50ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_for_with_predicate( + [](const auto in) { return 100 < in; }, 5s); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(50ms <= t.duration()); + VERIFY(t.duration() < 70ms); + } + + // WaitFor predicate : Will not return if value is changed to same value. + { + std::atomic wow = 34; + const Timer t; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_for_with_predicate( + [](const auto in) { return in < 30; }, 50ms); + auto taken = t.duration(); + VERIFY(!res); + VERIFY(50ms <= taken); + VERIFY(taken < 100ms); + } + + // WaitUntil predicate : Will return right away if the value is the same. + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until_with_predicate( + [](const auto in) { return in != 102; }, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 34); + VERIFY(finished <= deadLine); + } + + // WaitUntil predicate : Will not return before deadline, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + auto res = wow.wait_until_with_predicate([](const auto in) + { + return 40 < in; + }, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadLine <= finished); + VERIFY(finished < deadLine + 40ms); + } + + // WaitUntil predicate: Will return if changed, if not hit + { + std::atomic wow = 34; + const auto deadLine = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + std::this_thread::sleep_for(20ms); + wow.store(102); + wow.notify_all(); + }); + + auto res = wow.wait_until_with_predicate([](const auto in) + { + return 100 < in; + }, deadLine); + const auto finished = std::chrono::system_clock::now(); + VERIFY(res); + VERIFY(*res == 102); + VERIFY(finished < deadLine); + } + + // WaitUntil predicate: Will not return if not changed, if not hit + { + std::atomic wow = 34; + const auto deadline = std::chrono::system_clock::now() + 100ms; + + std::jthread outThere([&wow]() { + for (int i = 0; i < 2; i++) + { + std::this_thread::sleep_for(20ms); + wow.store(34); + wow.notify_all(); + } + }); + + auto res = wow.wait_until_with_predicate([](const auto in) + { + return 40 < in; + }, deadline); + const auto finished = std::chrono::system_clock::now(); + VERIFY(!res); + VERIFY(deadline <= finished); + VERIFY(finished < deadline + ms_buffer); + } + +} + + +int +main () +{ + // check bb; + check(); + check(); + check(); + check(); + check(); + check(); + check(); + check(); + check(); + check(); + check(); + + check(); + check(); + check(); + check(); + + check(); + check(); + check(); + check(); + + check(); + check(); + check(); + check(); + return 0; +} -- 2.44.0