-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
/cc @jonahwilliams
Starting at flutter/engine#45474 (flutter/engine@8d07c29), the ResourceManagerVK's spawn thread never terminates:
In practice, this doesn't (?) impact applications, because there is only a single instance per ContextVK, and the app eventually exits. It does impact unit testing, but we don't have much that spawns enough threads to notice the impact.
Here is a simple reproduction case using @gaaclarke's CreateMockVulkanContext():
$ ninja -j1000 -C ../out/host_debug_impeller_vulkan impeller_unittests && ../out/host_debug_impeller_vulkan/impeller_unittests --gtest_filter="MockVulkanContextTest.*" --gtest_repeat=10000Note the --gtest_repeat=10000, because that (on my PC) is the magnitude required where threads are no longer created and the test runner crashes (around 4k or so), I didn't see the problem originally when running at --gtest_repeat=1000.
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/testing.h" // IWYU pragma: keep
#include "gtest/gtest.h"
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
namespace impeller {
namespace testing {
TEST(MockVulkanContextTest, IsThreadSafe) {
// In a typical app, there is a single ContextVK per app, shared b/w threads.
//
// This test ensures that the (mock) ContextVK is thread-safe.
auto const context = CreateMockVulkanContext();
// Spawn two threads, and have them create a CommandPoolVK each.
std::thread thread1([&context]() {
auto const pool = CommandPoolVK::GetThreadLocal(context.get());
EXPECT_TRUE(pool);
});
std::thread thread2([&context]() {
auto const pool = CommandPoolVK::GetThreadLocal(context.get());
EXPECT_TRUE(pool);
});
thread1.join();
thread2.join();
context->Shutdown();
}
} // namespace testing
} // namespace impellerIt's likely the cause is this self-closure:
std::shared_ptr<ResourceManagerVK> ResourceManagerVK::Create() {
auto manager = std::shared_ptr<ResourceManagerVK>(new ResourceManagerVK());
manager->waiter_ = std::thread([manager]() { manager->Start(); });
manager->waiter_.detach();
return manager;
}I'm investigating, and if we can't find a fix, or it's causing other problems, we'll revert.
