summaryrefslogtreecommitdiff
path: root/Source/WebCore/fileapi/AsyncFileStream.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
commit41386e9cb918eed93b3f13648cbef387e371e451 (patch)
treea97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/WebCore/fileapi/AsyncFileStream.cpp
parente15dd966d523731101f70ccf768bba12435a0208 (diff)
downloadWebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/WebCore/fileapi/AsyncFileStream.cpp')
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.cpp266
1 files changed, 146 insertions, 120 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp
index 4f59aaf6f..374fac0e3 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, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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,185 +30,211 @@
*/
#include "config.h"
+
+#if ENABLE(BLOB)
+
#include "AsyncFileStream.h"
+#include "Blob.h"
#include "FileStream.h"
#include "FileStreamClient.h"
-#include "URL.h"
-#include <wtf/AutodrainedPool.h>
+#include "FileThread.h"
+#include "FileThreadTask.h"
+#include "MainThreadTask.h"
#include <wtf/MainThread.h>
-#include <wtf/MessageQueue.h>
-#include <wtf/NeverDestroyed.h>
-
-namespace WebCore {
+#include <wtf/text/WTFString.h>
-struct AsyncFileStream::Internals {
- explicit Internals(FileStreamClient&);
-
- FileStream stream;
- FileStreamClient& client;
-#if !COMPILER(MSVC)
- std::atomic_bool destroyed { false };
-#else
- std::atomic_bool destroyed;
+#if PLATFORM(IOS)
+#include "WebCoreThread.h"
#endif
-};
-inline AsyncFileStream::Internals::Internals(FileStreamClient& client)
- : client(client)
+namespace WebCore {
+
+static PassRefPtr<FileThread> createFileThread()
{
-#if COMPILER(MSVC)
- // Work around a bug that prevents the default value above from compiling.
- atomic_init(&destroyed, false);
-#endif
+ RefPtr<FileThread> thread = FileThread::create();
+ if (!thread->start())
+ return 0;
+ return thread.release();
}
-static void callOnFileThread(std::function<void()>&& function)
+static FileThread* fileThread()
{
ASSERT(isMainThread());
- ASSERT(function);
+ static FileThread* thread = createFileThread().leakRef();
+ return thread;
+}
- static NeverDestroyed<MessageQueue<std::function<void()>>> queue;
+inline AsyncFileStream::AsyncFileStream(FileStreamClient* client)
+ : m_stream(FileStream::create())
+ , m_client(client)
+{
+ ASSERT(isMainThread());
+}
- static std::once_flag createFileThreadOnce;
- std::call_once(createFileThreadOnce, [] {
- createThread("WebCore: AsyncFileStream", [] {
- for (;;) {
- AutodrainedPool pool;
+PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client)
+{
+ RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client));
- auto function = queue.get().waitForMessage();
+ // 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();
- // This can never be null because we never kill the MessageQueue.
- ASSERT(function);
+ fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread));
- // This can bever be null because we never queue a function that is null.
- ASSERT(*function);
+ return proxy.release();
+}
- (*function)();
- }
- });
- });
+AsyncFileStream::~AsyncFileStream()
+{
+}
- queue.get().append(std::make_unique<std::function<void()>>(WTF::move(function)));
+static void didStart(AsyncFileStream* proxy)
+{
+ if (proxy->client())
+ proxy->client()->didStart();
}
-AsyncFileStream::AsyncFileStream(FileStreamClient& client)
- : m_internals(std::make_unique<Internals>(client))
+void AsyncFileStream::startOnFileThread()
{
- ASSERT(isMainThread());
+ // 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));
}
-AsyncFileStream::~AsyncFileStream()
+void AsyncFileStream::stop()
{
- ASSERT(isMainThread());
+ // Clear the client so that we won't be invoking callbacks on the client.
+ setClient(0);
- // Release so that we can control the timing of deletion below.
- auto& internals = *m_internals.release();
+ fileThread()->unscheduleTasks(m_stream.get());
+ fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread));
+}
- // Set flag to prevent client callbacks and also prevent queued operations from starting.
- internals.destroyed = true;
+static void derefProxyOnMainThread(AsyncFileStream* proxy)
+{
+ ASSERT(proxy->hasOneRef());
+ proxy->deref();
+}
- // 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] {
- callOnMainThread([&internals] {
- delete &internals;
- });
- });
+void AsyncFileStream::stopOnFileThread()
+{
+ m_stream->stop();
+ callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this));
}
-void AsyncFileStream::perform(std::function<std::function<void(FileStreamClient&)>(FileStream&)> operation)
+static void didGetSize(AsyncFileStream* proxy, long long size)
{
- auto& internals = *m_internals;
- callOnFileThread([&internals, 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;
- auto mainThreadWork = operation(internals.stream);
- callOnMainThread([&internals, mainThreadWork] {
- if (internals.destroyed)
- return;
- mainThreadWork(internals.client);
- });
- });
+ if (proxy->client())
+ proxy->client()->didGetSize(size);
}
void AsyncFileStream::getSize(const String& path, double expectedModificationTime)
{
- StringCapture capturedPath(path);
- // 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([capturedPath, expectedModificationTime](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- long long size = stream.getSize(capturedPath.string(), expectedModificationTime);
- return [size](FileStreamClient& client) {
- client.didGetSize(size);
- };
- });
+ fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::getSizeOnFileThread, path, expectedModificationTime));
+}
+
+void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime)
+{
+ long long size = m_stream->getSize(path, expectedModificationTime);
+ callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size);
+}
+
+static void didOpen(AsyncFileStream* proxy, bool success)
+{
+ if (proxy->client())
+ proxy->client()->didOpen(success);
}
void AsyncFileStream::openForRead(const String& path, long long offset, long long length)
{
- StringCapture capturedPath(path);
- // FIXME: Explicit return type here is a workaround for a deficiency in the Windows compiler at the time of this writing.
- perform([capturedPath, offset, length](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- bool success = stream.openForRead(capturedPath.string(), offset, length);
- return [success](FileStreamClient& client) {
- client.didOpen(success);
- };
- });
+ 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)
{
- StringCapture capturedPath(path);
- perform([capturedPath](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- bool success = stream.openForWrite(capturedPath.string());
- return [success](FileStreamClient& client) {
- client.didOpen(success);
- };
- });
+ fileThread()->postTask(
+ createFileThreadTask(this,
+ &AsyncFileStream::openForWriteOnFileThread, path));
+}
+
+void AsyncFileStream::openForWriteOnFileThread(const String& path)
+{
+ bool success = m_stream->openForWrite(path);
+ callOnMainThread(didOpen, AllowCrossThreadAccess(this), success);
}
void AsyncFileStream::close()
{
- auto& internals = *m_internals;
- callOnFileThread([&internals] {
- internals.stream.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);
}
void AsyncFileStream::read(char* buffer, int length)
{
- perform([buffer, length](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- int bytesRead = stream.read(buffer, length);
- return [bytesRead](FileStreamClient& client) {
- client.didRead(bytesRead);
- };
- });
+ 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)
{
- URLCapture capturedURL(blobURL);
- perform([capturedURL, position, length](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- int bytesWritten = stream.write(capturedURL.url(), position, length);
- return [bytesWritten](FileStreamClient& client) {
- client.didWrite(bytesWritten);
- };
- });
+ 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)
{
- perform([position](FileStream& stream) -> std::function<void(FileStreamClient&)> {
- bool success = stream.truncate(position);
- return [success](FileStreamClient& client) {
- client.didTruncate(success);
- };
- });
+ fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::truncateOnFileThread, position));
+}
+
+void AsyncFileStream::truncateOnFileThread(long long position)
+{
+ bool success = m_stream->truncate(position);
+ callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success);
}
} // namespace WebCore
+
+#endif // ENABLE(BLOB)