Index: base/threading/thread_unittest.cc |
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc |
index dfa04c6ac48fce2e445daccb4e14911bda951757..a4b360f72fec7a5d5481eec503705953870706d0 100644 |
--- a/base/threading/thread_unittest.cc |
+++ b/base/threading/thread_unittest.cc |
@@ -9,14 +9,23 @@ |
#include <vector> |
#include "base/bind.h" |
-#include "base/location.h" |
#include "base/single_thread_task_runner.h" |
#include "base/synchronization/waitable_event.h" |
#include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
+#include "base/threading/platform_thread.h" |
#include "build/build_config.h" |
#include "testing/gtest/include/gtest/gtest.h" |
#include "testing/platform_test.h" |
+// Death tests misbehave on Android. |
+// TODO(gab): Remove this when https://codereview.chromium.org/2162053006 |
+// lands. |
+#if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) |
+#define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex) |
+#else |
+#define EXPECT_DCHECK_DEATH(statement, regex) |
+#endif |
+ |
using base::Thread; |
typedef PlatformTest ThreadTest; |
@@ -164,10 +173,38 @@ TEST_F(ThreadTest, StartWithOptions_StackSize) { |
event.Wait(); |
} |
-TEST_F(ThreadTest, TwoTasks) { |
+TEST_F(ThreadTest, StartWithOptions_NonJoinable) { |
+ Thread a("StartNonJoinable"); |
+ Thread::Options options; |
+ options.joinable = false; |
+ EXPECT_TRUE(a.StartWithOptions(options)); |
+ EXPECT_TRUE(a.message_loop()); |
+ EXPECT_TRUE(a.IsRunning()); |
+ |
+ // Make the thread block until |block_event| is signaled. |
+ base::WaitableEvent block_event( |
+ base::WaitableEvent::ResetPolicy::AUTOMATIC, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ a.task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&base::WaitableEvent::Wait, base::Unretained(&block_event))); |
+ |
+ // Stop() shouldn't block despite the thread still being alive. |
+ a.Stop(); |
+ EXPECT_TRUE(a.IsRunning()); |
+ |
+ // Unblock the task and give a bit of extra time to unwind QuitWhenIdle(). |
+ block_event.Signal(); |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
+ |
+ // The thread should now have stopped on its own. |
+ EXPECT_FALSE(a.IsRunning()); |
+} |
+ |
+TEST_F(ThreadTest, TwoTasksOnJoinableThread) { |
bool was_invoked = false; |
{ |
- Thread a("TwoTasks"); |
+ Thread a("TwoTasksOnJoinableThread"); |
EXPECT_TRUE(a.Start()); |
EXPECT_TRUE(a.message_loop()); |
@@ -231,6 +268,40 @@ TEST_F(ThreadTest, StartTwice) { |
EXPECT_FALSE(a.IsRunning()); |
} |
+TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) { |
+ Thread a("StartTwiceNonJoinable"); |
+ |
+ Thread::Options options; |
+ options.joinable = false; |
+ EXPECT_TRUE(a.StartWithOptions(options)); |
+ EXPECT_TRUE(a.message_loop()); |
+ EXPECT_TRUE(a.IsRunning()); |
+ |
+ // Signaled when last task on |a| is processed. |
+ base::WaitableEvent last_task_event( |
+ base::WaitableEvent::ResetPolicy::AUTOMATIC, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ a.task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&base::WaitableEvent::Signal, |
+ base::Unretained(&last_task_event))); |
+ |
+ // Stop() is non-blocking, but Yield() to |a|, wait for last task to be |
+ // processed and a little more for QuitWhenIdle() to unwind before considering |
+ // the thread "stopped". |
+ a.Stop(); |
+ base::PlatformThread::YieldCurrentThread(); |
+ last_task_event.Wait(); |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
+ |
+ // This test assumes that the above was sufficient to let the thread fully |
+ // stop. |
+ ASSERT_FALSE(a.IsRunning()); |
+ |
+ // Restarting it should not be allowed. |
+ EXPECT_DCHECK_DEATH(a.Start(), ""); |
+} |
+ |
TEST_F(ThreadTest, ThreadName) { |
Thread a("ThreadName"); |
EXPECT_TRUE(a.Start()); |