Home | History | Annotate | Download | only in threading
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <stddef.h>
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/macros.h"
      9 #include "base/synchronization/waitable_event.h"
     10 #include "base/threading/platform_thread.h"
     11 #include "build/build_config.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 #if defined(OS_POSIX)
     15 #include <sys/types.h>
     16 #include <unistd.h>
     17 #elif defined(OS_WIN)
     18 #include <windows.h>
     19 #endif
     20 
     21 namespace base {
     22 
     23 // Trivial tests that thread runs and doesn't crash on create and join ---------
     24 
     25 namespace {
     26 
     27 class TrivialThread : public PlatformThread::Delegate {
     28  public:
     29   TrivialThread() : did_run_(false) {}
     30 
     31   void ThreadMain() override { did_run_ = true; }
     32 
     33   bool did_run() const { return did_run_; }
     34 
     35  private:
     36   bool did_run_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(TrivialThread);
     39 };
     40 
     41 }  // namespace
     42 
     43 TEST(PlatformThreadTest, Trivial) {
     44   TrivialThread thread;
     45   PlatformThreadHandle handle;
     46 
     47   ASSERT_FALSE(thread.did_run());
     48   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
     49   PlatformThread::Join(handle);
     50   ASSERT_TRUE(thread.did_run());
     51 }
     52 
     53 TEST(PlatformThreadTest, TrivialTimesTen) {
     54   TrivialThread thread[10];
     55   PlatformThreadHandle handle[arraysize(thread)];
     56 
     57   for (size_t n = 0; n < arraysize(thread); n++)
     58     ASSERT_FALSE(thread[n].did_run());
     59   for (size_t n = 0; n < arraysize(thread); n++)
     60     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
     61   for (size_t n = 0; n < arraysize(thread); n++)
     62     PlatformThread::Join(handle[n]);
     63   for (size_t n = 0; n < arraysize(thread); n++)
     64     ASSERT_TRUE(thread[n].did_run());
     65 }
     66 
     67 // Tests of basic thread functions ---------------------------------------------
     68 
     69 namespace {
     70 
     71 class FunctionTestThread : public PlatformThread::Delegate {
     72  public:
     73   FunctionTestThread()
     74       : thread_id_(kInvalidThreadId),
     75         termination_ready_(true, false),
     76         terminate_thread_(true, false),
     77         done_(false) {}
     78   ~FunctionTestThread() override {
     79     EXPECT_TRUE(terminate_thread_.IsSignaled())
     80         << "Need to mark thread for termination and join the underlying thread "
     81         << "before destroying a FunctionTestThread as it owns the "
     82         << "WaitableEvent blocking the underlying thread's main.";
     83   }
     84 
     85   // Grabs |thread_id_|, runs an optional test on that thread, signals
     86   // |termination_ready_|, and then waits for |terminate_thread_| to be
     87   // signaled before exiting.
     88   void ThreadMain() override {
     89     thread_id_ = PlatformThread::CurrentId();
     90     EXPECT_NE(thread_id_, kInvalidThreadId);
     91 
     92     // Make sure that the thread ID is the same across calls.
     93     EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
     94 
     95     // Run extra tests.
     96     RunTest();
     97 
     98     termination_ready_.Signal();
     99     terminate_thread_.Wait();
    100 
    101     done_ = true;
    102   }
    103 
    104   PlatformThreadId thread_id() const {
    105     EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
    106     return thread_id_;
    107   }
    108 
    109   bool IsRunning() const {
    110     return termination_ready_.IsSignaled() && !done_;
    111   }
    112 
    113   // Blocks until this thread is started and ready to be terminated.
    114   void WaitForTerminationReady() { termination_ready_.Wait(); }
    115 
    116   // Marks this thread for termination (callers must then join this thread to be
    117   // guaranteed of termination).
    118   void MarkForTermination() { terminate_thread_.Signal(); }
    119 
    120  private:
    121   // Runs an optional test on the newly created thread.
    122   virtual void RunTest() {}
    123 
    124   PlatformThreadId thread_id_;
    125 
    126   mutable WaitableEvent termination_ready_;
    127   WaitableEvent terminate_thread_;
    128   bool done_;
    129 
    130   DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
    131 };
    132 
    133 }  // namespace
    134 
    135 TEST(PlatformThreadTest, Function) {
    136   PlatformThreadId main_thread_id = PlatformThread::CurrentId();
    137 
    138   FunctionTestThread thread;
    139   PlatformThreadHandle handle;
    140 
    141   ASSERT_FALSE(thread.IsRunning());
    142   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
    143   thread.WaitForTerminationReady();
    144   ASSERT_TRUE(thread.IsRunning());
    145   EXPECT_NE(thread.thread_id(), main_thread_id);
    146 
    147   thread.MarkForTermination();
    148   PlatformThread::Join(handle);
    149   ASSERT_FALSE(thread.IsRunning());
    150 
    151   // Make sure that the thread ID is the same across calls.
    152   EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
    153 }
    154 
    155 TEST(PlatformThreadTest, FunctionTimesTen) {
    156   PlatformThreadId main_thread_id = PlatformThread::CurrentId();
    157 
    158   FunctionTestThread thread[10];
    159   PlatformThreadHandle handle[arraysize(thread)];
    160 
    161   for (size_t n = 0; n < arraysize(thread); n++)
    162     ASSERT_FALSE(thread[n].IsRunning());
    163 
    164   for (size_t n = 0; n < arraysize(thread); n++)
    165     ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
    166   for (size_t n = 0; n < arraysize(thread); n++)
    167     thread[n].WaitForTerminationReady();
    168 
    169   for (size_t n = 0; n < arraysize(thread); n++) {
    170     ASSERT_TRUE(thread[n].IsRunning());
    171     EXPECT_NE(thread[n].thread_id(), main_thread_id);
    172 
    173     // Make sure no two threads get the same ID.
    174     for (size_t i = 0; i < n; ++i) {
    175       EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
    176     }
    177   }
    178 
    179   for (size_t n = 0; n < arraysize(thread); n++)
    180     thread[n].MarkForTermination();
    181   for (size_t n = 0; n < arraysize(thread); n++)
    182     PlatformThread::Join(handle[n]);
    183   for (size_t n = 0; n < arraysize(thread); n++)
    184     ASSERT_FALSE(thread[n].IsRunning());
    185 
    186   // Make sure that the thread ID is the same across calls.
    187   EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
    188 }
    189 
    190 namespace {
    191 
    192 const ThreadPriority kThreadPriorityTestValues[] = {
    193 // The order should be higher to lower to cover as much cases as possible on
    194 // Linux trybots running without CAP_SYS_NICE permission.
    195 #if !defined(OS_ANDROID)
    196     // PlatformThread::GetCurrentThreadPriority() on Android does not support
    197     // REALTIME_AUDIO case. See http://crbug.com/505474.
    198     ThreadPriority::REALTIME_AUDIO,
    199 #endif
    200     ThreadPriority::DISPLAY,
    201     // This redundant BACKGROUND priority is to test backgrounding from other
    202     // priorities, and unbackgrounding.
    203     ThreadPriority::BACKGROUND,
    204     ThreadPriority::NORMAL,
    205     ThreadPriority::BACKGROUND};
    206 
    207 bool IsBumpingPriorityAllowed() {
    208 #if defined(OS_POSIX)
    209   // Only root can raise thread priority on POSIX environment. On Linux, users
    210   // who have CAP_SYS_NICE permission also can raise the thread priority, but
    211   // libcap.so would be needed to check the capability.
    212   return geteuid() == 0;
    213 #else
    214   return true;
    215 #endif
    216 }
    217 
    218 class ThreadPriorityTestThread : public FunctionTestThread {
    219  public:
    220   ThreadPriorityTestThread() = default;
    221   ~ThreadPriorityTestThread() override = default;
    222 
    223  private:
    224   void RunTest() override {
    225     // Confirm that the current thread's priority is as expected.
    226     EXPECT_EQ(ThreadPriority::NORMAL,
    227               PlatformThread::GetCurrentThreadPriority());
    228 
    229     // Toggle each supported priority on the current thread and confirm it
    230     // affects it.
    231     const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
    232     for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
    233       SCOPED_TRACE(i);
    234       if (!bumping_priority_allowed &&
    235           kThreadPriorityTestValues[i] >
    236               PlatformThread::GetCurrentThreadPriority()) {
    237         continue;
    238       }
    239 
    240       // Alter and verify the current thread's priority.
    241       PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
    242       EXPECT_EQ(kThreadPriorityTestValues[i],
    243                 PlatformThread::GetCurrentThreadPriority());
    244     }
    245   }
    246 
    247   DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
    248 };
    249 
    250 }  // namespace
    251 
    252 #if defined(OS_MACOSX)
    253 // PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
    254 #define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
    255 #else
    256 #define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
    257 #endif
    258 
    259 // Test changing a created thread's priority (which has different semantics on
    260 // some platforms).
    261 TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
    262   ThreadPriorityTestThread thread;
    263   PlatformThreadHandle handle;
    264 
    265   ASSERT_FALSE(thread.IsRunning());
    266   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
    267   thread.WaitForTerminationReady();
    268   ASSERT_TRUE(thread.IsRunning());
    269 
    270   thread.MarkForTermination();
    271   PlatformThread::Join(handle);
    272   ASSERT_FALSE(thread.IsRunning());
    273 }
    274 
    275 }  // namespace base
    276