[libcxx] r228783 - libc++ tests: wait_until.pass test sporadically fails (bug 21998)

Eric Fiselier eric at efcs.ca
Tue Feb 10 17:25:57 PST 2015


Author: ericwf
Date: Tue Feb 10 19:25:57 2015
New Revision: 228783

URL: http://llvm.org/viewvc/llvm-project?rev=228783&view=rev
Log:
libc++ tests: wait_until.pass test sporadically fails (bug 21998)

Summary:
Hello Howard,

While running the libc++ tests on our ARM boards, we encounter sporadic failures of the two tests:
test/std/thread/futures/futures.shared_future/wait_until.pass.cpp
test/std/thread/futures/futures.unique_future/wait_until.pass.cpp

The worker thread might not finish yet when the main thread checks its result.
I filed the bug 21998 for this case: http://llvm.org/bugs/show_bug.cgi?id=21998

Would you be able to review this please?
Thank you.
Oleg

Reviewers: howard.hinnant, mclow.lists, danalbert, jroelofs, EricWF

Reviewed By: jroelofs, EricWF

Subscribers: EricWF, mclow.lists, aemerson, llvm-commits

Differential Revision: http://reviews.llvm.org/D6750

Modified:
    libcxx/trunk/test/std/thread/futures/futures.shared_future/wait_until.pass.cpp
    libcxx/trunk/test/std/thread/futures/futures.unique_future/wait_until.pass.cpp

Modified: libcxx/trunk/test/std/thread/futures/futures.shared_future/wait_until.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/futures/futures.shared_future/wait_until.pass.cpp?rev=228783&r1=228782&r2=228783&view=diff
==============================================================================
--- libcxx/trunk/test/std/thread/futures/futures.shared_future/wait_until.pass.cpp (original)
+++ libcxx/trunk/test/std/thread/futures/futures.shared_future/wait_until.pass.cpp Tue Feb 10 19:25:57 2015
@@ -1,97 +1,129 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-
-// <future>
-
-// class shared_future<R>
-
-// template <class Clock, class Duration>
-//   future_status
-//   wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
-
-#include <future>
-#include <cassert>
-
-typedef std::chrono::milliseconds ms;
-
-void func1(std::promise<int> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    p.set_value(3);
-}
-
-int j = 0;
-
-void func3(std::promise<int&> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    j = 5;
-    p.set_value(j);
-}
-
-void func5(std::promise<void> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    p.set_value();
-}
-
-int main()
-{
-    typedef std::chrono::high_resolution_clock Clock;
-    {
-        typedef int T;
-        std::promise<T> p;
-        std::shared_future<T> f = p.get_future();
-        std::thread(func1, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-    {
-        typedef int& T;
-        std::promise<T> p;
-        std::shared_future<T> f = p.get_future();
-        std::thread(func3, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-    {
-        typedef void T;
-        std::promise<T> p;
-        std::shared_future<T> f = p.get_future();
-        std::thread(func5, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-}
+ //===----------------------------------------------------------------------===//
+ //
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file is dual licensed under the MIT and the University of Illinois Open
+ // Source Licenses. See LICENSE.TXT for details.
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // UNSUPPORTED: libcpp-has-no-threads
+
+ // <future>
+
+ // class shared_future<R>
+
+ // template <class Clock, class Duration>
+ //   future_status
+ //   wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
+
+ #include <future>
+ #include <atomic>
+ #include <cassert>
+
+ enum class WorkerThreadState { Uninitialized, AllowedToRun, Exiting };
+ typedef std::chrono::milliseconds ms;
+
+ std::atomic<WorkerThreadState> thread_state(WorkerThreadState::Uninitialized);
+
+ void set_worker_thread_state(WorkerThreadState state)
+ {
+     thread_state.store(state, std::memory_order_relaxed);
+ }
+
+ void wait_for_worker_thread_state(WorkerThreadState state)
+ {
+     while (thread_state.load(std::memory_order_relaxed) != state);
+ }
+
+ void func1(std::promise<int> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     p.set_value(3);
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ int j = 0;
+
+ void func3(std::promise<int&> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     j = 5;
+     p.set_value(j);
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ void func5(std::promise<void> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     p.set_value();
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ int main()
+ {
+     typedef std::chrono::high_resolution_clock Clock;
+     {
+         typedef int T;
+         std::promise<T> p;
+         std::shared_future<T> f = p.get_future();
+         std::thread(func1, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+     {
+         typedef int& T;
+         std::promise<T> p;
+         std::shared_future<T> f = p.get_future();
+         std::thread(func3, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+     {
+         typedef void T;
+         std::promise<T> p;
+         std::shared_future<T> f = p.get_future();
+         std::thread(func5, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+ }

Modified: libcxx/trunk/test/std/thread/futures/futures.unique_future/wait_until.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/thread/futures/futures.unique_future/wait_until.pass.cpp?rev=228783&r1=228782&r2=228783&view=diff
==============================================================================
--- libcxx/trunk/test/std/thread/futures/futures.unique_future/wait_until.pass.cpp (original)
+++ libcxx/trunk/test/std/thread/futures/futures.unique_future/wait_until.pass.cpp Tue Feb 10 19:25:57 2015
@@ -1,97 +1,129 @@
-//===----------------------------------------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: libcpp-has-no-threads
-
-// <future>
-
-// class future<R>
-
-// template <class Clock, class Duration>
-//   future_status
-//   wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
-
-#include <future>
-#include <cassert>
-
-typedef std::chrono::milliseconds ms;
-
-void func1(std::promise<int> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    p.set_value(3);
-}
-
-int j = 0;
-
-void func3(std::promise<int&> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    j = 5;
-    p.set_value(j);
-}
-
-void func5(std::promise<void> p)
-{
-    std::this_thread::sleep_for(ms(500));
-    p.set_value();
-}
-
-int main()
-{
-    typedef std::chrono::high_resolution_clock Clock;
-    {
-        typedef int T;
-        std::promise<T> p;
-        std::future<T> f = p.get_future();
-        std::thread(func1, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-    {
-        typedef int& T;
-        std::promise<T> p;
-        std::future<T> f = p.get_future();
-        std::thread(func3, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-    {
-        typedef void T;
-        std::promise<T> p;
-        std::future<T> f = p.get_future();
-        std::thread(func5, std::move(p)).detach();
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout);
-        assert(f.valid());
-        assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready);
-        assert(f.valid());
-        Clock::time_point t0 = Clock::now();
-        f.wait();
-        Clock::time_point t1 = Clock::now();
-        assert(f.valid());
-        assert(t1-t0 < ms(5));
-    }
-}
+ //===----------------------------------------------------------------------===//
+ //
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file is dual licensed under the MIT and the University of Illinois Open
+ // Source Licenses. See LICENSE.TXT for details.
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // UNSUPPORTED: libcpp-has-no-threads
+
+ // <future>
+
+ // class future<R>
+
+ // template <class Clock, class Duration>
+ //   future_status
+ //   wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
+
+ #include <future>
+ #include <atomic>
+ #include <cassert>
+
+ enum class WorkerThreadState { Uninitialized, AllowedToRun, Exiting };
+ typedef std::chrono::milliseconds ms;
+
+ std::atomic<WorkerThreadState> thread_state(WorkerThreadState::Uninitialized);
+
+ void set_worker_thread_state(WorkerThreadState state)
+ {
+     thread_state.store(state, std::memory_order_relaxed);
+ }
+
+ void wait_for_worker_thread_state(WorkerThreadState state)
+ {
+     while (thread_state.load(std::memory_order_relaxed) != state);
+ }
+
+ void func1(std::promise<int> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     p.set_value(3);
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ int j = 0;
+
+ void func3(std::promise<int&> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     j = 5;
+     p.set_value(j);
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ void func5(std::promise<void> p)
+ {
+     wait_for_worker_thread_state(WorkerThreadState::AllowedToRun);
+     p.set_value();
+     set_worker_thread_state(WorkerThreadState::Exiting);
+ }
+
+ int main()
+ {
+     typedef std::chrono::high_resolution_clock Clock;
+     {
+         typedef int T;
+         std::promise<T> p;
+         std::future<T> f = p.get_future();
+         std::thread(func1, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+     {
+         typedef int& T;
+         std::promise<T> p;
+         std::future<T> f = p.get_future();
+         std::thread(func3, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+     {
+         typedef void T;
+         std::promise<T> p;
+         std::future<T> f = p.get_future();
+         std::thread(func5, std::move(p)).detach();
+         assert(f.valid());
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::timeout);
+         assert(f.valid());
+
+         // allow the worker thread to produce the result and wait until the worker is done
+         set_worker_thread_state(WorkerThreadState::AllowedToRun);
+         wait_for_worker_thread_state(WorkerThreadState::Exiting);
+
+         assert(f.wait_until(Clock::now() + ms(10)) == std::future_status::ready);
+         assert(f.valid());
+         Clock::time_point t0 = Clock::now();
+         f.wait();
+         Clock::time_point t1 = Clock::now();
+         assert(f.valid());
+         assert(t1-t0 < ms(5));
+     }
+ }





More information about the cfe-commits mailing list