summaryrefslogtreecommitdiff
path: root/Source/WebCore/fileapi/AsyncFileStream.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/fileapi/AsyncFileStream.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/fileapi/AsyncFileStream.cpp')
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.cpp255
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)