| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "config.h" | 27 #include "config.h" |
| 28 | 28 |
| 29 #include "core/workers/WorkerThread.h" | 29 #include "core/workers/WorkerThread.h" |
| 30 | 30 |
| 31 #include "bindings/v8/ScriptSourceCode.h" | 31 #include "bindings/v8/ScriptSourceCode.h" |
| 32 #include "bindings/v8/ScriptValue.h" | 32 #include "bindings/v8/ScriptValue.h" |
| 33 #include "core/inspector/InspectorInstrumentation.h" | 33 #include "core/inspector/InspectorInstrumentation.h" |
| 34 #include "core/platform/ThreadGlobalData.h" | 34 #include "core/platform/ThreadGlobalData.h" |
| 35 #include "core/workers/DedicatedWorkerContext.h" | 35 #include "core/workers/DedicatedWorkerGlobalScope.h" |
| 36 #include "modules/webdatabase/DatabaseManager.h" | 36 #include "modules/webdatabase/DatabaseManager.h" |
| 37 #include "modules/webdatabase/DatabaseTask.h" | 37 #include "modules/webdatabase/DatabaseTask.h" |
| 38 #include "public/platform/Platform.h" | 38 #include "public/platform/Platform.h" |
| 39 #include "public/platform/WebWorkerRunLoop.h" | 39 #include "public/platform/WebWorkerRunLoop.h" |
| 40 #include "weborigin/KURL.h" | 40 #include "weborigin/KURL.h" |
| 41 #include "wtf/Noncopyable.h" | 41 #include "wtf/Noncopyable.h" |
| 42 #include "wtf/text/WTFString.h" | 42 #include "wtf/text/WTFString.h" |
| 43 | 43 |
| 44 #include <utility> | 44 #include <utility> |
| 45 | 45 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 | 128 |
| 129 void WorkerThread::workerThreadStart(void* thread) | 129 void WorkerThread::workerThreadStart(void* thread) |
| 130 { | 130 { |
| 131 static_cast<WorkerThread*>(thread)->workerThread(); | 131 static_cast<WorkerThread*>(thread)->workerThread(); |
| 132 } | 132 } |
| 133 | 133 |
| 134 void WorkerThread::workerThread() | 134 void WorkerThread::workerThread() |
| 135 { | 135 { |
| 136 { | 136 { |
| 137 MutexLocker lock(m_threadCreationMutex); | 137 MutexLocker lock(m_threadCreationMutex); |
| 138 m_workerContext = createWorkerContext(m_startupData->m_scriptURL, m_star
tupData->m_userAgent, m_startupData->m_contentSecurityPolicy, m_startupData->m_c
ontentSecurityPolicyType, m_startupData->m_topOrigin.release()); | 138 m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL
, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicy, m_startupD
ata->m_contentSecurityPolicyType, m_startupData->m_topOrigin.release()); |
| 139 | 139 |
| 140 if (m_runLoop.terminated()) { | 140 if (m_runLoop.terminated()) { |
| 141 // The worker was terminated before the thread had a chance to run.
Since the context didn't exist yet, | 141 // The worker was terminated before the thread had a chance to run.
Since the context didn't exist yet, |
| 142 // forbidExecution() couldn't be called from stop(). | 142 // forbidExecution() couldn't be called from stop(). |
| 143 m_workerContext->script()->forbidExecution(); | 143 m_workerGlobalScope->script()->forbidExecution(); |
| 144 } | 144 } |
| 145 } | 145 } |
| 146 // The corresponding call to didStopWorkerRunLoop is in | 146 // The corresponding call to didStopWorkerRunLoop is in |
| 147 // ~WorkerScriptController. | 147 // ~WorkerScriptController. |
| 148 WebKit::Platform::current()->didStartWorkerRunLoop(WebKit::WebWorkerRunLoop(
&m_runLoop)); | 148 WebKit::Platform::current()->didStartWorkerRunLoop(WebKit::WebWorkerRunLoop(
&m_runLoop)); |
| 149 | 149 |
| 150 WorkerScriptController* script = m_workerContext->script(); | 150 WorkerScriptController* script = m_workerGlobalScope->script(); |
| 151 InspectorInstrumentation::willEvaluateWorkerScript(workerContext(), m_startu
pData->m_startMode); | 151 InspectorInstrumentation::willEvaluateWorkerScript(workerGlobalScope(), m_st
artupData->m_startMode); |
| 152 script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData
->m_scriptURL)); | 152 script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData
->m_scriptURL)); |
| 153 // Free the startup data to cause its member variable deref's happen on the
worker's thread (since | 153 // Free the startup data to cause its member variable deref's happen on the
worker's thread (since |
| 154 // all ref/derefs of these objects are happening on the thread at this point
). Note that | 154 // all ref/derefs of these objects are happening on the thread at this point
). Note that |
| 155 // WorkerThread::~WorkerThread happens on a different thread where it was cr
eated. | 155 // WorkerThread::~WorkerThread happens on a different thread where it was cr
eated. |
| 156 m_startupData.clear(); | 156 m_startupData.clear(); |
| 157 | 157 |
| 158 runEventLoop(); | 158 runEventLoop(); |
| 159 | 159 |
| 160 ThreadIdentifier threadID = m_threadID; | 160 ThreadIdentifier threadID = m_threadID; |
| 161 | 161 |
| 162 ASSERT(m_workerContext->hasOneRef()); | 162 ASSERT(m_workerGlobalScope->hasOneRef()); |
| 163 | 163 |
| 164 // The below assignment will destroy the context, which will in turn notify
messaging proxy. | 164 // The below assignment will destroy the context, which will in turn notify
messaging proxy. |
| 165 // We cannot let any objects survive past thread exit, because no other thre
ad will run GC or otherwise destroy them. | 165 // We cannot let any objects survive past thread exit, because no other thre
ad will run GC or otherwise destroy them. |
| 166 m_workerContext = 0; | 166 m_workerGlobalScope = 0; |
| 167 | 167 |
| 168 // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! | 168 // Clean up WebCore::ThreadGlobalData before WTF::WTFThreadData goes away! |
| 169 threadGlobalData().destroy(); | 169 threadGlobalData().destroy(); |
| 170 | 170 |
| 171 // The thread object may be already destroyed from notification now, don't t
ry to access "this". | 171 // The thread object may be already destroyed from notification now, don't t
ry to access "this". |
| 172 detachThread(threadID); | 172 detachThread(threadID); |
| 173 } | 173 } |
| 174 | 174 |
| 175 void WorkerThread::runEventLoop() | 175 void WorkerThread::runEventLoop() |
| 176 { | 176 { |
| 177 // Does not return until terminated. | 177 // Does not return until terminated. |
| 178 m_runLoop.run(m_workerContext.get()); | 178 m_runLoop.run(m_workerGlobalScope.get()); |
| 179 } | 179 } |
| 180 | 180 |
| 181 class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task { | 181 class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task { |
| 182 public: | 182 public: |
| 183 static PassOwnPtr<WorkerThreadShutdownFinishTask> create() | 183 static PassOwnPtr<WorkerThreadShutdownFinishTask> create() |
| 184 { | 184 { |
| 185 return adoptPtr(new WorkerThreadShutdownFinishTask()); | 185 return adoptPtr(new WorkerThreadShutdownFinishTask()); |
| 186 } | 186 } |
| 187 | 187 |
| 188 virtual void performTask(ScriptExecutionContext *context) | 188 virtual void performTask(ScriptExecutionContext *context) |
| 189 { | 189 { |
| 190 ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerContext()); | 190 ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); |
| 191 WorkerContext* workerContext = static_cast<WorkerContext*>(context); | 191 WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(c
ontext); |
| 192 workerContext->clearInspector(); | 192 workerGlobalScope->clearInspector(); |
| 193 // It's not safe to call clearScript until all the cleanup tasks posted
by functions initiated by WorkerThreadShutdownStartTask have completed. | 193 // It's not safe to call clearScript until all the cleanup tasks posted
by functions initiated by WorkerThreadShutdownStartTask have completed. |
| 194 workerContext->clearScript(); | 194 workerGlobalScope->clearScript(); |
| 195 } | 195 } |
| 196 | 196 |
| 197 virtual bool isCleanupTask() const { return true; } | 197 virtual bool isCleanupTask() const { return true; } |
| 198 }; | 198 }; |
| 199 | 199 |
| 200 class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task { | 200 class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task { |
| 201 public: | 201 public: |
| 202 static PassOwnPtr<WorkerThreadShutdownStartTask> create() | 202 static PassOwnPtr<WorkerThreadShutdownStartTask> create() |
| 203 { | 203 { |
| 204 return adoptPtr(new WorkerThreadShutdownStartTask()); | 204 return adoptPtr(new WorkerThreadShutdownStartTask()); |
| 205 } | 205 } |
| 206 | 206 |
| 207 virtual void performTask(ScriptExecutionContext *context) | 207 virtual void performTask(ScriptExecutionContext *context) |
| 208 { | 208 { |
| 209 ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerContext()); | 209 ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); |
| 210 WorkerContext* workerContext = static_cast<WorkerContext*>(context); | 210 WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(c
ontext); |
| 211 | 211 |
| 212 // FIXME: Should we stop the databases as part of stopActiveDOMObjects()
below? | 212 // FIXME: Should we stop the databases as part of stopActiveDOMObjects()
below? |
| 213 DatabaseTaskSynchronizer cleanupSync; | 213 DatabaseTaskSynchronizer cleanupSync; |
| 214 DatabaseManager::manager().stopDatabases(workerContext, &cleanupSync); | 214 DatabaseManager::manager().stopDatabases(workerGlobalScope, &cleanupSync
); |
| 215 | 215 |
| 216 workerContext->stopActiveDOMObjects(); | 216 workerGlobalScope->stopActiveDOMObjects(); |
| 217 | 217 |
| 218 workerContext->notifyObserversOfStop(); | 218 workerGlobalScope->notifyObserversOfStop(); |
| 219 | 219 |
| 220 // Event listeners would keep DOMWrapperWorld objects alive for too long
. Also, they have references to JS objects, | 220 // Event listeners would keep DOMWrapperWorld objects alive for too long
. Also, they have references to JS objects, |
| 221 // which become dangling once Heap is destroyed. | 221 // which become dangling once Heap is destroyed. |
| 222 workerContext->removeAllEventListeners(); | 222 workerGlobalScope->removeAllEventListeners(); |
| 223 | 223 |
| 224 // We wait for the database thread to clean up all its stuff so that we | 224 // We wait for the database thread to clean up all its stuff so that we |
| 225 // can do more stringent leak checks as we exit. | 225 // can do more stringent leak checks as we exit. |
| 226 cleanupSync.waitForTaskCompletion(); | 226 cleanupSync.waitForTaskCompletion(); |
| 227 | 227 |
| 228 // Stick a shutdown command at the end of the queue, so that we deal | 228 // Stick a shutdown command at the end of the queue, so that we deal |
| 229 // with all the cleanup tasks the databases post first. | 229 // with all the cleanup tasks the databases post first. |
| 230 workerContext->postTask(WorkerThreadShutdownFinishTask::create()); | 230 workerGlobalScope->postTask(WorkerThreadShutdownFinishTask::create()); |
| 231 } | 231 } |
| 232 | 232 |
| 233 virtual bool isCleanupTask() const { return true; } | 233 virtual bool isCleanupTask() const { return true; } |
| 234 }; | 234 }; |
| 235 | 235 |
| 236 void WorkerThread::stop() | 236 void WorkerThread::stop() |
| 237 { | 237 { |
| 238 // Mutex protection is necessary because stop() can be called before the con
text is fully created. | 238 // Mutex protection is necessary because stop() can be called before the con
text is fully created. |
| 239 MutexLocker lock(m_threadCreationMutex); | 239 MutexLocker lock(m_threadCreationMutex); |
| 240 | 240 |
| 241 // Ensure that tasks are being handled by thread event loop. If script execu
tion weren't forbidden, a while(1) loop in JS could keep the thread alive foreve
r. | 241 // Ensure that tasks are being handled by thread event loop. If script execu
tion weren't forbidden, a while(1) loop in JS could keep the thread alive foreve
r. |
| 242 if (m_workerContext) { | 242 if (m_workerGlobalScope) { |
| 243 m_workerContext->script()->scheduleExecutionTermination(); | 243 m_workerGlobalScope->script()->scheduleExecutionTermination(); |
| 244 | 244 |
| 245 DatabaseManager::manager().interruptAllDatabasesForContext(m_workerConte
xt.get()); | 245 DatabaseManager::manager().interruptAllDatabasesForContext(m_workerGloba
lScope.get()); |
| 246 m_runLoop.postTaskAndTerminate(WorkerThreadShutdownStartTask::create()); | 246 m_runLoop.postTaskAndTerminate(WorkerThreadShutdownStartTask::create()); |
| 247 return; | 247 return; |
| 248 } | 248 } |
| 249 m_runLoop.terminate(); | 249 m_runLoop.terminate(); |
| 250 } | 250 } |
| 251 | 251 |
| 252 bool WorkerThread::isCurrentThread() const | 252 bool WorkerThread::isCurrentThread() const |
| 253 { | 253 { |
| 254 return m_threadID == currentThread(); | 254 return m_threadID == currentThread(); |
| 255 } | 255 } |
| 256 | 256 |
| 257 class ReleaseFastMallocFreeMemoryTask : public ScriptExecutionContext::Task { | 257 class ReleaseFastMallocFreeMemoryTask : public ScriptExecutionContext::Task { |
| 258 virtual void performTask(ScriptExecutionContext*) OVERRIDE { WTF::releaseFas
tMallocFreeMemory(); } | 258 virtual void performTask(ScriptExecutionContext*) OVERRIDE { WTF::releaseFas
tMallocFreeMemory(); } |
| 259 }; | 259 }; |
| 260 | 260 |
| 261 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads() | 261 void WorkerThread::releaseFastMallocFreeMemoryInAllThreads() |
| 262 { | 262 { |
| 263 MutexLocker lock(threadSetMutex()); | 263 MutexLocker lock(threadSetMutex()); |
| 264 HashSet<WorkerThread*>& threads = workerThreads(); | 264 HashSet<WorkerThread*>& threads = workerThreads(); |
| 265 HashSet<WorkerThread*>::iterator end = threads.end(); | 265 HashSet<WorkerThread*>::iterator end = threads.end(); |
| 266 for (HashSet<WorkerThread*>::iterator it = threads.begin(); it != end; ++it) | 266 for (HashSet<WorkerThread*>::iterator it = threads.begin(); it != end; ++it) |
| 267 (*it)->runLoop().postTask(adoptPtr(new ReleaseFastMallocFreeMemoryTask))
; | 267 (*it)->runLoop().postTask(adoptPtr(new ReleaseFastMallocFreeMemoryTask))
; |
| 268 } | 268 } |
| 269 | 269 |
| 270 } // namespace WebCore | 270 } // namespace WebCore |
| OLD | NEW |