• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30 
31 #include "config.h"
32 #include "WorkerFileWriterCallbacksBridge.h"
33 
34 #if ENABLE(FILE_SYSTEM)
35 
36 #include "AsyncFileWriterClient.h"
37 #include "CrossThreadTask.h"
38 #include "WebCString.h"
39 #include "WebFileSystem.h"
40 #include "WebFileWriter.h"
41 #include "WebKit.h"
42 #include "WebKitClient.h"
43 #include "WebWorkerBase.h"
44 #include "WorkerContext.h"
45 #include "WorkerLoaderProxy.h"
46 #include "WorkerThread.h"
47 #include <wtf/MainThread.h>
48 #include <wtf/Threading.h>
49 
50 using namespace WebCore;
51 
52 namespace WebKit {
53 
notifyStop()54 void WorkerFileWriterCallbacksBridge::notifyStop()
55 {
56     ASSERT(m_workerContext->isContextThread());
57     m_clientOnWorkerThread = 0;
58 }
59 
postWriteToMainThread(long long position,const KURL & data)60 void WorkerFileWriterCallbacksBridge::postWriteToMainThread(long long position, const KURL& data)
61 {
62     ASSERT(!m_operationInProgress);
63     m_operationInProgress = true;
64     dispatchTaskToMainThread(createCallbackTask(&writeOnMainThread, this, position, data));
65 }
66 
postTruncateToMainThread(long long length)67 void WorkerFileWriterCallbacksBridge::postTruncateToMainThread(long long length)
68 {
69     ASSERT(!m_operationInProgress);
70     m_operationInProgress = true;
71     dispatchTaskToMainThread(createCallbackTask(&truncateOnMainThread, this, length));
72 }
73 
postAbortToMainThread()74 void WorkerFileWriterCallbacksBridge::postAbortToMainThread()
75 {
76     ASSERT(m_operationInProgress);
77     dispatchTaskToMainThread(createCallbackTask(&abortOnMainThread, this));
78 }
79 
postShutdownToMainThread(PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)80 void WorkerFileWriterCallbacksBridge::postShutdownToMainThread(PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)
81 {
82     ASSERT(m_workerContext->isContextThread());
83     m_clientOnWorkerThread = 0;
84     dispatchTaskToMainThread(createCallbackTask(&shutdownOnMainThread, bridge));
85 }
86 
writeOnMainThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,long long position,const KURL & data)87 void WorkerFileWriterCallbacksBridge::writeOnMainThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, long long position, const KURL& data)
88 {
89     bridge->m_writer->write(position, WebURL(data));
90 }
91 
truncateOnMainThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,long long length)92 void WorkerFileWriterCallbacksBridge::truncateOnMainThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, long long length)
93 {
94     bridge->m_writer->truncate(length);
95 }
96 
abortOnMainThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)97 void WorkerFileWriterCallbacksBridge::abortOnMainThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)
98 {
99     bridge->m_writer->cancel();
100 }
101 
initOnMainThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,const String & path)102 void WorkerFileWriterCallbacksBridge::initOnMainThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, const String& path)
103 {
104     ASSERT(!bridge->m_writer);
105     bridge->m_writer = webKitClient()->fileSystem()->createFileWriter(path, bridge.get());
106 }
107 
shutdownOnMainThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)108 void WorkerFileWriterCallbacksBridge::shutdownOnMainThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)
109 {
110     bridge->m_writerDeleted = true;
111     bridge->m_writer.clear();
112 }
113 
didWrite(long long bytes,bool complete)114 void WorkerFileWriterCallbacksBridge::didWrite(long long bytes, bool complete)
115 {
116     dispatchTaskToWorkerThread(createCallbackTask(&didWriteOnWorkerThread, this, bytes, complete));
117 }
118 
didFail(WebFileError error)119 void WorkerFileWriterCallbacksBridge::didFail(WebFileError error)
120 {
121     dispatchTaskToWorkerThread(createCallbackTask(&didFailOnWorkerThread, this, error));
122 }
123 
didTruncate()124 void WorkerFileWriterCallbacksBridge::didTruncate()
125 {
126     dispatchTaskToWorkerThread(createCallbackTask(&didTruncateOnWorkerThread, this));
127 }
128 
129 static const char fileWriterOperationsMode[] = "fileWriterOperationsMode";
130 
WorkerFileWriterCallbacksBridge(const String & path,WorkerLoaderProxy * proxy,ScriptExecutionContext * scriptExecutionContext,AsyncFileWriterClient * client)131 WorkerFileWriterCallbacksBridge::WorkerFileWriterCallbacksBridge(const String& path, WorkerLoaderProxy* proxy, ScriptExecutionContext* scriptExecutionContext, AsyncFileWriterClient* client)
132     : WorkerContext::Observer(static_cast<WorkerContext*>(scriptExecutionContext))
133     , m_proxy(proxy)
134     , m_workerContext(scriptExecutionContext)
135     , m_clientOnWorkerThread(client)
136     , m_writerDeleted(false)
137     , m_operationInProgress(false)
138 {
139     ASSERT(m_workerContext->isContextThread());
140     m_mode = fileWriterOperationsMode;
141     m_mode.append(String::number(static_cast<WorkerContext*>(scriptExecutionContext)->thread()->runLoop().createUniqueId()));
142     postInitToMainThread(path);
143 }
144 
postInitToMainThread(const String & path)145 void WorkerFileWriterCallbacksBridge::postInitToMainThread(const String& path)
146 {
147     dispatchTaskToMainThread(createCallbackTask(&initOnMainThread, this, path));
148 }
149 
~WorkerFileWriterCallbacksBridge()150 WorkerFileWriterCallbacksBridge::~WorkerFileWriterCallbacksBridge()
151 {
152     ASSERT(!m_clientOnWorkerThread);
153     ASSERT(!m_writer);
154 }
155 
156 // We know m_clientOnWorkerThread is still valid because it is only cleared on the context thread, and because we check in runTaskOnWorkerThread before calling any of these methods.
didWriteOnWorkerThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,long long length,bool complete)157 void WorkerFileWriterCallbacksBridge::didWriteOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, long long length, bool complete)
158 {
159     ASSERT(bridge->m_workerContext->isContextThread());
160     ASSERT(bridge->m_operationInProgress);
161     if (complete)
162         bridge->m_operationInProgress = false;
163     bridge->m_clientOnWorkerThread->didWrite(length, complete);
164 }
165 
didFailOnWorkerThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,WebFileError error)166 void WorkerFileWriterCallbacksBridge::didFailOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, WebFileError error)
167 {
168     ASSERT(bridge->m_workerContext->isContextThread());
169     ASSERT(bridge->m_operationInProgress);
170     bridge->m_operationInProgress = false;
171     bridge->m_clientOnWorkerThread->didFail(static_cast<FileError::ErrorCode>(error));
172 }
173 
didTruncateOnWorkerThread(ScriptExecutionContext *,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)174 void WorkerFileWriterCallbacksBridge::didTruncateOnWorkerThread(ScriptExecutionContext*, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge)
175 {
176     ASSERT(bridge->m_workerContext->isContextThread());
177     ASSERT(bridge->m_operationInProgress);
178     bridge->m_operationInProgress = false;
179     bridge->m_clientOnWorkerThread->didTruncate();
180 }
181 
runTaskOnMainThread(ScriptExecutionContext * scriptExecutionContext,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,PassOwnPtr<ScriptExecutionContext::Task> taskToRun)182 void WorkerFileWriterCallbacksBridge::runTaskOnMainThread(ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, PassOwnPtr<ScriptExecutionContext::Task> taskToRun)
183 {
184     ASSERT(isMainThread());
185     if (!bridge->m_writerDeleted)
186         taskToRun->performTask(scriptExecutionContext);
187 }
188 
runTaskOnWorkerThread(ScriptExecutionContext * scriptExecutionContext,PassRefPtr<WorkerFileWriterCallbacksBridge> bridge,PassOwnPtr<ScriptExecutionContext::Task> taskToRun)189 void WorkerFileWriterCallbacksBridge::runTaskOnWorkerThread(ScriptExecutionContext* scriptExecutionContext, PassRefPtr<WorkerFileWriterCallbacksBridge> bridge, PassOwnPtr<ScriptExecutionContext::Task> taskToRun)
190 {
191     ASSERT(bridge->m_workerContext->isContextThread());
192     if (bridge->m_clientOnWorkerThread)
193         taskToRun->performTask(scriptExecutionContext);
194 }
195 
dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task)196 void WorkerFileWriterCallbacksBridge::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task)
197 {
198     ASSERT(m_workerContext->isContextThread());
199     WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&runTaskOnMainThread, this, task));
200 }
201 
dispatchTaskToWorkerThread(PassOwnPtr<ScriptExecutionContext::Task> task)202 void WorkerFileWriterCallbacksBridge::dispatchTaskToWorkerThread(PassOwnPtr<ScriptExecutionContext::Task> task)
203 {
204     ASSERT(isMainThread());
205     m_proxy->postTaskForModeToWorkerContext(createCallbackTask(&runTaskOnWorkerThread, this, task), m_mode);
206 }
207 
waitForOperationToComplete()208 bool WorkerFileWriterCallbacksBridge::waitForOperationToComplete()
209 {
210     while (m_operationInProgress) {
211         WorkerContext* context = static_cast<WorkerContext*>(m_workerContext);
212         if (context->thread()->runLoop().runInMode(context, m_mode) == MessageQueueTerminated)
213             return false;
214     }
215     return true;
216 }
217 
218 } // namespace WebKit
219 
220 #endif // ENABLE(FILE_SYSTEM)
221