https://bugs.webkit.org/show_bug.cgi?id=174790
Reviewed by Brady Eidson.
Fix lifetime management issue in ResourceLoadStatisticsPersistentStorage::scheduleOrWriteMemoryStore().
WorkQueue::dispatchAfter() keeps the WorkQueue alive because its implementation keeps a strong ref to
|this|. As a result, the lambda passed to dispatchAfter(), which calls writeMemoryStoreToDisk(), can
get executed after the store is gone.
To address the issue, we now use a RunLoop::Timer to schedule the write, instead of a
WorkQueue::dispatchAfter() call. This way, we are guaranteed that the callback will not get called
after the store has been destroyed.
* UIProcess/Storage/ResourceLoadStatisticsPersistentStorage.cpp:
(WebKit::ResourceLoadStatisticsPersistentStorage::ResourceLoadStatisticsPersistentStorage):
(WebKit::ResourceLoadStatisticsPersistentStorage::asyncWriteTimerFired):
(WebKit::ResourceLoadStatisticsPersistentStorage::scheduleOrWriteMemoryStore):
(WebKit::ResourceLoadStatisticsPersistentStorage::finishAllPendingWorkSynchronously):
(WebKit::ResourceLoadStatisticsPersistentStorage::ref):
(WebKit::ResourceLoadStatisticsPersistentStorage::deref):
* UIProcess/Storage/ResourceLoadStatisticsPersistentStorage.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219845
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-07-24 Chris Dumez <cdumez@apple.com>
+
+ Fix lifetime management issue in ResourceLoadStatisticsPersistentStorage::scheduleOrWriteMemoryStore()
+ https://bugs.webkit.org/show_bug.cgi?id=174790
+
+ Reviewed by Brady Eidson.
+
+ Fix lifetime management issue in ResourceLoadStatisticsPersistentStorage::scheduleOrWriteMemoryStore().
+ WorkQueue::dispatchAfter() keeps the WorkQueue alive because its implementation keeps a strong ref to
+ |this|. As a result, the lambda passed to dispatchAfter(), which calls writeMemoryStoreToDisk(), can
+ get executed after the store is gone.
+
+ To address the issue, we now use a RunLoop::Timer to schedule the write, instead of a
+ WorkQueue::dispatchAfter() call. This way, we are guaranteed that the callback will not get called
+ after the store has been destroyed.
+
+ * UIProcess/Storage/ResourceLoadStatisticsPersistentStorage.cpp:
+ (WebKit::ResourceLoadStatisticsPersistentStorage::ResourceLoadStatisticsPersistentStorage):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::asyncWriteTimerFired):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::scheduleOrWriteMemoryStore):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::finishAllPendingWorkSynchronously):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::ref):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::deref):
+ * UIProcess/Storage/ResourceLoadStatisticsPersistentStorage.h:
+
2017-07-24 Chris Dumez <cdumez@apple.com>
Unreviewed, rolling out r219828.
ResourceLoadStatisticsPersistentStorage::ResourceLoadStatisticsPersistentStorage(WebResourceLoadStatisticsStore& store, const String& storageDirectoryPath)
: m_memoryStore(store)
, m_storageDirectoryPath(storageDirectoryPath)
+ , m_asyncWriteTimer(RunLoop::main(), this, &ResourceLoadStatisticsPersistentStorage::asyncWriteTimerFired)
{
}
m_memoryStore.grandfatherExistingWebsiteData();
}
+void ResourceLoadStatisticsPersistentStorage::asyncWriteTimerFired()
+{
+ ASSERT(RunLoop::isMain());
+ m_memoryStore.statisticsQueue().dispatch([this] () mutable {
+ writeMemoryStoreToDisk();
+ });
+}
+
void ResourceLoadStatisticsPersistentStorage::writeMemoryStoreToDisk()
{
ASSERT(!RunLoop::isMain());
if (!m_hasPendingWrite) {
m_hasPendingWrite = true;
Seconds delay = minimumWriteInterval - timeSinceLastWrite + 1_s;
- m_memoryStore.statisticsQueue().dispatchAfter(delay, [this] () mutable {
- writeMemoryStoreToDisk();
+ RunLoop::main().dispatch([this, protectedThis = makeRef(*this), delay] {
+ m_asyncWriteTimer.startOneShot(delay);
});
}
return;
void ResourceLoadStatisticsPersistentStorage::finishAllPendingWorkSynchronously()
{
+ m_asyncWriteTimer.stop();
+
BinarySemaphore semaphore;
// Make sure any pending work in our queue is finished before we terminate.
m_memoryStore.statisticsQueue().dispatch([&semaphore, this] {
semaphore.wait(WallTime::infinity());
}
+void ResourceLoadStatisticsPersistentStorage::ref()
+{
+ m_memoryStore.ref();
+}
+
+void ResourceLoadStatisticsPersistentStorage::deref()
+{
+ m_memoryStore.deref();
+}
+
#if !PLATFORM(IOS)
void ResourceLoadStatisticsPersistentStorage::excludeFromBackup() const
{
#include <wtf/Forward.h>
#include <wtf/MonotonicTime.h>
+#include <wtf/RunLoop.h>
#include <wtf/WallTime.h>
#include <wtf/text/WTFString.h>
void finishAllPendingWorkSynchronously();
+ void ref();
+ void deref();
+
private:
String storageDirectoryPath() const;
String resourceLogFilePath() const;
void populateMemoryStoreFromDisk();
void excludeFromBackup() const;
void refreshMemoryStoreFromDisk();
+ void asyncWriteTimerFired();
WebResourceLoadStatisticsStore& m_memoryStore;
const String m_storageDirectoryPath;
+ RunLoop::Timer<ResourceLoadStatisticsPersistentStorage> m_asyncWriteTimer;
std::unique_ptr<WebCore::FileMonitor> m_fileMonitor;
WallTime m_lastStatisticsFileSyncTime;
MonotonicTime m_lastStatisticsWriteTime;