replaced by .editorconfig # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D287878
154 lines
5.6 KiB
C++
154 lines
5.6 KiB
C++
/* 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 "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include "gtest/gtest-spi.h"
|
|
#include "mozilla/LazyIdleThread.h"
|
|
#include "mozilla/SharedThreadPool.h"
|
|
#include "mozilla/TaskQueue.h"
|
|
#include "nsITargetShutdownTask.h"
|
|
|
|
namespace TestTargetShutdownTask {
|
|
|
|
using namespace mozilla;
|
|
|
|
class DidRunTask final : public nsITargetShutdownTask {
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
explicit DidRunTask(nsIEventTarget* aTarget) : mTarget(aTarget) {}
|
|
|
|
void TargetShutdown() override {
|
|
mCorrect = mTarget->IsOnCurrentThread();
|
|
mRan = true;
|
|
// Dispatch something to our target, should be still allowed and run.
|
|
mDispatched = NS_SUCCEEDED(mTarget->Dispatch(NS_NewRunnableFunction(
|
|
"RunFromShutdown", [self = nsCOMPtr<DidRunTask>{this}]() {
|
|
self->mDispatchedRan = true;
|
|
})));
|
|
}
|
|
|
|
bool DidRunOnTarget() { return mRan && mCorrect; }
|
|
bool DidDispatchOnTarget() { return mDispatched && mDispatchedRan; }
|
|
|
|
private:
|
|
~DidRunTask() = default;
|
|
|
|
Atomic<bool> mRan{false};
|
|
Atomic<bool> mCorrect{false};
|
|
Atomic<bool> mDispatched{false};
|
|
Atomic<bool> mDispatchedRan{false};
|
|
nsCOMPtr<nsIEventTarget> mTarget;
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(DidRunTask, nsITargetShutdownTask)
|
|
|
|
TEST(TestTargetShutdownTask, Thread)
|
|
{
|
|
nsCOMPtr<nsIThread> thread;
|
|
nsresult rv = NS_NewNamedThread("nsIThread", getter_AddRefs(thread));
|
|
EXPECT_EQ(rv, NS_OK);
|
|
|
|
// Add two tasks, remove one, leave one for shutdown.
|
|
auto threadTask1 = MakeRefPtr<DidRunTask>(thread);
|
|
auto threadTask2 = MakeRefPtr<DidRunTask>(thread);
|
|
EXPECT_EQ(thread->RegisterShutdownTask(threadTask1), NS_OK);
|
|
EXPECT_EQ(thread->RegisterShutdownTask(threadTask2), NS_OK);
|
|
EXPECT_EQ(thread->UnregisterShutdownTask(threadTask1), NS_OK);
|
|
EXPECT_EQ(thread->UnregisterShutdownTask(threadTask1), NS_ERROR_UNEXPECTED);
|
|
|
|
thread->Shutdown();
|
|
|
|
// Register/unregister after shutdown should fail.
|
|
EXPECT_EQ(thread->RegisterShutdownTask(threadTask1), NS_ERROR_UNEXPECTED);
|
|
EXPECT_EQ(thread->UnregisterShutdownTask(threadTask2), NS_ERROR_UNEXPECTED);
|
|
|
|
// Task 1 was removed before shutdown and should not have run.
|
|
EXPECT_FALSE(threadTask1->DidRunOnTarget());
|
|
EXPECT_FALSE(threadTask1->DidDispatchOnTarget());
|
|
EXPECT_TRUE(threadTask2->DidRunOnTarget());
|
|
EXPECT_TRUE(threadTask2->DidDispatchOnTarget());
|
|
}
|
|
|
|
TEST(TestTargetShutdownTask, LazyIdleThread)
|
|
{
|
|
auto target = MakeRefPtr<LazyIdleThread>(
|
|
100, "LazyIdleThread", LazyIdleThread::ShutdownMethod::ManualShutdown);
|
|
|
|
// Add two tasks, remove one, leave one for shutdown.
|
|
auto threadTask1 = MakeRefPtr<DidRunTask>(target);
|
|
auto threadTask2 = MakeRefPtr<DidRunTask>(target);
|
|
EXPECT_EQ(target->RegisterShutdownTask(threadTask1), NS_OK);
|
|
EXPECT_EQ(target->RegisterShutdownTask(threadTask2), NS_OK);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(threadTask1), NS_OK);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(threadTask1), NS_ERROR_UNEXPECTED);
|
|
|
|
target->Shutdown();
|
|
|
|
// Register/unregister after shutdown should fail.
|
|
EXPECT_EQ(target->RegisterShutdownTask(threadTask1), NS_ERROR_UNEXPECTED);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(threadTask2), NS_ERROR_UNEXPECTED);
|
|
|
|
// Task 1 was removed before shutdown and should not have run.
|
|
EXPECT_FALSE(threadTask1->DidRunOnTarget());
|
|
EXPECT_FALSE(threadTask1->DidDispatchOnTarget());
|
|
EXPECT_TRUE(threadTask2->DidRunOnTarget());
|
|
EXPECT_TRUE(threadTask2->DidDispatchOnTarget());
|
|
}
|
|
|
|
TEST(TestTargetShutdownTask, PoolAndTaskQueue)
|
|
{
|
|
nsCOMPtr<nsIThreadPool> pool = new nsThreadPool();
|
|
|
|
// Add two tasks, remove one, leave one for shutdown.
|
|
auto poolTask1 = MakeRefPtr<DidRunTask>(pool);
|
|
auto poolTask2 = MakeRefPtr<DidRunTask>(pool);
|
|
EXPECT_EQ(pool->RegisterShutdownTask(poolTask1), NS_OK);
|
|
EXPECT_EQ(pool->RegisterShutdownTask(poolTask2), NS_OK);
|
|
EXPECT_EQ(pool->UnregisterShutdownTask(poolTask1), NS_OK);
|
|
EXPECT_EQ(pool->UnregisterShutdownTask(poolTask1), NS_ERROR_UNEXPECTED);
|
|
|
|
{
|
|
RefPtr<TaskQueue> target =
|
|
TaskQueue::Create(do_AddRef(pool), "TaskQueue", true);
|
|
|
|
// Add two tasks, remove one, leave one for shutdown.
|
|
auto queueTask1 = MakeRefPtr<DidRunTask>(target);
|
|
auto queueTask2 = MakeRefPtr<DidRunTask>(target);
|
|
EXPECT_EQ(target->RegisterShutdownTask(queueTask1), NS_OK);
|
|
EXPECT_EQ(target->RegisterShutdownTask(queueTask2), NS_OK);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(queueTask1), NS_OK);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(queueTask1), NS_ERROR_UNEXPECTED);
|
|
|
|
target->BeginShutdown();
|
|
|
|
// Register/unregister after shutdown should fail.
|
|
EXPECT_EQ(target->RegisterShutdownTask(queueTask1), NS_ERROR_UNEXPECTED);
|
|
EXPECT_EQ(target->UnregisterShutdownTask(queueTask2), NS_ERROR_UNEXPECTED);
|
|
|
|
target->AwaitShutdownAndIdle();
|
|
|
|
// Task 1 was removed before shutdown and should not have run.
|
|
EXPECT_FALSE(queueTask1->DidRunOnTarget());
|
|
EXPECT_FALSE(queueTask1->DidDispatchOnTarget());
|
|
EXPECT_TRUE(queueTask2->DidRunOnTarget());
|
|
EXPECT_TRUE(queueTask2->DidDispatchOnTarget());
|
|
}
|
|
|
|
pool->Shutdown();
|
|
|
|
// Register/unregister after shutdown should fail.
|
|
EXPECT_EQ(pool->RegisterShutdownTask(poolTask1), NS_ERROR_UNEXPECTED);
|
|
EXPECT_EQ(pool->UnregisterShutdownTask(poolTask2), NS_ERROR_UNEXPECTED);
|
|
|
|
// Task 1 was removed before shutdown and should not have run.
|
|
EXPECT_FALSE(poolTask1->DidRunOnTarget());
|
|
EXPECT_FALSE(poolTask1->DidDispatchOnTarget());
|
|
EXPECT_TRUE(poolTask2->DidRunOnTarget());
|
|
EXPECT_TRUE(poolTask2->DidDispatchOnTarget());
|
|
}
|
|
|
|
} // namespace TestTargetShutdownTask
|