xpcom/tests/gtest/TestTaskQueue.cpp
author Andrea Marchesini <amarchesini@mozilla.com>
Wed, 15 Nov 2017 07:58:02 +0100
changeset 391968 430e5be1f7bb6c2ebd991bc5e2a2222b83d2fdf2
parent 391960 7613f8e20ad525e183b9e5a237cb5725fbe3f630
child 450554 09c71a7cf75aeaf2963050e315276fb9a866fd62
permissions -rw-r--r--
Bug 1416724 - part 1 - AbstractThread::Dispatch should propage errors if failing the dispatching of Runnables, r=jwwang

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "gtest/gtest.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Unused.h"
#include "VideoUtils.h"

namespace TestTaskQueue {

using namespace mozilla;

TEST(TaskQueue, EventOrder)
{
  RefPtr<TaskQueue> tq1 =
    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), true);
  RefPtr<TaskQueue> tq2 =
    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), true);
  RefPtr<TaskQueue> tq3 =
    new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK), true);

  bool errored = false;
  int counter = 0;
  int sync = 0;
  Monitor monitor("TaskQueue::EventOrder::monitor");

  // We expect task1 happens before task3.
  for (int i = 0; i < 10000; ++i) {
    Unused << tq1->Dispatch(
      NS_NewRunnableFunction(
        "TestTaskQueue::TaskQueue_EventOrder_Test::TestBody",
        [&]() {
          Unused << tq2->Dispatch(NS_NewRunnableFunction(
            "TestTaskQueue::TaskQueue_EventOrder_Test::TestBody",
            []() { // task0
            }));
          Unused << tq3->Dispatch(NS_NewRunnableFunction(
            "TestTaskQueue::TaskQueue_EventOrder_Test::TestBody",
            [&]() { // task1
              EXPECT_EQ(1, ++counter);
              errored = counter != 1;
              MonitorAutoLock mon(monitor);
              ++sync;
              mon.Notify();
            }));
          Unused << tq2->Dispatch(NS_NewRunnableFunction(
            "TestTaskQueue::TaskQueue_EventOrder_Test::TestBody",
            [&]() { // task2
              Unused << tq3->Dispatch(NS_NewRunnableFunction(
                "TestTaskQueue::TaskQueue_EventOrder_Test::TestBody",
                [&]() { // task3
                  EXPECT_EQ(0, --counter);
                  errored = counter != 0;
                  MonitorAutoLock mon(monitor);
                  ++sync;
                  mon.Notify();
                }));
            }));
        }),
      AbstractThread::TailDispatch);

    // Ensure task1 and task3 are done before next loop.
    MonitorAutoLock mon(monitor);
    while (sync != 2) {
      mon.Wait();
    }
    sync = 0;

    if (errored) {
      break;
    }
  }

  tq1->BeginShutdown();
  tq1->AwaitShutdownAndIdle();
  tq2->BeginShutdown();
  tq2->AwaitShutdownAndIdle();
  tq3->BeginShutdown();
  tq3->AwaitShutdownAndIdle();
}

} // namespace TestTaskQueue