ThreadableBlobRegistry.cpp [plain text]
#include "config.h"
#include "ThreadableBlobRegistry.h"
#include "BlobDataFileReference.h"
#include "BlobPart.h"
#include "BlobRegistry.h"
#include "BlobURL.h"
#include "SecurityOrigin.h"
#include <mutex>
#include <wtf/CrossThreadQueue.h>
#include <wtf/CrossThreadTask.h>
#include <wtf/HashMap.h>
#include <wtf/MainThread.h>
#include <wtf/MessageQueue.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/text/StringHash.h>
#include <wtf/threads/BinarySemaphore.h>
using WTF::ThreadSpecific;
namespace WebCore {
typedef HashMap<String, RefPtr<SecurityOrigin>> BlobUrlOriginMap;
static ThreadSpecific<BlobUrlOriginMap>& originMap()
{
static std::once_flag onceFlag;
static ThreadSpecific<BlobUrlOriginMap>* map;
std::call_once(onceFlag, []{
map = new ThreadSpecific<BlobUrlOriginMap>;
});
return *map;
}
static void postToMainThread(CrossThreadTask&& task)
{
static std::once_flag onceFlag;
static CrossThreadQueue<CrossThreadTask>* queue;
std::call_once(onceFlag, [] {
queue = new CrossThreadQueue<CrossThreadTask>;
});
queue->append(WTFMove(task));
callOnMainThread([] {
auto task = queue->tryGetMessage();
ASSERT(task);
task->performTask();
});
}
void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
{
if (isMainThread())
blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
else {
callOnMainThread([url = url.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] {
blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
});
}
}
void ThreadableBlobRegistry::registerBlobURL(const URL& url, Vector<BlobPart> blobParts, const String& contentType)
{
if (isMainThread())
blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
else {
for (auto& part : blobParts)
part.detachFromCurrentThread();
callOnMainThread([url = url.isolatedCopy(), blobParts = WTFMove(blobParts), contentType = contentType.isolatedCopy()]() mutable {
blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
});
}
}
void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& url, const URL& srcURL)
{
if (origin && BlobURL::getOrigin(url) == "null")
originMap()->add(url.string(), origin);
if (isMainThread())
blobRegistry().registerBlobURL(url, srcURL);
else {
callOnMainThread([url = url.isolatedCopy(), srcURL = srcURL.isolatedCopy()] {
blobRegistry().registerBlobURL(url, srcURL);
});
}
}
void ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType)
{
if (isMainThread())
blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReference::create(fileBackedPath), contentType);
else
postToMainThread(createCrossThreadTask(ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked, url, srcURL, fileBackedPath, contentType));
}
void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end)
{
if (isMainThread())
blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
else {
callOnMainThread([newURL = newURL.isolatedCopy(), srcURL = srcURL.isolatedCopy(), start, end] {
blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
});
}
}
unsigned long long ThreadableBlobRegistry::blobSize(const URL& url)
{
unsigned long long resultSize;
if (isMainThread())
resultSize = blobRegistry().blobSize(url);
else {
BinarySemaphore semaphore;
callOnMainThread([url = url.isolatedCopy(), &semaphore, &resultSize] {
resultSize = blobRegistry().blobSize(url);
semaphore.signal();
});
semaphore.wait(std::numeric_limits<double>::max());
}
return resultSize;
}
void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
{
if (BlobURL::getOrigin(url) == "null")
originMap()->remove(url.string());
if (isMainThread())
blobRegistry().unregisterBlobURL(url);
else {
callOnMainThread([url = url.isolatedCopy()] {
blobRegistry().unregisterBlobURL(url);
});
}
}
RefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
{
return originMap()->get(url.string());
}
}