1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33 34#include "AsyncFileStream.h" 35 36#include "Blob.h" 37#include "FileStream.h" 38#include "FileStreamClient.h" 39#include "FileThread.h" 40#include <wtf/MainThread.h> 41#include <wtf/text/WTFString.h> 42 43#if PLATFORM(IOS) 44#include "WebCoreThread.h" 45#endif 46 47namespace WebCore { 48 49static PassRefPtr<FileThread> createFileThread() 50{ 51 RefPtr<FileThread> thread = FileThread::create(); 52 if (!thread->start()) 53 return 0; 54 return thread.release(); 55} 56 57static FileThread* fileThread() 58{ 59 ASSERT(isMainThread()); 60 static FileThread* thread = createFileThread().leakRef(); 61 return thread; 62} 63 64inline AsyncFileStream::AsyncFileStream(FileStreamClient* client) 65 : m_stream(FileStream::create()) 66 , m_client(client) 67{ 68 ASSERT(isMainThread()); 69} 70 71PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client) 72{ 73 RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client)); 74 75 // Hold a reference so that the instance will not get deleted while there are tasks on the file thread. 76 // This is balanced by the deref in derefProxyOnContext below. 77 proxy->ref(); 78 79 AsyncFileStream* proxyPtr = proxy.get(); 80 fileThread()->postTask({ proxyPtr, [=] { 81 // FIXME: It is not correct to check m_client from a secondary thread - stop() could be racing with this check. 82 if (!proxyPtr->client()) 83 return; 84 85 proxyPtr->m_stream->start(); 86 callOnMainThread([proxyPtr] { 87 if (proxyPtr->client()) 88 proxyPtr->client()->didStart(); 89 }); 90 } }); 91 92 return proxy.release(); 93} 94 95AsyncFileStream::~AsyncFileStream() 96{ 97} 98 99void AsyncFileStream::stop() 100{ 101 // Clear the client so that we won't be invoking callbacks on the client. 102 setClient(0); 103 104 fileThread()->unscheduleTasks(m_stream.get()); 105 fileThread()->postTask({ this, [this] { 106 m_stream->stop(); 107 callOnMainThread([this] { 108 ASSERT(hasOneRef()); 109 deref(); 110 }); 111 } }); 112} 113 114void AsyncFileStream::getSize(const String& path, double expectedModificationTime) 115{ 116 String pathCopy = path.isolatedCopy(); 117 fileThread()->postTask({ this, [this, pathCopy, expectedModificationTime] { 118 long long size = m_stream->getSize(pathCopy, expectedModificationTime); 119 callOnMainThread([this, size] { 120 if (client()) 121 client()->didGetSize(size); 122 }); 123 } }); 124} 125 126void AsyncFileStream::openForRead(const String& path, long long offset, long long length) 127{ 128 String pathCopy = path.isolatedCopy(); 129 fileThread()->postTask({ this, [this, pathCopy, offset, length] { 130 bool success = m_stream->openForRead(pathCopy, offset, length); 131 callOnMainThread([this, success] { 132 if (client()) 133 client()->didOpen(success); 134 }); 135 } }); 136} 137 138void AsyncFileStream::openForWrite(const String& path) 139{ 140 String pathCopy = path.isolatedCopy(); 141 fileThread()->postTask({ this, [this, pathCopy] { 142 bool success = m_stream->openForWrite(pathCopy); 143 callOnMainThread([this, success] { 144 if (client()) 145 client()->didOpen(success); 146 }); 147 } }); 148} 149 150void AsyncFileStream::close() 151{ 152 fileThread()->postTask({this, [this] { 153 m_stream->close(); 154 } }); 155} 156 157void AsyncFileStream::read(char* buffer, int length) 158{ 159 fileThread()->postTask({ this, [this, buffer, length] { 160 int bytesRead = m_stream->read(buffer, length); 161 callOnMainThread([this, bytesRead] { 162 if (client()) 163 client()->didRead(bytesRead); 164 }); 165 } }); 166} 167 168void AsyncFileStream::write(const URL& blobURL, long long position, int length) 169{ 170 URL blobURLCopy = blobURL.copy(); 171 fileThread()->postTask({ this, [this, blobURLCopy, position, length] { 172 int bytesWritten = m_stream->write(blobURLCopy, position, length); 173 callOnMainThread([this, bytesWritten] { 174 if (client()) 175 client()->didWrite(bytesWritten); 176 }); 177 } }); 178} 179 180void AsyncFileStream::truncate(long long position) 181{ 182 fileThread()->postTask({ this, [this, position] { 183 bool success = m_stream->truncate(position); 184 callOnMainThread([this, success] { 185 if (client()) 186 client()->didTruncate(success); 187 }); 188 } }); 189} 190 191} // namespace WebCore 192