Home | History | Annotate | Download | only in unittests
      1 // Copyright 2015 the V8 project 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 "src/base/atomicops.h"
      6 #include "src/base/platform/platform.h"
      7 #include "src/cancelable-task.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 namespace {
     15 
     16 class TestTask : public Task, public Cancelable {
     17  public:
     18   enum Mode { kDoNothing, kWaitTillCanceledAgain, kCheckNotRun };
     19 
     20   TestTask(CancelableTaskManager* parent, base::AtomicWord* result,
     21            Mode mode = kDoNothing)
     22       : Cancelable(parent), result_(result), mode_(mode) {}
     23 
     24   // Task overrides.
     25   void Run() final {
     26     if (TryRun()) {
     27       RunInternal();
     28     }
     29   }
     30 
     31  private:
     32   void RunInternal() {
     33     base::Release_Store(result_, id());
     34 
     35     switch (mode_) {
     36       case kWaitTillCanceledAgain:
     37         // Simple busy wait until the main thread tried to cancel.
     38         while (CancelAttempts() == 0) {
     39         }
     40         break;
     41       case kCheckNotRun:
     42         // Check that we never execute {RunInternal}.
     43         EXPECT_TRUE(false);
     44         break;
     45       default:
     46         break;
     47     }
     48   }
     49 
     50   base::AtomicWord* result_;
     51   Mode mode_;
     52 };
     53 
     54 
     55 class SequentialRunner {
     56  public:
     57   explicit SequentialRunner(TestTask* task) : task_(task) {}
     58 
     59   void Run() {
     60     task_->Run();
     61     delete task_;
     62   }
     63 
     64  private:
     65   TestTask* task_;
     66 };
     67 
     68 
     69 class ThreadedRunner final : public base::Thread {
     70  public:
     71   explicit ThreadedRunner(TestTask* task)
     72       : Thread(Options("runner thread")), task_(task) {}
     73 
     74   virtual void Run() {
     75     task_->Run();
     76     delete task_;
     77   }
     78 
     79  private:
     80   TestTask* task_;
     81 };
     82 
     83 
     84 typedef base::AtomicWord ResultType;
     85 
     86 
     87 intptr_t GetValue(ResultType* result) { return base::Acquire_Load(result); }
     88 
     89 }  // namespace
     90 
     91 
     92 TEST(CancelableTask, EmptyCancelableTaskManager) {
     93   CancelableTaskManager manager;
     94   manager.CancelAndWait();
     95 }
     96 
     97 
     98 TEST(CancelableTask, SequentialCancelAndWait) {
     99   CancelableTaskManager manager;
    100   ResultType result1 = 0;
    101   SequentialRunner runner1(
    102       new TestTask(&manager, &result1, TestTask::kCheckNotRun));
    103   EXPECT_EQ(GetValue(&result1), 0);
    104   manager.CancelAndWait();
    105   EXPECT_EQ(GetValue(&result1), 0);
    106   runner1.Run();  // Run to avoid leaking the Task.
    107   EXPECT_EQ(GetValue(&result1), 0);
    108 }
    109 
    110 
    111 TEST(CancelableTask, SequentialMultipleTasks) {
    112   CancelableTaskManager manager;
    113   ResultType result1 = 0;
    114   ResultType result2 = 0;
    115   TestTask* task1 = new TestTask(&manager, &result1);
    116   TestTask* task2 = new TestTask(&manager, &result2);
    117   SequentialRunner runner1(task1);
    118   SequentialRunner runner2(task2);
    119   EXPECT_EQ(task1->id(), 1u);
    120   EXPECT_EQ(task2->id(), 2u);
    121 
    122   EXPECT_EQ(GetValue(&result1), 0);
    123   runner1.Run();  // Don't touch task1 after running it.
    124   EXPECT_EQ(GetValue(&result1), 1);
    125 
    126   EXPECT_EQ(GetValue(&result2), 0);
    127   runner2.Run();  // Don't touch task2 after running it.
    128   EXPECT_EQ(GetValue(&result2), 2);
    129 
    130   manager.CancelAndWait();
    131   EXPECT_FALSE(manager.TryAbort(1));
    132   EXPECT_FALSE(manager.TryAbort(2));
    133 }
    134 
    135 
    136 TEST(CancelableTask, ThreadedMultipleTasksStarted) {
    137   CancelableTaskManager manager;
    138   ResultType result1 = 0;
    139   ResultType result2 = 0;
    140   TestTask* task1 =
    141       new TestTask(&manager, &result1, TestTask::kWaitTillCanceledAgain);
    142   TestTask* task2 =
    143       new TestTask(&manager, &result2, TestTask::kWaitTillCanceledAgain);
    144   ThreadedRunner runner1(task1);
    145   ThreadedRunner runner2(task2);
    146   runner1.Start();
    147   runner2.Start();
    148   // Busy wait on result to make sure both tasks are done.
    149   while ((GetValue(&result1) == 0) || (GetValue(&result2) == 0)) {
    150   }
    151   manager.CancelAndWait();
    152   runner1.Join();
    153   runner2.Join();
    154   EXPECT_EQ(GetValue(&result1), 1);
    155   EXPECT_EQ(GetValue(&result2), 2);
    156 }
    157 
    158 
    159 TEST(CancelableTask, ThreadedMultipleTasksNotRun) {
    160   CancelableTaskManager manager;
    161   ResultType result1 = 0;
    162   ResultType result2 = 0;
    163   TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
    164   TestTask* task2 = new TestTask(&manager, &result2, TestTask::kCheckNotRun);
    165   ThreadedRunner runner1(task1);
    166   ThreadedRunner runner2(task2);
    167   manager.CancelAndWait();
    168   // Tasks are canceled, hence the runner will bail out and not update result.
    169   runner1.Start();
    170   runner2.Start();
    171   runner1.Join();
    172   runner2.Join();
    173   EXPECT_EQ(GetValue(&result1), 0);
    174   EXPECT_EQ(GetValue(&result2), 0);
    175 }
    176 
    177 
    178 TEST(CancelableTask, RemoveBeforeCancelAndWait) {
    179   CancelableTaskManager manager;
    180   ResultType result1 = 0;
    181   TestTask* task1 = new TestTask(&manager, &result1, TestTask::kCheckNotRun);
    182   ThreadedRunner runner1(task1);
    183   uint32_t id = task1->id();
    184   EXPECT_EQ(id, 1u);
    185   EXPECT_TRUE(manager.TryAbort(id));
    186   runner1.Start();
    187   runner1.Join();
    188   manager.CancelAndWait();
    189   EXPECT_EQ(GetValue(&result1), 0);
    190 }
    191 
    192 
    193 TEST(CancelableTask, RemoveAfterCancelAndWait) {
    194   CancelableTaskManager manager;
    195   ResultType result1 = 0;
    196   TestTask* task1 = new TestTask(&manager, &result1);
    197   ThreadedRunner runner1(task1);
    198   uint32_t id = task1->id();
    199   EXPECT_EQ(id, 1u);
    200   runner1.Start();
    201   runner1.Join();
    202   manager.CancelAndWait();
    203   EXPECT_FALSE(manager.TryAbort(id));
    204   EXPECT_EQ(GetValue(&result1), 1);
    205 }
    206 
    207 
    208 TEST(CancelableTask, RemoveUnmanagedId) {
    209   CancelableTaskManager manager;
    210   EXPECT_FALSE(manager.TryAbort(1));
    211   EXPECT_FALSE(manager.TryAbort(2));
    212   manager.CancelAndWait();
    213   EXPECT_FALSE(manager.TryAbort(1));
    214   EXPECT_FALSE(manager.TryAbort(3));
    215 }
    216 
    217 }  // namespace internal
    218 }  // namespace v8
    219