QmlDesigner: Add waitForFinished to ImageCache

Task-number: QDS-2998
Change-Id: I5ffb63b7345a17ccb499db876bb4dbb0a946ed85
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2020-11-04 13:00:17 +01:00
parent 0eb65f7211
commit c3aad50184
8 changed files with 79 additions and 12 deletions

View File

@@ -60,10 +60,7 @@ ImageCache::ImageCache(ImageCacheStorageInterface &storage,
ImageCache::~ImageCache() ImageCache::~ImageCache()
{ {
clean(); clean();
stopThread(); wait();
m_condition.notify_all();
if (m_backgroundThread.joinable())
m_backgroundThread.join();
} }
void ImageCache::request(Utils::SmallStringView name, void ImageCache::request(Utils::SmallStringView name,
@@ -88,6 +85,14 @@ void ImageCache::request(Utils::SmallStringView name,
} }
} }
void ImageCache::wait()
{
stopThread();
m_condition.notify_all();
if (m_backgroundThread.joinable())
m_backgroundThread.join();
}
void ImageCache::requestImage(Utils::PathString name, void ImageCache::requestImage(Utils::PathString name,
ImageCache::CaptureCallback captureCallback, ImageCache::CaptureCallback captureCallback,
AbortCallback abortCallback) AbortCallback abortCallback)
@@ -110,6 +115,13 @@ void ImageCache::clean()
m_generator.clean(); m_generator.clean();
} }
void ImageCache::waitForFinished()
{
wait();
m_generator.waitForFinished();
}
std::tuple<bool, ImageCache::Entry> ImageCache::getEntry() std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
{ {
std::unique_lock lock{m_mutex}; std::unique_lock lock{m_mutex};
@@ -160,7 +172,7 @@ void ImageCache::stopThread()
bool ImageCache::isRunning() bool ImageCache::isRunning()
{ {
std::unique_lock lock{m_mutex}; std::unique_lock lock{m_mutex};
return !m_finishing; return !m_finishing || m_entries.size();
} }
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -44,11 +44,7 @@ ImageCacheGenerator::ImageCacheGenerator(ImageCacheCollectorInterface &collector
ImageCacheGenerator::~ImageCacheGenerator() ImageCacheGenerator::~ImageCacheGenerator()
{ {
clean(); clean();
stopThread(); waitForFinished();
m_condition.notify_all();
if (m_backgroundThread)
m_backgroundThread->wait();
} }
void ImageCacheGenerator::generateImage(Utils::SmallStringView name, void ImageCacheGenerator::generateImage(Utils::SmallStringView name,
@@ -72,6 +68,15 @@ void ImageCacheGenerator::clean()
m_tasks.clear(); m_tasks.clear();
} }
void ImageCacheGenerator::waitForFinished()
{
stopThread();
m_condition.notify_all();
if (m_backgroundThread)
m_backgroundThread->wait();
}
void ImageCacheGenerator::startGeneration() void ImageCacheGenerator::startGeneration()
{ {
while (isRunning()) { while (isRunning()) {
@@ -82,7 +87,7 @@ void ImageCacheGenerator::startGeneration()
{ {
std::lock_guard lock{m_mutex}; std::lock_guard lock{m_mutex};
if (m_finishing) { if (m_finishing && m_tasks.empty()) {
m_storage.walCheckpointFull(); m_storage.walCheckpointFull();
return; return;
} }
@@ -129,7 +134,7 @@ void ImageCacheGenerator::stopThread()
bool ImageCacheGenerator::isRunning() bool ImageCacheGenerator::isRunning()
{ {
std::unique_lock lock{m_mutex}; std::unique_lock lock{m_mutex};
return !m_finishing; return !m_finishing || m_tasks.size();
} }
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -56,6 +56,8 @@ public:
AbortCallback &&abortCallback) override; AbortCallback &&abortCallback) override;
void clean() override; void clean() override;
void waitForFinished() override;
private: private:
struct Task struct Task
{ {

View File

@@ -45,6 +45,7 @@ public:
= 0; = 0;
virtual void clean() = 0; virtual void clean() = 0;
virtual void waitForFinished() = 0;
protected: protected:
~ImageCacheGeneratorInterface() = default; ~ImageCacheGeneratorInterface() = default;

View File

@@ -60,6 +60,7 @@ public:
AbortCallback abortCallback); AbortCallback abortCallback);
void clean(); void clean();
void waitForFinished();
private: private:
enum class RequestType { Image, Icon }; enum class RequestType { Image, Icon };
@@ -99,6 +100,9 @@ private:
ImageCacheGeneratorInterface &generator, ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider); TimeStampProviderInterface &timeStampProvider);
private:
void wait();
private: private:
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
mutable std::mutex m_mutex; mutable std::mutex m_mutex;

View File

@@ -319,4 +319,27 @@ TEST_F(ImageCache, AfterCleanNewJobsWorks)
notification.wait(); notification.wait();
} }
TEST_F(ImageCache, WaitForFinished)
{
ON_CALL(mockStorage, fetchImage(_, _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
cache.requestImage("/path/to/Component1.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
cache.requestImage("/path/to/Component2.qml",
mockCaptureCallback.AsStdFunction(),
mockAbortCallback.AsStdFunction());
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(2);
cache.waitForFinished();
}
TEST_F(ImageCache, WaitForFinishedInGenerator)
{
EXPECT_CALL(mockGenerator, waitForFinished());
cache.waitForFinished();
}
} // namespace } // namespace

View File

@@ -247,4 +247,23 @@ TEST_F(ImageCacheGenerator, CleanIsCallingAbortCallback)
waitInThread.notify(); waitInThread.notify();
} }
TEST_F(ImageCacheGenerator, WaitForFinished)
{
ON_CALL(collectorMock, start(_, _, _)).WillByDefault([&](auto, auto captureCallback, auto) {
captureCallback(QImage{image1});
});
generator.generateImage("name",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
generator.generateImage("name2",
{11},
imageCallbackMock.AsStdFunction(),
abortCallbackMock.AsStdFunction());
EXPECT_CALL(imageCallbackMock, Call(_)).Times(2);
generator.waitForFinished();
}
} // namespace } // namespace

View File

@@ -40,4 +40,5 @@ public:
AbortCallback &&abortCallback), AbortCallback &&abortCallback),
(override)); (override));
MOCK_METHOD(void, clean, (), (override)); MOCK_METHOD(void, clean, (), (override));
MOCK_METHOD(void, waitForFinished, (), (override));
}; };