diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/fileapi/AsyncFileStream.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/fileapi/AsyncFileStream.cpp')
-rw-r--r-- | Source/WebCore/fileapi/AsyncFileStream.cpp | 255 |
1 files changed, 96 insertions, 159 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp index 374fac0e3..168e4e277 100644 --- a/Source/WebCore/fileapi/AsyncFileStream.cpp +++ b/Source/WebCore/fileapi/AsyncFileStream.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -30,211 +30,148 @@ */ #include "config.h" - -#if ENABLE(BLOB) - #include "AsyncFileStream.h" -#include "Blob.h" #include "FileStream.h" #include "FileStreamClient.h" -#include "FileThread.h" -#include "FileThreadTask.h" -#include "MainThreadTask.h" +#include "URL.h" +#include <mutex> +#include <wtf/AutodrainedPool.h> +#include <wtf/Function.h> #include <wtf/MainThread.h> -#include <wtf/text/WTFString.h> - -#if PLATFORM(IOS) -#include "WebCoreThread.h" -#endif +#include <wtf/MessageQueue.h> +#include <wtf/NeverDestroyed.h> namespace WebCore { -static PassRefPtr<FileThread> createFileThread() -{ - RefPtr<FileThread> thread = FileThread::create(); - if (!thread->start()) - return 0; - return thread.release(); -} +struct AsyncFileStream::Internals { + explicit Internals(FileStreamClient&); + + FileStream stream; + FileStreamClient& client; +#if !COMPILER(MSVC) + std::atomic_bool destroyed { false }; +#else + std::atomic_bool destroyed; +#endif +}; -static FileThread* fileThread() +inline AsyncFileStream::Internals::Internals(FileStreamClient& client) + : client(client) { - ASSERT(isMainThread()); - static FileThread* thread = createFileThread().leakRef(); - return thread; +#if COMPILER(MSVC) + // Work around a bug that prevents the default value above from compiling. + atomic_init(&destroyed, false); +#endif } -inline AsyncFileStream::AsyncFileStream(FileStreamClient* client) - : m_stream(FileStream::create()) - , m_client(client) +static void callOnFileThread(Function<void ()>&& function) { ASSERT(isMainThread()); -} + ASSERT(function); -PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client) -{ - RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client)); + static NeverDestroyed<MessageQueue<Function<void ()>>> queue; - // Hold a reference so that the instance will not get deleted while there are tasks on the file thread. - // This is balanced by the deref in derefProxyOnContext below. - proxy->ref(); + static std::once_flag createFileThreadOnce; + std::call_once(createFileThreadOnce, [] { + createThread("WebCore: AsyncFileStream", [] { + for (;;) { + AutodrainedPool pool; - fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread)); + auto function = queue.get().waitForMessage(); - return proxy.release(); -} + // This can never be null because we never kill the MessageQueue. + ASSERT(function); -AsyncFileStream::~AsyncFileStream() -{ -} + // This can bever be null because we never queue a function that is null. + ASSERT(*function); -static void didStart(AsyncFileStream* proxy) -{ - if (proxy->client()) - proxy->client()->didStart(); -} + (*function)(); + } + }); + }); -void AsyncFileStream::startOnFileThread() -{ - // FIXME: It is not correct to check m_client from a secondary thread - stop() could be racing with this check. - if (!m_client) - return; - m_stream->start(); - callOnMainThread(didStart, AllowCrossThreadAccess(this)); + queue.get().append(std::make_unique<Function<void ()>>(WTFMove(function))); } -void AsyncFileStream::stop() +AsyncFileStream::AsyncFileStream(FileStreamClient& client) + : m_internals(std::make_unique<Internals>(client)) { - // Clear the client so that we won't be invoking callbacks on the client. - setClient(0); - - fileThread()->unscheduleTasks(m_stream.get()); - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread)); + ASSERT(isMainThread()); } -static void derefProxyOnMainThread(AsyncFileStream* proxy) +AsyncFileStream::~AsyncFileStream() { - ASSERT(proxy->hasOneRef()); - proxy->deref(); -} + ASSERT(isMainThread()); -void AsyncFileStream::stopOnFileThread() -{ - m_stream->stop(); - callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this)); -} + // Set flag to prevent client callbacks and also prevent queued operations from starting. + m_internals->destroyed = true; -static void didGetSize(AsyncFileStream* proxy, long long size) -{ - if (proxy->client()) - proxy->client()->didGetSize(size); + // Call through file thread and back to main thread to make sure deletion happens + // after all file thread functions and all main thread functions called from them. + callOnFileThread([internals = WTFMove(m_internals)]() mutable { + callOnMainThread([internals = WTFMove(internals)] { + }); + }); } -void AsyncFileStream::getSize(const String& path, double expectedModificationTime) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::getSizeOnFileThread, path, expectedModificationTime)); -} - -void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime) +void AsyncFileStream::perform(Function<std::function<void(FileStreamClient&)>(FileStream&)>&& operation) { - long long size = m_stream->getSize(path, expectedModificationTime); - callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size); + auto& internals = *m_internals; + callOnFileThread([&internals, operation = WTFMove(operation)] { + // Don't do the operation if stop was already called on the main thread. Note that there is + // a race here, but since skipping the operation is an optimization it's OK that we can't + // guarantee exactly which operations are skipped. Note that this is also the only reason + // we use an atomic_bool rather than just a bool for destroyed. + if (internals.destroyed) + return; + callOnMainThread([&internals, mainThreadWork = operation(internals.stream)] { + if (internals.destroyed) + return; + mainThreadWork(internals.client); + }); + }); } -static void didOpen(AsyncFileStream* proxy, bool success) +void AsyncFileStream::getSize(const String& path, double expectedModificationTime) { - if (proxy->client()) - proxy->client()->didOpen(success); + // FIXME: Explicit return type here and in all the other cases like this below is a workaround for a deficiency + // in the Windows compiler at the time of this writing. Could remove it if that is resolved. + perform([path = path.isolatedCopy(), expectedModificationTime](FileStream& stream) -> std::function<void(FileStreamClient&)> { + long long size = stream.getSize(path, expectedModificationTime); + return [size](FileStreamClient& client) { + client.didGetSize(size); + }; + }); } void AsyncFileStream::openForRead(const String& path, long long offset, long long length) { - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::openForReadOnFileThread, path, offset, length)); -} - -void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length) -{ - bool success = m_stream->openForRead(path, offset, length); - callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); -} - -void AsyncFileStream::openForWrite(const String& path) -{ - fileThread()->postTask( - createFileThreadTask(this, - &AsyncFileStream::openForWriteOnFileThread, path)); -} - -void AsyncFileStream::openForWriteOnFileThread(const String& path) -{ - bool success = m_stream->openForWrite(path); - callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); + // FIXME: Explicit return type here is a workaround for a deficiency in the Windows compiler at the time of this writing. + perform([path = path.isolatedCopy(), offset, length](FileStream& stream) -> std::function<void(FileStreamClient&)> { + bool success = stream.openForRead(path, offset, length); + return [success](FileStreamClient& client) { + client.didOpen(success); + }; + }); } void AsyncFileStream::close() { - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::closeOnFileThread)); -} - -void AsyncFileStream::closeOnFileThread() -{ - m_stream->close(); -} - -static void didRead(AsyncFileStream* proxy, int bytesRead) -{ - if (proxy->client()) - proxy->client()->didRead(bytesRead); + auto& internals = *m_internals; + callOnFileThread([&internals] { + internals.stream.close(); + }); } void AsyncFileStream::read(char* buffer, int length) { - fileThread()->postTask( - createFileThreadTask(this, &AsyncFileStream::readOnFileThread, - AllowCrossThreadAccess(buffer), length)); -} - -void AsyncFileStream::readOnFileThread(char* buffer, int length) -{ - int bytesRead = m_stream->read(buffer, length); - callOnMainThread(didRead, AllowCrossThreadAccess(this), bytesRead); -} - -static void didWrite(AsyncFileStream* proxy, int bytesWritten) -{ - if (proxy->client()) - proxy->client()->didWrite(bytesWritten); -} - -void AsyncFileStream::write(const URL& blobURL, long long position, int length) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::writeOnFileThread, blobURL, position, length)); -} - -void AsyncFileStream::writeOnFileThread(const URL& blobURL, long long position, int length) -{ - int bytesWritten = m_stream->write(blobURL, position, length); - callOnMainThread(didWrite, AllowCrossThreadAccess(this), bytesWritten); -} - -static void didTruncate(AsyncFileStream* proxy, bool success) -{ - if (proxy->client()) - proxy->client()->didTruncate(success); -} - -void AsyncFileStream::truncate(long long position) -{ - fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::truncateOnFileThread, position)); -} - -void AsyncFileStream::truncateOnFileThread(long long position) -{ - bool success = m_stream->truncate(position); - callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success); + perform([buffer, length](FileStream& stream) -> std::function<void(FileStreamClient&)> { + int bytesRead = stream.read(buffer, length); + return [bytesRead](FileStreamClient& client) { + client.didRead(bytesRead); + }; + }); } } // namespace WebCore - -#endif // ENABLE(BLOB) |