2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "WorkerFileSystemCallbacksBridge.h"
34 #if ENABLE(FILE_SYSTEM) && ENABLE(WORKERS)
36 #include "CrossThreadTask.h"
38 #include "WebCommonWorkerClient.h"
39 #include "WebFileInfo.h"
40 #include "WebFileSystemCallbacks.h"
41 #include "WebFileSystemEntry.h"
42 #include "WebString.h"
44 #include "WebWorkerBase.h"
45 #include "WorkerContext.h"
46 #include "WorkerLoaderProxy.h"
47 #include "WorkerScriptController.h"
48 #include "WorkerThread.h"
49 #include <wtf/MainThread.h>
50 #include <wtf/Threading.h>
51 #include <wtf/UnusedParam.h>
55 template<> struct CrossThreadCopierBase<false, false, WebKit::WebFileInfo> {
56 typedef WebKit::WebFileInfo Type;
57 static Type copy(const WebKit::WebFileInfo& info)
59 // Perform per-field copy to make sure we don't do any (unexpected) non-thread safe copy here.
60 struct WebKit::WebFileInfo newInfo;
61 newInfo.modificationTime = info.modificationTime;
62 newInfo.length = info.length;
63 newInfo.type = info.type;
64 newInfo.platformPath.assign(info.platformPath.data(), info.platformPath.length());
69 template<> struct CrossThreadCopierBase<false, false, WebKit::WebVector<WebKit::WebFileSystemEntry> > {
70 typedef WebKit::WebVector<WebKit::WebFileSystemEntry> Type;
71 static Type copy(const WebKit::WebVector<WebKit::WebFileSystemEntry>& entries)
73 WebKit::WebVector<WebKit::WebFileSystemEntry> newEntries(entries.size());
74 for (size_t i = 0; i < entries.size(); ++i) {
75 String name = entries[i].name;
76 newEntries[i].isDirectory = entries[i].isDirectory;
77 newEntries[i].name = name.isolatedCopy();
85 using namespace WebCore;
89 // FileSystemCallbacks that are to be dispatched on the main thread.
90 class MainThreadFileSystemCallbacks : public WebFileSystemCallbacks {
92 // Callbacks are self-destructed and we always return leaked pointer here.
93 static MainThreadFileSystemCallbacks* createLeakedPtr(WorkerFileSystemCallbacksBridge* bridge, const String& mode)
95 OwnPtr<MainThreadFileSystemCallbacks> callbacks = adoptPtr(new MainThreadFileSystemCallbacks(bridge, mode));
96 return callbacks.leakPtr();
99 virtual ~MainThreadFileSystemCallbacks()
103 virtual void didOpenFileSystem(const WebString& name, const WebURL& rootURL)
105 m_bridge->didOpenFileSystemOnMainThread(name, rootURL, m_mode);
109 virtual void didFail(WebFileError error)
111 m_bridge->didFailOnMainThread(error, m_mode);
115 virtual void didSucceed()
117 m_bridge->didSucceedOnMainThread(m_mode);
121 virtual void didReadMetadata(const WebFileInfo& info)
123 m_bridge->didReadMetadataOnMainThread(info, m_mode);
127 virtual void didReadDirectory(const WebVector<WebFileSystemEntry>& entries, bool hasMore)
129 m_bridge->didReadDirectoryOnMainThread(entries, hasMore, m_mode);
134 MainThreadFileSystemCallbacks(WorkerFileSystemCallbacksBridge* bridge, const String& mode)
141 friend class WorkerFileSystemCallbacksBridge;
142 // The bridge pointer is kept by the bridge itself on the WorkerThread.
143 WorkerFileSystemCallbacksBridge* m_bridge;
147 void WorkerFileSystemCallbacksBridge::stop()
149 ASSERT(m_workerContext->isContextThread());
150 MutexLocker locker(m_mutex);
151 m_workerLoaderProxy = 0;
153 if (m_callbacksOnWorkerThread) {
154 m_callbacksOnWorkerThread->didFail(WebFileErrorAbort);
155 m_callbacksOnWorkerThread = 0;
159 void WorkerFileSystemCallbacksBridge::postOpenFileSystemToMainThread(NewWebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, const String& mode)
161 dispatchTaskToMainThread(
162 createCallbackTask(&openFileSystemOnMainThread,
163 AllowCrossThreadAccess(commonClient), type, size, create,
164 AllowCrossThreadAccess(this), mode));
167 void WorkerFileSystemCallbacksBridge::postMoveToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
169 dispatchTaskToMainThread(
170 createCallbackTask(&moveOnMainThread,
171 AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
172 AllowCrossThreadAccess(this), mode));
175 void WorkerFileSystemCallbacksBridge::postCopyToMainThread(WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, const String& mode)
177 dispatchTaskToMainThread(
178 createCallbackTask(©OnMainThread,
179 AllowCrossThreadAccess(fileSystem), sourcePath, destinationPath,
180 AllowCrossThreadAccess(this), mode));
183 void WorkerFileSystemCallbacksBridge::postRemoveToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
186 dispatchTaskToMainThread(
187 createCallbackTask(&removeOnMainThread,
188 AllowCrossThreadAccess(fileSystem), path,
189 AllowCrossThreadAccess(this), mode));
192 void WorkerFileSystemCallbacksBridge::postRemoveRecursivelyToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
195 dispatchTaskToMainThread(
196 createCallbackTask(&removeRecursivelyOnMainThread,
197 AllowCrossThreadAccess(fileSystem), path,
198 AllowCrossThreadAccess(this), mode));
201 void WorkerFileSystemCallbacksBridge::postReadMetadataToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
204 dispatchTaskToMainThread(
205 createCallbackTask(&readMetadataOnMainThread,
206 AllowCrossThreadAccess(fileSystem), path,
207 AllowCrossThreadAccess(this), mode));
210 void WorkerFileSystemCallbacksBridge::postCreateFileToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
212 dispatchTaskToMainThread(
213 createCallbackTask(&createFileOnMainThread,
214 AllowCrossThreadAccess(fileSystem), path, exclusive,
215 AllowCrossThreadAccess(this), mode));
218 void WorkerFileSystemCallbacksBridge::postCreateDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, bool exclusive, const String& mode)
221 dispatchTaskToMainThread(
222 createCallbackTask(&createDirectoryOnMainThread,
223 AllowCrossThreadAccess(fileSystem), path, exclusive,
224 AllowCrossThreadAccess(this), mode));
227 void WorkerFileSystemCallbacksBridge::postFileExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
230 dispatchTaskToMainThread(
231 createCallbackTask(&fileExistsOnMainThread,
232 AllowCrossThreadAccess(fileSystem), path,
233 AllowCrossThreadAccess(this), mode));
236 void WorkerFileSystemCallbacksBridge::postDirectoryExistsToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
239 dispatchTaskToMainThread(
240 createCallbackTask(&directoryExistsOnMainThread,
241 AllowCrossThreadAccess(fileSystem), path,
242 AllowCrossThreadAccess(this), mode));
245 void WorkerFileSystemCallbacksBridge::postReadDirectoryToMainThread(WebFileSystem* fileSystem, const KURL& path, const String& mode)
248 dispatchTaskToMainThread(
249 createCallbackTask(&readDirectoryOnMainThread,
250 AllowCrossThreadAccess(fileSystem), path,
251 AllowCrossThreadAccess(this), mode));
254 void WorkerFileSystemCallbacksBridge::openFileSystemOnMainThread(ScriptExecutionContext*, NewWebCommonWorkerClient* commonClient, WebFileSystem::Type type, long long size, bool create, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
257 bridge->didFailOnMainThread(WebFileErrorAbort, mode);
259 commonClient->openFileSystem(type, size, create, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
263 void WorkerFileSystemCallbacksBridge::moveOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
265 fileSystem->move(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
268 void WorkerFileSystemCallbacksBridge::copyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& sourcePath, const KURL& destinationPath, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
270 fileSystem->copy(sourcePath, destinationPath, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
273 void WorkerFileSystemCallbacksBridge::removeOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
275 fileSystem->remove(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
278 void WorkerFileSystemCallbacksBridge::removeRecursivelyOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
280 fileSystem->removeRecursively(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
283 void WorkerFileSystemCallbacksBridge::readMetadataOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
285 fileSystem->readMetadata(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
288 void WorkerFileSystemCallbacksBridge::createFileOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
290 fileSystem->createFile(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
293 void WorkerFileSystemCallbacksBridge::createDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, bool exclusive, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
295 fileSystem->createDirectory(path, exclusive, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
298 void WorkerFileSystemCallbacksBridge::fileExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
300 fileSystem->fileExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
303 void WorkerFileSystemCallbacksBridge::directoryExistsOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
305 fileSystem->directoryExists(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
308 void WorkerFileSystemCallbacksBridge::readDirectoryOnMainThread(WebCore::ScriptExecutionContext*, WebFileSystem* fileSystem, const KURL& path, WorkerFileSystemCallbacksBridge* bridge, const String& mode)
310 fileSystem->readDirectory(path, MainThreadFileSystemCallbacks::createLeakedPtr(bridge, mode));
313 void WorkerFileSystemCallbacksBridge::didFailOnMainThread(WebFileError error, const String& mode)
315 mayPostTaskToWorker(createCallbackTask(&didFailOnWorkerThread, AllowCrossThreadAccess(this), error), mode);
318 void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnMainThread(const String& name, const KURL& rootURL, const String& mode)
320 mayPostTaskToWorker(createCallbackTask(&didOpenFileSystemOnWorkerThread,
321 AllowCrossThreadAccess(this), name, rootURL), mode);
324 void WorkerFileSystemCallbacksBridge::didSucceedOnMainThread(const String& mode)
326 mayPostTaskToWorker(createCallbackTask(&didSucceedOnWorkerThread, AllowCrossThreadAccess(this)), mode);
329 void WorkerFileSystemCallbacksBridge::didReadMetadataOnMainThread(const WebFileInfo& info, const String& mode)
331 mayPostTaskToWorker(createCallbackTask(&didReadMetadataOnWorkerThread, AllowCrossThreadAccess(this), info), mode);
334 void WorkerFileSystemCallbacksBridge::didReadDirectoryOnMainThread(const WebVector<WebFileSystemEntry>& entries, bool hasMore, const String& mode)
337 createCallbackTask(&didReadDirectoryOnWorkerThread,
338 AllowCrossThreadAccess(this), entries, hasMore), mode);
341 WorkerFileSystemCallbacksBridge::WorkerFileSystemCallbacksBridge(WebCore::WorkerLoaderProxy* workerLoaderProxy, ScriptExecutionContext* scriptExecutionContext, WebFileSystemCallbacks* callbacks)
342 : WorkerContext::Observer(static_cast<WorkerContext*>(scriptExecutionContext))
343 , m_workerLoaderProxy(workerLoaderProxy)
344 , m_workerContext(scriptExecutionContext)
345 , m_callbacksOnWorkerThread(callbacks)
347 ASSERT(m_workerContext->isContextThread());
350 WorkerFileSystemCallbacksBridge::~WorkerFileSystemCallbacksBridge()
352 ASSERT(!m_callbacksOnWorkerThread);
355 void WorkerFileSystemCallbacksBridge::didFailOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, WebFileError error)
357 bridge->m_callbacksOnWorkerThread->didFail(error);
360 void WorkerFileSystemCallbacksBridge::didOpenFileSystemOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const String& name, const KURL& rootURL)
362 bridge->m_callbacksOnWorkerThread->didOpenFileSystem(name, rootURL);
365 void WorkerFileSystemCallbacksBridge::didSucceedOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge)
367 bridge->m_callbacksOnWorkerThread->didSucceed();
370 void WorkerFileSystemCallbacksBridge::didReadMetadataOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const WebFileInfo& info)
372 bridge->m_callbacksOnWorkerThread->didReadMetadata(info);
375 void WorkerFileSystemCallbacksBridge::didReadDirectoryOnWorkerThread(ScriptExecutionContext*, WorkerFileSystemCallbacksBridge* bridge, const WebVector<WebFileSystemEntry>& entries, bool hasMore)
377 bridge->m_callbacksOnWorkerThread->didReadDirectory(entries, hasMore);
381 void WorkerFileSystemCallbacksBridge::runTaskOnMainThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
383 ASSERT(isMainThread());
385 // Every task run will result in one call to mayPostTaskToWorker, which is where this ref is released.
386 WorkerFileSystemCallbacksBridge* leaked = bridge.leakRef();
387 UNUSED_PARAM(leaked);
388 taskToRun->performTask(scriptExecutionContext);
391 void WorkerFileSystemCallbacksBridge::runTaskOnWorkerThread(WebCore::ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileSystemCallbacksBridge> bridge, PassOwnPtr<WebCore::ScriptExecutionContext::Task> taskToRun)
393 if (!bridge->m_callbacksOnWorkerThread)
395 ASSERT(bridge->m_workerContext->isContextThread());
396 taskToRun->performTask(scriptExecutionContext);
397 bridge->m_callbacksOnWorkerThread = 0;
398 bridge->stopObserving();
401 void WorkerFileSystemCallbacksBridge::dispatchTaskToMainThread(PassOwnPtr<WebCore::ScriptExecutionContext::Task> task)
403 ASSERT(m_workerLoaderProxy);
404 ASSERT(m_workerContext->isContextThread());
405 WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&runTaskOnMainThread, RefPtr<WorkerFileSystemCallbacksBridge>(this).release(), task));
408 void WorkerFileSystemCallbacksBridge::mayPostTaskToWorker(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
410 ASSERT(isMainThread());
412 // Balancing out the ref() done in runTaskOnMainThread. (Since m_mutex is a member and the deref may result
413 // in the destruction of WorkerFileSystemCallbacksBridge, the ordering of the RefPtr and the MutexLocker
414 // is very important, to ensure that the m_mutex is still valid when it gets unlocked.)
415 RefPtr<WorkerFileSystemCallbacksBridge> bridge = adoptRef(this);
416 MutexLocker locker(m_mutex);
417 if (m_workerLoaderProxy)
418 m_workerLoaderProxy->postTaskForModeToWorkerContext(createCallbackTask(&runTaskOnWorkerThread, bridge, task), mode);
421 } // namespace WebCore
423 #endif // ENABLE(FILE_SYSTEM)