[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373
eric at webkit.org
eric at webkit.org
Thu Apr 8 01:18:55 UTC 2010
The following commit has been merged in the webkit-1.2 branch:
commit a1d89653c4b1ed0d0a43349c554e1e95d80f455b
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date: Thu Jan 21 03:49:51 2010 +0000
2010-01-20 Eric Uhrhane <ericu at chromium.org>
Reviewed by Dmitry Titov.
Refactoring and plumbing to get the HTML5 SQL Database API accessible to
web workers. No new functionality is exposed yet; this just gets the
infrastructure in place. It touches a lot of files in small ways; here
are the main changes:
1) Database members and methods move from Document up to
ScriptExecutionContext. Each of Document and WorkerContext must
implement a few virtual methods where the Database code requires
differentiation.
2) Worker thread shutdown got changed a bunch to handle Database cleanup
and thread synchronization issues. Database cleanup tasks need to post
some cleanup tasks to the JavaScript thread. However, since database
cleanup may happen due to the destruction of the WorkerThread, I added a
handshake [involving WorkerThreadShutdownStartTask,
WorkerThreadShutdownFinishTask, and a DatabaseTaskSynchronizer] between
the Database thread and WorkerThread that cleans up all the Database
stuff before the WorkerThread's runLoop can exit.
3) The runtime enabler for the Database moved to a static variable
accessible through Database::isAvailable, following the model used by
WebSocket.
4) Worker threads don't run their JavaScript on the Main thread, so
Database code that differentiated between the Main thread and the
Database thread now need to deal with a third possibility.
5) Most of the other changes have to do with having a
ScriptExecutionContext pointer instead of a Document pointer when
dealing with a Database. In many cases it's just a string replacement,
but in some it required the creation of a new virtual function [e.g.
databaseExceededQuota, isDatabaseReadOnly]
https://bugs.webkit.org/show_bug.cgi?id=22725
No new tests; in a future patch I'll add JSC and V8 bindings and new
layout tests to exercise them.
* bindings/v8/custom/V8DOMWindowCustom.cpp:
(WebCore::V8DOMWindow::OpenDatabaseEnabled):
* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::~Document):
(WebCore::Document::isDatabaseReadOnly):
(WebCore::Document::databaseExceededQuota):
(WebCore::Document::isContextThread):
* dom/Document.h:
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::ScriptExecutionContext):
(WebCore::ScriptExecutionContext::~ScriptExecutionContext):
(WebCore::ScriptExecutionContext::databaseThread):
(WebCore::ScriptExecutionContext::addOpenDatabase):
(WebCore::ScriptExecutionContext::removeOpenDatabase):
(WebCore::ScriptExecutionContext::stopDatabases):
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::setHasOpenDatabases):
(WebCore::ScriptExecutionContext::hasOpenDatabases):
(WebCore::ScriptExecutionContext::Task::isCleanupTask):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::stopLoading):
* storage/Database.cpp:
(WebCore::Database::setIsAvailable):
(WebCore::Database::isAvailable):
(WebCore::Database::openDatabase):
(WebCore::Database::Database):
(WebCore::DerefContextTask::create):
(WebCore::DerefContextTask::performTask):
(WebCore::DerefContextTask::isCleanupTask):
(WebCore::Database::~Database):
(WebCore::Database::openAndVerifyVersion):
(WebCore::Database::markAsDeletedAndClose):
(WebCore::ContextRemoveOpenDatabaseTask::create):
(WebCore::ContextRemoveOpenDatabaseTask::performTask):
(WebCore::ContextRemoveOpenDatabaseTask::isCleanupTask):
(WebCore::ContextRemoveOpenDatabaseTask::ContextRemoveOpenDatabaseTask):
(WebCore::Database::close):
(WebCore::Database::performOpenAndVerify):
(WebCore::Database::scheduleTransaction):
(WebCore::Database::scheduleTransactionStep):
(WebCore::DeliverPendingCallbackTask::create):
(WebCore::DeliverPendingCallbackTask::performTask):
(WebCore::DeliverPendingCallbackTask::DeliverPendingCallbackTask):
(WebCore::Database::scheduleTransactionCallback):
(WebCore::Database::transactionClient):
(WebCore::Database::transactionCoordinator):
(WebCore::Database::tableNames):
(WebCore::Database::securityOrigin):
* storage/Database.h:
(WebCore::Database::scriptExecutionContext):
* storage/DatabaseTask.h:
* storage/DatabaseThread.cpp:
(WebCore::DatabaseThread::DatabaseThread):
(WebCore::DatabaseThread::~DatabaseThread):
(WebCore::DatabaseThread::requestTermination):
(WebCore::DatabaseThread::databaseThread):
(WebCore::DatabaseThread::unscheduleDatabaseTasks):
* storage/DatabaseThread.h:
* storage/DatabaseTracker.cpp:
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::getMaxSizeForDatabase):
* storage/DatabaseTracker.h:
* storage/SQLTransaction.cpp:
(WebCore::SQLTransaction::executeSQL):
* storage/SQLTransactionClient.cpp:
(WebCore::SQLTransactionClient::didCommitTransaction):
(WebCore::SQLTransactionClient::didExecuteStatement):
(WebCore::SQLTransactionClient::didExceedQuota):
* storage/chromium/DatabaseTrackerChromium.cpp:
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::addOpenDatabase):
(WebCore::TrackerRemoveOpenDatabaseTask::create):
(WebCore::TrackerRemoveOpenDatabaseTask::performTask):
(WebCore::TrackerRemoveOpenDatabaseTask::TrackerRemoveOpenDatabaseTask):
(WebCore::DatabaseTracker::removeOpenDatabase):
(WebCore::DatabaseTracker::getMaxSizeForDatabase):
* storage/chromium/SQLTransactionClientChromium.cpp:
(WebCore::NotifyDatabaseChangedTask::create):
(WebCore::NotifyDatabaseChangedTask::performTask):
(WebCore::NotifyDatabaseChangedTask::NotifyDatabaseChangedTask):
(WebCore::SQLTransactionClient::didCommitTransaction):
(WebCore::SQLTransactionClient::didExecuteStatement):
(WebCore::SQLTransactionClient::didExceedQuota):
* workers/WorkerContext.cpp:
(WebCore::WorkerContext::openDatabase):
(WebCore::WorkerContext::isContextThread):
* workers/WorkerContext.h:
(WebCore::WorkerContext::clearScript):
(WebCore::WorkerContext::thread):
(WebCore::WorkerContext::isDatabaseReadOnly):
(WebCore::WorkerContext::databaseExceededQuota):
* workers/WorkerRunLoop.cpp:
(WebCore::WorkerRunLoop::runInMode):
(WebCore::WorkerRunLoop::Task::performTask):
* workers/WorkerThread.cpp:
(WebCore::WorkerThread::workerThread):
(WebCore::WorkerThreadShutdownFinishTask::create):
(WebCore::WorkerThreadShutdownFinishTask::performTask):
(WebCore::WorkerThreadShutdownFinishTask::isCleanupTask):
(WebCore::WorkerThreadShutdownStartTask::create):
(WebCore::WorkerThreadShutdownStartTask::performTask):
(WebCore::WorkerThreadShutdownStartTask::isCleanupTask):
(WebCore::WorkerThread::stop):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53595 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 47f3eb2..71e05b8 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,146 @@
+2010-01-20 Eric Uhrhane <ericu at chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Refactoring and plumbing to get the HTML5 SQL Database API accessible to
+ web workers. No new functionality is exposed yet; this just gets the
+ infrastructure in place. It touches a lot of files in small ways; here
+ are the main changes:
+
+ 1) Database members and methods move from Document up to
+ ScriptExecutionContext. Each of Document and WorkerContext must
+ implement a few virtual methods where the Database code requires
+ differentiation.
+ 2) Worker thread shutdown got changed a bunch to handle Database cleanup
+ and thread synchronization issues. Database cleanup tasks need to post
+ some cleanup tasks to the JavaScript thread. However, since database
+ cleanup may happen due to the destruction of the WorkerThread, I added a
+ handshake [involving WorkerThreadShutdownStartTask,
+ WorkerThreadShutdownFinishTask, and a DatabaseTaskSynchronizer] between
+ the Database thread and WorkerThread that cleans up all the Database
+ stuff before the WorkerThread's runLoop can exit.
+ 3) The runtime enabler for the Database moved to a static variable
+ accessible through Database::isAvailable, following the model used by
+ WebSocket.
+ 4) Worker threads don't run their JavaScript on the Main thread, so
+ Database code that differentiated between the Main thread and the
+ Database thread now need to deal with a third possibility.
+ 5) Most of the other changes have to do with having a
+ ScriptExecutionContext pointer instead of a Document pointer when
+ dealing with a Database. In many cases it's just a string replacement,
+ but in some it required the creation of a new virtual function [e.g.
+ databaseExceededQuota, isDatabaseReadOnly]
+
+ https://bugs.webkit.org/show_bug.cgi?id=22725
+
+ No new tests; in a future patch I'll add JSC and V8 bindings and new
+ layout tests to exercise them.
+
+ * bindings/v8/custom/V8DOMWindowCustom.cpp:
+ (WebCore::V8DOMWindow::OpenDatabaseEnabled):
+ * dom/Document.cpp:
+ (WebCore::Document::Document):
+ (WebCore::Document::~Document):
+ (WebCore::Document::isDatabaseReadOnly):
+ (WebCore::Document::databaseExceededQuota):
+ (WebCore::Document::isContextThread):
+ * dom/Document.h:
+ * dom/ScriptExecutionContext.cpp:
+ (WebCore::ScriptExecutionContext::ScriptExecutionContext):
+ (WebCore::ScriptExecutionContext::~ScriptExecutionContext):
+ (WebCore::ScriptExecutionContext::databaseThread):
+ (WebCore::ScriptExecutionContext::addOpenDatabase):
+ (WebCore::ScriptExecutionContext::removeOpenDatabase):
+ (WebCore::ScriptExecutionContext::stopDatabases):
+ * dom/ScriptExecutionContext.h:
+ (WebCore::ScriptExecutionContext::setHasOpenDatabases):
+ (WebCore::ScriptExecutionContext::hasOpenDatabases):
+ (WebCore::ScriptExecutionContext::Task::isCleanupTask):
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::stopLoading):
+ * storage/Database.cpp:
+ (WebCore::Database::setIsAvailable):
+ (WebCore::Database::isAvailable):
+ (WebCore::Database::openDatabase):
+ (WebCore::Database::Database):
+ (WebCore::DerefContextTask::create):
+ (WebCore::DerefContextTask::performTask):
+ (WebCore::DerefContextTask::isCleanupTask):
+ (WebCore::Database::~Database):
+ (WebCore::Database::openAndVerifyVersion):
+ (WebCore::Database::markAsDeletedAndClose):
+ (WebCore::ContextRemoveOpenDatabaseTask::create):
+ (WebCore::ContextRemoveOpenDatabaseTask::performTask):
+ (WebCore::ContextRemoveOpenDatabaseTask::isCleanupTask):
+ (WebCore::ContextRemoveOpenDatabaseTask::ContextRemoveOpenDatabaseTask):
+ (WebCore::Database::close):
+ (WebCore::Database::performOpenAndVerify):
+ (WebCore::Database::scheduleTransaction):
+ (WebCore::Database::scheduleTransactionStep):
+ (WebCore::DeliverPendingCallbackTask::create):
+ (WebCore::DeliverPendingCallbackTask::performTask):
+ (WebCore::DeliverPendingCallbackTask::DeliverPendingCallbackTask):
+ (WebCore::Database::scheduleTransactionCallback):
+ (WebCore::Database::transactionClient):
+ (WebCore::Database::transactionCoordinator):
+ (WebCore::Database::tableNames):
+ (WebCore::Database::securityOrigin):
+ * storage/Database.h:
+ (WebCore::Database::scriptExecutionContext):
+ * storage/DatabaseTask.h:
+ * storage/DatabaseThread.cpp:
+ (WebCore::DatabaseThread::DatabaseThread):
+ (WebCore::DatabaseThread::~DatabaseThread):
+ (WebCore::DatabaseThread::requestTermination):
+ (WebCore::DatabaseThread::databaseThread):
+ (WebCore::DatabaseThread::unscheduleDatabaseTasks):
+ * storage/DatabaseThread.h:
+ * storage/DatabaseTracker.cpp:
+ (WebCore::DatabaseTracker::canEstablishDatabase):
+ (WebCore::DatabaseTracker::getMaxSizeForDatabase):
+ * storage/DatabaseTracker.h:
+ * storage/SQLTransaction.cpp:
+ (WebCore::SQLTransaction::executeSQL):
+ * storage/SQLTransactionClient.cpp:
+ (WebCore::SQLTransactionClient::didCommitTransaction):
+ (WebCore::SQLTransactionClient::didExecuteStatement):
+ (WebCore::SQLTransactionClient::didExceedQuota):
+ * storage/chromium/DatabaseTrackerChromium.cpp:
+ (WebCore::DatabaseTracker::canEstablishDatabase):
+ (WebCore::DatabaseTracker::addOpenDatabase):
+ (WebCore::TrackerRemoveOpenDatabaseTask::create):
+ (WebCore::TrackerRemoveOpenDatabaseTask::performTask):
+ (WebCore::TrackerRemoveOpenDatabaseTask::TrackerRemoveOpenDatabaseTask):
+ (WebCore::DatabaseTracker::removeOpenDatabase):
+ (WebCore::DatabaseTracker::getMaxSizeForDatabase):
+ * storage/chromium/SQLTransactionClientChromium.cpp:
+ (WebCore::NotifyDatabaseChangedTask::create):
+ (WebCore::NotifyDatabaseChangedTask::performTask):
+ (WebCore::NotifyDatabaseChangedTask::NotifyDatabaseChangedTask):
+ (WebCore::SQLTransactionClient::didCommitTransaction):
+ (WebCore::SQLTransactionClient::didExecuteStatement):
+ (WebCore::SQLTransactionClient::didExceedQuota):
+ * workers/WorkerContext.cpp:
+ (WebCore::WorkerContext::openDatabase):
+ (WebCore::WorkerContext::isContextThread):
+ * workers/WorkerContext.h:
+ (WebCore::WorkerContext::clearScript):
+ (WebCore::WorkerContext::thread):
+ (WebCore::WorkerContext::isDatabaseReadOnly):
+ (WebCore::WorkerContext::databaseExceededQuota):
+ * workers/WorkerRunLoop.cpp:
+ (WebCore::WorkerRunLoop::runInMode):
+ (WebCore::WorkerRunLoop::Task::performTask):
+ * workers/WorkerThread.cpp:
+ (WebCore::WorkerThread::workerThread):
+ (WebCore::WorkerThreadShutdownFinishTask::create):
+ (WebCore::WorkerThreadShutdownFinishTask::performTask):
+ (WebCore::WorkerThreadShutdownFinishTask::isCleanupTask):
+ (WebCore::WorkerThreadShutdownStartTask::create):
+ (WebCore::WorkerThreadShutdownStartTask::performTask):
+ (WebCore::WorkerThreadShutdownStartTask::isCleanupTask):
+ (WebCore::WorkerThread::stop):
+
2010-01-20 Fumitoshi Ukai <ukai at chromium.org>
Reviewed by Alexey Proskuryakov.
diff --git a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
index b594518..924da72 100644
--- a/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
+++ b/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
@@ -33,6 +33,7 @@
#include "Base64.h"
#include "Chrome.h"
+#include "Database.h"
#include "DOMTimer.h"
#include "DOMWindow.h"
#include "ExceptionCode.h"
@@ -296,7 +297,7 @@ bool V8DOMWindow::WebSocketEnabled()
#if ENABLE(DATABASE)
bool V8DOMWindow::OpenDatabaseEnabled()
{
- return WebCore::RuntimeEnabledFeatures::databaseEnabled();
+ return Database::isAvailable();
}
#endif
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 70e9ae9..96b262b 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -37,6 +37,7 @@
#include "CString.h"
#include "CachedCSSStyleSheet.h"
#include "Chrome.h"
+#include "ChromeClient.h"
#include "Comment.h"
#include "Console.h"
#include "CookieJar.h"
@@ -138,11 +139,6 @@
#include <wtf/PassRefPtr.h>
#include <wtf/StdLibExtras.h>
-#if ENABLE(DATABASE)
-#include "Database.h"
-#include "DatabaseThread.h"
-#endif
-
#if ENABLE(SHARED_WORKERS)
#include "SharedWorkerRepository.h"
#endif
@@ -391,9 +387,6 @@ Document::Document(Frame* frame, bool isXHTML, bool isHTML)
#if USE(JSC)
, m_normalWorldWrapperCache(0)
#endif
-#if ENABLE(DATABASE)
- , m_hasOpenDatabases(false)
-#endif
, m_usingGeolocation(false)
#if ENABLE(WML)
, m_containsWMLContent(false)
@@ -539,13 +532,6 @@ Document::~Document()
for (unsigned i = 0; i < count; i++)
deleteAllValues(m_nameCollectionInfo[i]);
-#if ENABLE(DATABASE)
- if (m_databaseThread) {
- ASSERT(m_databaseThread->terminationRequested());
- m_databaseThread = 0;
- }
-#endif
-
if (m_styleSheets)
m_styleSheets->documentDestroyed();
@@ -4443,6 +4429,29 @@ void Document::setSecurityOrigin(SecurityOrigin* securityOrigin)
initDNSPrefetch();
}
+#if ENABLE(DATABASE)
+
+bool Document::isDatabaseReadOnly() const
+{
+ if (!page() || page()->settings()->privateBrowsingEnabled())
+ return true;
+ return false;
+}
+
+void Document::databaseExceededQuota(const String& name)
+{
+ Page* currentPage = page();
+ if (currentPage)
+ currentPage->chrome()->client()->exceededDatabaseQuota(document()->frame(), name);
+}
+
+#endif
+
+bool Document::isContextThread() const
+{
+ return isMainThread();
+}
+
void Document::updateURLForPushOrReplaceState(const KURL& url)
{
Frame* f = frame();
@@ -4543,57 +4552,6 @@ DOMSelection* Document::getSelection() const
return frame() ? frame()->domWindow()->getSelection() : 0;
}
-#if ENABLE(DATABASE)
-
-void Document::addOpenDatabase(Database* database)
-{
- if (!m_openDatabaseSet)
- m_openDatabaseSet.set(new DatabaseSet);
-
- ASSERT(!m_openDatabaseSet->contains(database));
- m_openDatabaseSet->add(database);
-}
-
-void Document::removeOpenDatabase(Database* database)
-{
- ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
- if (!m_openDatabaseSet)
- return;
-
- m_openDatabaseSet->remove(database);
-}
-
-DatabaseThread* Document::databaseThread()
-{
- if (!m_databaseThread && !m_hasOpenDatabases) {
- // Create the database thread on first request - but not if at least one database was already opened,
- // because in that case we already had a database thread and terminated it and should not create another.
- m_databaseThread = DatabaseThread::create();
- if (!m_databaseThread->start())
- m_databaseThread = 0;
- }
-
- return m_databaseThread.get();
-}
-
-void Document::stopDatabases()
-{
- if (m_openDatabaseSet) {
- DatabaseSet::iterator i = m_openDatabaseSet->begin();
- DatabaseSet::iterator end = m_openDatabaseSet->end();
- for (; i != end; ++i) {
- (*i)->stop();
- if (m_databaseThread)
- m_databaseThread->unscheduleDatabaseTasks(*i);
- }
- }
-
- if (m_databaseThread)
- m_databaseThread->requestTermination();
-}
-
-#endif
-
#if ENABLE(WML)
void Document::resetWMLPageState()
{
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index 6d7e088..20073cf 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -912,14 +912,12 @@ public:
bool processingLoadEvent() const { return m_processingLoadEvent; }
#if ENABLE(DATABASE)
- void addOpenDatabase(Database*);
- void removeOpenDatabase(Database*);
- DatabaseThread* databaseThread(); // Creates the thread as needed, but not if it has been already terminated.
- void setHasOpenDatabases() { m_hasOpenDatabases = true; }
- bool hasOpenDatabases() { return m_hasOpenDatabases; }
- void stopDatabases();
+ virtual bool isDatabaseReadOnly() const;
+ virtual void databaseExceededQuota(const String& name);
#endif
+ virtual bool isContextThread() const;
+
void setUsingGeolocation(bool f) { m_usingGeolocation = f; }
bool usingGeolocation() const { return m_usingGeolocation; };
@@ -1183,13 +1181,6 @@ private:
JSWrapperCache* m_normalWorldWrapperCache;
#endif
-#if ENABLE(DATABASE)
- RefPtr<DatabaseThread> m_databaseThread;
- bool m_hasOpenDatabases; // This never changes back to false, even as the database thread is closed.
- typedef HashSet<Database*> DatabaseSet;
- OwnPtr<DatabaseSet> m_openDatabaseSet;
-#endif
-
bool m_usingGeolocation;
#if ENABLE(WML)
diff --git a/WebCore/dom/ScriptExecutionContext.cpp b/WebCore/dom/ScriptExecutionContext.cpp
index bc71084..b10f06e 100644
--- a/WebCore/dom/ScriptExecutionContext.cpp
+++ b/WebCore/dom/ScriptExecutionContext.cpp
@@ -28,7 +28,8 @@
#include "ScriptExecutionContext.h"
#include "ActiveDOMObject.h"
-#include "Document.h"
+#include "DatabaseTask.h"
+#include "DatabaseThread.h"
#include "MessagePort.h"
#include "SecurityOrigin.h"
#include "WorkerContext.h"
@@ -56,6 +57,9 @@ public:
};
ScriptExecutionContext::ScriptExecutionContext()
+#if ENABLE(DATABASE)
+ : m_hasOpenDatabases(false)
+#endif
{
}
@@ -72,8 +76,67 @@ ScriptExecutionContext::~ScriptExecutionContext()
ASSERT((*iter)->scriptExecutionContext() == this);
(*iter)->contextDestroyed();
}
+ if (m_databaseThread) {
+ ASSERT(m_databaseThread->terminationRequested());
+ m_databaseThread = 0;
+ }
}
+#if ENABLE(DATABASE)
+
+DatabaseThread* ScriptExecutionContext::databaseThread()
+{
+ if (!m_databaseThread && !m_hasOpenDatabases) {
+ // Create the database thread on first request - but not if at least one database was already opened,
+ // because in that case we already had a database thread and terminated it and should not create another.
+ m_databaseThread = DatabaseThread::create();
+ if (!m_databaseThread->start())
+ m_databaseThread = 0;
+ }
+
+ return m_databaseThread.get();
+}
+
+void ScriptExecutionContext::addOpenDatabase(Database* database)
+{
+ ASSERT(isContextThread());
+ if (!m_openDatabaseSet)
+ m_openDatabaseSet.set(new DatabaseSet());
+
+ ASSERT(!m_openDatabaseSet->contains(database));
+ m_openDatabaseSet->add(database);
+}
+
+void ScriptExecutionContext::removeOpenDatabase(Database* database)
+{
+ ASSERT(isContextThread());
+ ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
+ if (!m_openDatabaseSet)
+ return;
+ m_openDatabaseSet->remove(database);
+}
+
+void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
+{
+ ASSERT(isContextThread());
+ if (m_openDatabaseSet) {
+ DatabaseSet::iterator i = m_openDatabaseSet->begin();
+ DatabaseSet::iterator end = m_openDatabaseSet->end();
+ for (; i != end; ++i) {
+ (*i)->stop();
+ if (m_databaseThread)
+ m_databaseThread->unscheduleDatabaseTasks(*i);
+ }
+ }
+
+ if (m_databaseThread)
+ m_databaseThread->requestTermination(cleanupSync);
+ else if (cleanupSync)
+ cleanupSync->taskCompleted();
+}
+
+#endif
+
void ScriptExecutionContext::processMessagePortMessagesSoon()
{
postTask(ProcessMessagesSoonTask::create());
diff --git a/WebCore/dom/ScriptExecutionContext.h b/WebCore/dom/ScriptExecutionContext.h
index cf332c3..709bc69 100644
--- a/WebCore/dom/ScriptExecutionContext.h
+++ b/WebCore/dom/ScriptExecutionContext.h
@@ -33,11 +33,17 @@
#include <wtf/HashSet.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
namespace WebCore {
class ActiveDOMObject;
+#if ENABLE(DATABASE)
+ class Database;
+ class DatabaseTaskSynchronizer;
+ class DatabaseThread;
+#endif
class DOMTimer;
class MessagePort;
class SecurityOrigin;
@@ -59,6 +65,19 @@ namespace WebCore {
virtual bool isDocument() const { return false; }
virtual bool isWorkerContext() const { return false; }
+#if ENABLE(DATABASE)
+ virtual bool isDatabaseReadOnly() const = 0;
+ virtual void databaseExceededQuota(const String& name) = 0;
+ DatabaseThread* databaseThread();
+ void setHasOpenDatabases() { m_hasOpenDatabases = true; }
+ bool hasOpenDatabases() const { return m_hasOpenDatabases; }
+ void addOpenDatabase(Database*);
+ void removeOpenDatabase(Database*);
+ // When the database cleanup is done, cleanupSync will be signalled.
+ void stopDatabases(DatabaseTaskSynchronizer*);
+#endif
+ virtual bool isContextThread() const = 0;
+
const KURL& url() const { return virtualURL(); }
KURL completeURL(const String& url) const { return virtualCompleteURL(url); }
@@ -97,6 +116,8 @@ namespace WebCore {
public:
virtual ~Task();
virtual void performTask(ScriptExecutionContext*) = 0;
+ // Certain tasks get marked specially so that they aren't discarded, and are executed, when the context is shutting down its message queue.
+ virtual bool isCleanupTask() const { return false; }
};
virtual void postTask(PassOwnPtr<Task>) = 0; // Executes the task on context's thread asynchronously.
@@ -129,6 +150,13 @@ namespace WebCore {
virtual void refScriptExecutionContext() = 0;
virtual void derefScriptExecutionContext() = 0;
+
+#if ENABLE(DATABASE)
+ RefPtr<DatabaseThread> m_databaseThread;
+ bool m_hasOpenDatabases; // This never changes back to false, even after the database thread is closed.
+ typedef HashSet<Database* > DatabaseSet;
+ OwnPtr<DatabaseSet> m_openDatabaseSet;
+#endif
};
} // namespace WebCore
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index a03a1b8..afa56e9 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -566,7 +566,7 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
#if ENABLE(DATABASE)
if (databasePolicy == DatabasePolicyStop)
- doc->stopDatabases();
+ doc->stopDatabases(0);
#else
UNUSED_PARAM(databasePolicy);
#endif
diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp
index 305f5f9..648492f 100644
--- a/WebCore/storage/Database.cpp
+++ b/WebCore/storage/Database.cpp
@@ -53,8 +53,8 @@
#include "SQLResultSet.h"
#include "SQLTransactionClient.h"
#include "SQLTransactionCoordinator.h"
-#include <wtf/MainThread.h>
-#endif
+
+#endif // ENABLE(DATABASE)
#if USE(JSC)
#include "JSDOMWindow.h"
@@ -73,6 +73,18 @@ const String& Database::databaseInfoTableName()
#if ENABLE(DATABASE)
+static bool isDatabaseAvailable = false;
+
+void Database::setIsAvailable(bool available)
+{
+ isDatabaseAvailable = available;
+}
+
+bool Database::isAvailable()
+{
+ return isDatabaseAvailable;
+}
+
static Mutex& guidMutex()
{
// Note: We don't have to use AtomicallyInitializedStatic here because
@@ -120,39 +132,41 @@ static const String& databaseVersionKey()
static int guidForOriginAndName(const String& origin, const String& name);
-PassRefPtr<Database> Database::openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
+PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
{
- if (!DatabaseTracker::tracker().canEstablishDatabase(document, name, displayName, estimatedSize)) {
+ if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
// FIXME: There should be an exception raised here in addition to returning a null Database object. The question has been raised with the WHATWG.
- LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), document->securityOrigin()->toString().ascii().data());
+ LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
return 0;
}
- RefPtr<Database> database = adoptRef(new Database(document, name, expectedVersion, displayName, estimatedSize));
+ RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize));
if (!database->openAndVerifyVersion(e)) {
LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
- document->removeOpenDatabase(database.get());
+ context->removeOpenDatabase(database.get());
DatabaseTracker::tracker().removeOpenDatabase(database.get());
return 0;
}
- DatabaseTracker::tracker().setDatabaseDetails(document->securityOrigin(), name, displayName, estimatedSize);
-
- document->setHasOpenDatabases();
+ DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+ context->setHasOpenDatabases();
#if ENABLE(INSPECTOR)
- if (Page* page = document->frame()->page())
- page->inspectorController()->didOpenDatabase(database.get(), document->securityOrigin()->host(), name, expectedVersion);
+ if (context->isDocument()) {
+ Document* document = static_cast<Document*>(context);
+ if (Page* page = document->page())
+ page->inspectorController()->didOpenDatabase(database.get(), context->securityOrigin()->host(), name, expectedVersion);
+ }
#endif
return database;
}
-Database::Database(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
+Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
: m_transactionInProgress(false)
, m_isTransactionQueueEnabled(true)
- , m_document(document)
+ , m_scriptExecutionContext(context)
, m_name(name.crossThreadString())
, m_guid(0)
, m_expectedVersion(expectedVersion.crossThreadString())
@@ -162,16 +176,15 @@ Database::Database(Document* document, const String& name, const String& expecte
, m_stopped(false)
, m_opened(false)
{
- ASSERT(document);
- m_mainThreadSecurityOrigin = document->securityOrigin();
+ ASSERT(m_scriptExecutionContext.get());
+ m_mainThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
m_databaseThreadSecurityOrigin = m_mainThreadSecurityOrigin->threadsafeCopy();
-
if (m_name.isNull())
m_name = "";
ScriptController::initializeThreading();
- m_guid = guidForOriginAndName(m_mainThreadSecurityOrigin->toString(), name);
+ m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
{
MutexLocker locker(guidMutex());
@@ -185,28 +198,40 @@ Database::Database(Document* document, const String& name, const String& expecte
hashSet->add(this);
}
- ASSERT(m_document->databaseThread());
-
- m_filename = DatabaseTracker::tracker().fullPathForDatabase(m_mainThreadSecurityOrigin.get(), m_name);
+ ASSERT(m_scriptExecutionContext->databaseThread());
+ m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
DatabaseTracker::tracker().addOpenDatabase(this);
- m_document->addOpenDatabase(this);
+ context->addOpenDatabase(this);
}
-static void derefDocument(void* document)
-{
- static_cast<Document*>(document)->deref();
-}
+class DerefContextTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DerefContextTask> create()
+ {
+ return new DerefContextTask();
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ context->deref();
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+};
Database::~Database()
{
- // Deref m_document on the main thread.
- callOnMainThread(derefDocument, m_document.release().releaseRef());
+ // The reference to the ScriptExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing.
+ if (!m_scriptExecutionContext->isContextThread()) {
+ m_scriptExecutionContext->postTask(DerefContextTask::create());
+ m_scriptExecutionContext.release().releaseRef();
+ }
}
bool Database::openAndVerifyVersion(ExceptionCode& e)
{
- if (!m_document->databaseThread())
+ if (!m_scriptExecutionContext->databaseThread())
return false;
m_databaseAuthorizer = DatabaseAuthorizer::create();
@@ -214,7 +239,7 @@ bool Database::openAndVerifyVersion(ExceptionCode& e)
DatabaseTaskSynchronizer synchronizer;
OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success);
- m_document->databaseThread()->scheduleImmediateTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
return success;
@@ -309,43 +334,62 @@ bool Database::versionMatchesExpected() const
void Database::markAsDeletedAndClose()
{
- if (m_deleted || !m_document->databaseThread())
+ if (m_deleted || !m_scriptExecutionContext->databaseThread())
return;
LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
m_deleted = true;
- if (m_document->databaseThread()->terminationRequested()) {
+ if (m_scriptExecutionContext->databaseThread()->terminationRequested()) {
LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
return;
}
- m_document->databaseThread()->unscheduleDatabaseTasks(this);
+ m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
DatabaseTaskSynchronizer synchronizer;
OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
- m_document->databaseThread()->scheduleImmediateTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
}
-static void documentRemoveOpenDatabase(void* context)
-{
- ASSERT(isMainThread());
- Database* database = static_cast<Database*>(context);
- database->document()->removeOpenDatabase(database);
- database->deref();
-}
+class ContextRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<ContextRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
+ {
+ return new ContextRemoveOpenDatabaseTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ context->removeOpenDatabase(m_database.get());
+ DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+
+private:
+ ContextRemoveOpenDatabaseTask(PassRefPtr<Database> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<Database> m_database;
+};
void Database::close()
{
+ RefPtr<Database> protect = this;
+
if (!m_opened)
return;
- ASSERT(m_document->databaseThread());
- ASSERT(currentThread() == document()->databaseThread()->getThreadID());
+ ASSERT(m_scriptExecutionContext->databaseThread());
+ ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
m_sqliteDatabase.close();
- m_document->databaseThread()->recordDatabaseClosed(this);
+ // Must ref() before calling databaseThread()->recordDatabaseClosed().
+ m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this);
m_opened = false;
{
@@ -362,11 +406,8 @@ void Database::close()
}
}
- m_document->databaseThread()->unscheduleDatabaseTasks(this);
-
- DatabaseTracker::tracker().removeOpenDatabase(this);
- ref(); // deref() called in documentRemoveOpenDatabase()
- callOnMainThread(documentRemoveOpenDatabase, this);
+ m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
+ m_scriptExecutionContext->postTask(ContextRemoveOpenDatabaseTask::create(this));
}
void Database::stop()
@@ -532,8 +573,8 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
// All checks passed and we still have a handle to this database file.
// Make sure DatabaseThread closes it when DatabaseThread goes away.
m_opened = true;
- if (m_document->databaseThread())
- m_document->databaseThread()->recordDatabaseOpen(this);
+ if (m_scriptExecutionContext->databaseThread())
+ m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
return true;
}
@@ -567,32 +608,52 @@ void Database::scheduleTransaction()
m_transactionQueue.removeFirst();
}
- if (transaction && m_document->databaseThread()) {
+ if (transaction && m_scriptExecutionContext->databaseThread()) {
OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
m_transactionInProgress = true;
- m_document->databaseThread()->scheduleTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
} else
m_transactionInProgress = false;
}
void Database::scheduleTransactionStep(SQLTransaction* transaction, bool immediately)
{
- if (!m_document->databaseThread())
+ if (!m_scriptExecutionContext->databaseThread())
return;
OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
if (immediately)
- m_document->databaseThread()->scheduleImmediateTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
else
- m_document->databaseThread()->scheduleTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
}
+class DeliverPendingCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction)
+ {
+ return new DeliverPendingCallbackTask(transaction);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_transaction->performPendingCallback();
+ }
+
+private:
+ DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)
+ : m_transaction(transaction)
+ {
+ }
+
+ RefPtr<SQLTransaction> m_transaction;
+};
+
void Database::scheduleTransactionCallback(SQLTransaction* transaction)
{
- transaction->ref();
- callOnMainThread(deliverPendingCallback, transaction);
+ m_scriptExecutionContext->postTask(DeliverPendingCallbackTask::create(transaction));
}
Vector<String> Database::performGetTableNames()
@@ -626,12 +687,12 @@ Vector<String> Database::performGetTableNames()
SQLTransactionClient* Database::transactionClient() const
{
- return m_document->databaseThread()->transactionClient();
+ return m_scriptExecutionContext->databaseThread()->transactionClient();
}
SQLTransactionCoordinator* Database::transactionCoordinator() const
{
- return m_document->databaseThread()->transactionCoordinator();
+ return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
}
String Database::version() const
@@ -642,25 +703,18 @@ String Database::version() const
return guidToVersionMap().get(m_guid).threadsafeCopy();
}
-void Database::deliverPendingCallback(void* context)
-{
- SQLTransaction* transaction = static_cast<SQLTransaction*>(context);
- transaction->performPendingCallback();
- transaction->deref(); // Was ref'd in scheduleTransactionCallback().
-}
-
Vector<String> Database::tableNames()
{
// FIXME: Not using threadsafeCopy on these strings looks ok since threads take strict turns
// in dealing with them. However, if the code changes, this may not be true anymore.
Vector<String> result;
- if (!m_document->databaseThread())
+ if (!m_scriptExecutionContext->databaseThread())
return result;
DatabaseTaskSynchronizer synchronizer;
OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
- m_document->databaseThread()->scheduleImmediateTask(task.release());
+ m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
return result;
@@ -676,9 +730,9 @@ void Database::setExpectedVersion(const String& version)
SecurityOrigin* Database::securityOrigin() const
{
- if (isMainThread())
+ if (scriptExecutionContext()->isContextThread())
return m_mainThreadSecurityOrigin.get();
- if (currentThread() == document()->databaseThread()->getThreadID())
+ if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID())
return m_databaseThreadSecurityOrigin.get();
return 0;
}
@@ -706,6 +760,6 @@ String Database::fileName() const
return m_filename.threadsafeCopy();
}
-#endif
+#endif // ENABLE(DATABASE)
-}
+} // namespace WebCore
diff --git a/WebCore/storage/Database.h b/WebCore/storage/Database.h
index 61c9b66..0d7f33c 100644
--- a/WebCore/storage/Database.h
+++ b/WebCore/storage/Database.h
@@ -52,7 +52,7 @@ namespace WebCore {
class DatabaseAuthorizer;
class DatabaseThread;
-class Document;
+class ScriptExecutionContext;
class SQLResultSet;
class SQLTransactionCallback;
class SQLTransactionClient;
@@ -67,10 +67,13 @@ class Database : public ThreadSafeShared<Database> {
friend class SQLStatement;
friend class SQLTransaction;
public:
+ static void setIsAvailable(bool);
+ static bool isAvailable();
+
~Database();
// Direct support for the DOM API
- static PassRefPtr<Database> openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
+ static PassRefPtr<Database> openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
String version() const;
void changeVersion(const String& oldVersion, const String& newVersion,
PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
@@ -87,7 +90,7 @@ public:
Vector<String> tableNames();
- Document* document() const { return m_document.get(); }
+ ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); }
SecurityOrigin* securityOrigin() const;
String stringIdentifier() const;
String displayName() const;
@@ -123,8 +126,9 @@ public:
SQLTransactionCoordinator* transactionCoordinator() const;
private:
- Database(Document* document, const String& name, const String& expectedVersion,
- const String& displayName, unsigned long estimatedSize);
+ Database(ScriptExecutionContext* context, const String& name,
+ const String& expectedVersion, const String& displayName,
+ unsigned long estimatedSize);
bool openAndVerifyVersion(ExceptionCode&);
@@ -139,7 +143,7 @@ private:
static void deliverPendingCallback(void*);
- RefPtr<Document> m_document;
+ RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
RefPtr<SecurityOrigin> m_mainThreadSecurityOrigin;
RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
String m_name;
diff --git a/WebCore/storage/DatabaseTask.h b/WebCore/storage/DatabaseTask.h
index 97a23c7..998e373 100644
--- a/WebCore/storage/DatabaseTask.h
+++ b/WebCore/storage/DatabaseTask.h
@@ -50,16 +50,15 @@ class VersionChangeCallback;
// Can be used to wait until DatabaseTask is completed.
// Has to be passed into DatabaseTask::create to be associated with the task.
class DatabaseTaskSynchronizer : public Noncopyable {
- friend class DatabaseTask;
public:
DatabaseTaskSynchronizer();
// Called from main thread to wait until task is completed.
void waitForTaskCompletion();
-private:
// Called by the task.
void taskCompleted();
+private:
bool m_taskCompleted;
Mutex m_synchronousMutex;
diff --git a/WebCore/storage/DatabaseThread.cpp b/WebCore/storage/DatabaseThread.cpp
index 12e9251..ec4c6d1 100644
--- a/WebCore/storage/DatabaseThread.cpp
+++ b/WebCore/storage/DatabaseThread.cpp
@@ -44,6 +44,7 @@ DatabaseThread::DatabaseThread()
: m_threadID(0)
, m_transactionClient(new SQLTransactionClient())
, m_transactionCoordinator(new SQLTransactionCoordinator())
+ , m_cleanupSync(0)
{
m_selfRef = this;
}
@@ -51,6 +52,7 @@ DatabaseThread::DatabaseThread()
DatabaseThread::~DatabaseThread()
{
// FIXME: Any cleanup required here? Since the thread deletes itself after running its detached course, I don't think so. Lets be sure.
+ ASSERT(terminationRequested());
}
bool DatabaseThread::start()
@@ -65,8 +67,10 @@ bool DatabaseThread::start()
return m_threadID;
}
-void DatabaseThread::requestTermination()
+void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
{
+ ASSERT(!m_cleanupSync);
+ m_cleanupSync = cleanupSync;
LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
m_queue.kill();
}
@@ -115,9 +119,14 @@ void* DatabaseThread::databaseThread()
// Detach the thread so its resources are no longer of any concern to anyone else
detachThread(m_threadID);
+ DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;
+
// Clear the self refptr, possibly resulting in deletion
m_selfRef = 0;
+ if (cleanupSync) // Someone wanted to know when we were done cleaning up.
+ cleanupSync->taskCompleted();
+
return 0;
}
@@ -162,6 +171,5 @@ void DatabaseThread::unscheduleDatabaseTasks(Database* database)
SameDatabasePredicate predicate(database);
m_queue.removeIf(predicate);
}
-
} // namespace WebCore
#endif
diff --git a/WebCore/storage/DatabaseThread.h b/WebCore/storage/DatabaseThread.h
index 269a633..3702619 100644
--- a/WebCore/storage/DatabaseThread.h
+++ b/WebCore/storage/DatabaseThread.h
@@ -43,6 +43,7 @@ namespace WebCore {
class Database;
class DatabaseTask;
+class DatabaseTaskSynchronizer;
class Document;
class SQLTransactionClient;
class SQLTransactionCoordinator;
@@ -53,7 +54,7 @@ public:
~DatabaseThread();
bool start();
- void requestTermination();
+ void requestTermination(DatabaseTaskSynchronizer* cleanupSync);
bool terminationRequested() const;
void scheduleTask(PassOwnPtr<DatabaseTask>);
@@ -85,6 +86,7 @@ private:
OwnPtr<SQLTransactionClient> m_transactionClient;
OwnPtr<SQLTransactionCoordinator> m_transactionCoordinator;
+ DatabaseTaskSynchronizer* m_cleanupSync;
};
} // namespace WebCore
diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp
index 7ab6233..bed83a7 100644
--- a/WebCore/storage/DatabaseTracker.cpp
+++ b/WebCore/storage/DatabaseTracker.cpp
@@ -36,10 +36,10 @@
#include "Database.h"
#include "DatabaseThread.h"
#include "DatabaseTrackerClient.h"
-#include "Document.h"
#include "Logging.h"
#include "OriginQuotaManager.h"
#include "Page.h"
+#include "ScriptExecutionContext.h"
#include "SecurityOrigin.h"
#include "SecurityOriginHash.h"
#include "SQLiteFileSystem.h"
@@ -120,7 +120,7 @@ void DatabaseTracker::openTrackerDatabase(bool createIfDoesNotExist)
}
}
-bool DatabaseTracker::canEstablishDatabase(Document* document, const String& name, const String& displayName, unsigned long estimatedSize)
+bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize)
{
ASSERT(currentThread() == m_thread);
@@ -128,9 +128,9 @@ bool DatabaseTracker::canEstablishDatabase(Document* document, const String& nam
// can run on the database thread later.
populateOrigins();
- SecurityOrigin* origin = document->securityOrigin();
+ SecurityOrigin* origin = context->securityOrigin();
- // Since we're imminently opening a database within this Document's origin, make sure this origin is being tracked by the QuotaTracker
+ // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker
// by fetching it's current usage now
unsigned long long usage = usageForOrigin(origin);
@@ -147,12 +147,9 @@ bool DatabaseTracker::canEstablishDatabase(Document* document, const String& nam
// Give the chrome client a chance to increase the quota.
// Temporarily make the details of the proposed database available, so the client can get at them.
- Page* page = document->page();
- if (!page)
- return false;
pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0));
m_proposedDatabase = &details;
- page->chrome()->client()->exceededDatabaseQuota(document->frame(), name);
+ context->databaseExceededQuota(name);
m_proposedDatabase = 0;
// If the database will fit now, allow its creation.
@@ -186,7 +183,7 @@ bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
{
- ASSERT(currentThread() == database->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
// The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
// plus the current usage of the given database
Locker<OriginQuotaManager> locker(originQuotaManager());
diff --git a/WebCore/storage/DatabaseTracker.h b/WebCore/storage/DatabaseTracker.h
index fbcadfc..38a3418 100644
--- a/WebCore/storage/DatabaseTracker.h
+++ b/WebCore/storage/DatabaseTracker.h
@@ -45,7 +45,7 @@
namespace WebCore {
class Database;
-class Document;
+class ScriptExecutionContext;
class SecurityOrigin;
#if !PLATFORM(CHROMIUM)
@@ -59,8 +59,11 @@ struct SecurityOriginTraits;
class DatabaseTracker : public Noncopyable {
public:
static DatabaseTracker& tracker();
+ // FIXME: Due to workers having multiple threads in a single process sharing
+ // a DatabaseTracker, this singleton will have to be synchronized or moved
+ // to TLS.
- bool canEstablishDatabase(Document*, const String& name, const String& displayName, unsigned long estimatedSize);
+ bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize);
void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize);
String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true);
diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp
index 165685b..de615ca 100644
--- a/WebCore/storage/SQLTransaction.cpp
+++ b/WebCore/storage/SQLTransaction.cpp
@@ -35,11 +35,11 @@
#include "Database.h"
#include "DatabaseAuthorizer.h"
#include "DatabaseDetails.h"
-#include "Document.h"
#include "ExceptionCode.h"
#include "Logging.h"
#include "Page.h"
#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
#include "Settings.h"
#include "SQLError.h"
#include "SQLiteTransaction.h"
@@ -94,8 +94,7 @@ void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValu
bool readOnlyMode = m_readOnly;
if (!readOnlyMode) {
- Page* page = m_database->document()->page();
- if (!page || page->settings()->privateBrowsingEnabled())
+ if (m_database->scriptExecutionContext()->isDatabaseReadOnly())
readOnlyMode = true;
}
diff --git a/WebCore/storage/SQLTransactionClient.cpp b/WebCore/storage/SQLTransactionClient.cpp
index 6ef2e14..6064c99 100644
--- a/WebCore/storage/SQLTransactionClient.cpp
+++ b/WebCore/storage/SQLTransactionClient.cpp
@@ -47,7 +47,7 @@ namespace WebCore {
void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
{
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
Database* database = transaction->database();
DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
database->securityOrigin(), database->stringIdentifier());
@@ -55,7 +55,7 @@ void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
{
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
Locker<OriginQuotaManager> locker(manager);
manager.markDatabase(transaction->database());
@@ -63,13 +63,11 @@ void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
{
- ASSERT(isMainThread());
+ ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
Database* database = transaction->database();
- Page* page = database->document()->page();
- ASSERT(page);
unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
- page->chrome()->client()->exceededDatabaseQuota(database->document()->frame(), database->stringIdentifier());
+ database->scriptExecutionContext()->databaseExceededQuota(database->stringIdentifier());
unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
return (newQuota > currentQuota);
}
diff --git a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
index 523a3b5..e18706b 100644
--- a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
+++ b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
@@ -35,8 +35,8 @@
#include "Database.h"
#include "DatabaseObserver.h"
#include "DatabaseThread.h"
-#include "Document.h"
#include "QuotaTracker.h"
+#include "ScriptExecutionContext.h"
#include "SecurityOrigin.h"
#include "SQLiteFileSystem.h"
#include <wtf/HashSet.h>
@@ -56,7 +56,7 @@ DatabaseTracker::DatabaseTracker()
SQLiteFileSystem::registerSQLiteVFS();
}
-bool DatabaseTracker::canEstablishDatabase(Document*, const String&, const String&, unsigned long)
+bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long)
{
// In Chromium, a database can always be established (even though we might not
// be able to write anything to it if the quota for this origin was exceeded)
@@ -75,21 +75,35 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
void DatabaseTracker::addOpenDatabase(Database* database)
{
- ASSERT(isMainThread());
+ ASSERT(database->scriptExecutionContext()->isContextThread());
DatabaseObserver::databaseOpened(database);
}
-static void removeOpenDatabaseOnMainThread(void* context)
-{
- Database* database = static_cast<Database*>(context);
- DatabaseTracker::tracker().removeOpenDatabase(database);
- database->deref();
-}
+
+class TrackerRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
+ {
+ return new TrackerRemoveOpenDatabaseTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
+ }
+
+private:
+ TrackerRemoveOpenDatabaseTask(PassRefPtr<Database> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<Database> m_database;
+};
void DatabaseTracker::removeOpenDatabase(Database* database)
{
- if (!isMainThread()) {
- database->ref();
- callOnMainThread(removeOpenDatabaseOnMainThread, database);
+ if (!database->scriptExecutionContext()->isContextThread()) {
+ database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database));
return;
}
@@ -98,7 +112,7 @@ void DatabaseTracker::removeOpenDatabase(Database* database)
unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
{
- ASSERT(currentThread() == database->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
unsigned long long spaceAvailable = 0;
unsigned long long databaseSize = 0;
QuotaTracker::instance().getDatabaseSizeAndSpaceAvailableToOrigin(
diff --git a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
index 46d73ba..a10ca3e 100644
--- a/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
+++ b/WebCore/storage/chromium/SQLTransactionClientChromium.cpp
@@ -38,20 +38,34 @@
#include "SQLTransaction.h"
#include <wtf/MainThread.h>
-static void notifyDatabaseChanged(void* context) {
- WebCore::Database* database = static_cast<WebCore::Database*>(context);
- WebCore::DatabaseObserver::databaseModified(database);
- database->deref(); // ref()'d in didCommitTransaction()
-}
-
namespace WebCore {
+class NotifyDatabaseChangedTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<NotifyDatabaseChangedTask> create(Database *database)
+ {
+ return new NotifyDatabaseChangedTask(database);
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ WebCore::DatabaseObserver::databaseModified(m_database.get());
+ }
+
+private:
+ NotifyDatabaseChangedTask(PassRefPtr<Database> database)
+ : m_database(database)
+ {
+ }
+
+ RefPtr<Database> m_database;
+};
+
void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
{
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
if (!transaction->isReadOnly()) {
- transaction->database()->ref(); // deref()'d in notifyDatabaseChanged()
- callOnMainThread(notifyDatabaseChanged, transaction->database());
+ transaction->database()->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(transaction->database()));
}
}
@@ -59,14 +73,14 @@ void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
{
// This method is called after executing every statement that changes the DB.
// Chromium doesn't need to do anything at that point.
- ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
}
-bool SQLTransactionClient::didExceedQuota(SQLTransaction*)
+bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
{
// Chromium does not allow users to manually change the quota for an origin (for now, at least).
// Don't do anything.
- ASSERT(isMainThread());
+ ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
return false;
}
diff --git a/WebCore/workers/WorkerContext.cpp b/WebCore/workers/WorkerContext.cpp
index e823278..0ec24e6 100644
--- a/WebCore/workers/WorkerContext.cpp
+++ b/WebCore/workers/WorkerContext.cpp
@@ -32,6 +32,7 @@
#include "WorkerContext.h"
#include "ActiveDOMObject.h"
+#include "Database.h"
#include "DOMTimer.h"
#include "DOMWindow.h"
#include "Event.h"
@@ -254,6 +255,27 @@ NotificationCenter* WorkerContext::webkitNotifications() const
}
#endif
+#if ENABLE(DATABASE)
+PassRefPtr<Database> WorkerContext::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec)
+{
+ if (!securityOrigin()->canAccessDatabase()) {
+ ec = SECURITY_ERR;
+ return 0;
+ }
+
+ ASSERT(Database::isAvailable());
+ if (!Database::isAvailable())
+ return 0;
+
+ return Database::openDatabase(this, name, version, displayName, estimatedSize, ec);
+}
+#endif
+
+bool WorkerContext::isContextThread() const
+{
+ return currentThread() == thread()->threadID();
+}
+
EventTargetData* WorkerContext::eventTargetData()
{
return &m_eventTargetData;
diff --git a/WebCore/workers/WorkerContext.h b/WebCore/workers/WorkerContext.h
index f37d42c..a795947 100644
--- a/WebCore/workers/WorkerContext.h
+++ b/WebCore/workers/WorkerContext.h
@@ -30,11 +30,13 @@
#if ENABLE(WORKERS)
#include "AtomicStringHash.h"
+#include "Database.h"
#include "EventListener.h"
#include "EventNames.h"
#include "EventTarget.h"
#include "ScriptExecutionContext.h"
#include "WorkerScriptController.h"
+#include <wtf/Assertions.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -42,6 +44,7 @@
namespace WebCore {
+ class Database;
class NotificationCenter;
class ScheduledAction;
class WorkerLocation;
@@ -65,9 +68,9 @@ namespace WebCore {
virtual String userAgent(const KURL&) const;
WorkerScriptController* script() { return m_script.get(); }
- void clearScript() { return m_script.clear(); }
+ void clearScript() { m_script.clear(); }
- WorkerThread* thread() { return m_thread; }
+ WorkerThread* thread() const { return m_thread; }
bool hasPendingActivity() const;
@@ -101,6 +104,17 @@ namespace WebCore {
NotificationCenter* webkitNotifications() const;
#endif
+#if ENABLE(DATABASE)
+ // HTML 5 client-side database
+ PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
+ // Not implemented yet.
+ virtual bool isDatabaseReadOnly() const { return false; }
+ // Not implemented yet.
+ virtual void databaseExceededQuota(const String&) { }
+#endif
+ virtual bool isContextThread() const;
+
+
// These methods are used for GC marking. See JSWorkerContext::markChildren(MarkStack&) in
// JSWorkerContextCustom.cpp.
WorkerNavigator* optionalNavigator() const { return m_navigator.get(); }
diff --git a/WebCore/workers/WorkerRunLoop.cpp b/WebCore/workers/WorkerRunLoop.cpp
index 445fa65..83f243f 100644
--- a/WebCore/workers/WorkerRunLoop.cpp
+++ b/WebCore/workers/WorkerRunLoop.cpp
@@ -152,9 +152,7 @@ MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const Mo
MessageQueueWaitResult result;
OwnPtr<WorkerRunLoop::Task> task = m_messageQueue.waitForMessageFilteredWithTimeout(result, predicate, absoluteTime);
- // If the context is closing, don't dispatch any further tasks (per section 4.1.1 of the Web Workers spec).
- if (context->isClosing())
- return result;
+ // If the context is closing, don't execute any further JavaScript tasks (per section 4.1.1 of the Web Workers spec). However, there may be implementation cleanup tasks in the queue, so keep running through it.
switch (result) {
case MessageQueueTerminated:
@@ -165,7 +163,8 @@ MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const Mo
break;
case MessageQueueTimeout:
- m_sharedTimer->fire();
+ if (!context->isClosing())
+ m_sharedTimer->fire();
break;
}
@@ -194,7 +193,9 @@ PassOwnPtr<WorkerRunLoop::Task> WorkerRunLoop::Task::create(PassOwnPtr<ScriptExe
void WorkerRunLoop::Task::performTask(ScriptExecutionContext* context)
{
- m_task->performTask(context);
+ WorkerContext* workerContext = static_cast<WorkerContext *>(context);
+ if (!workerContext->isClosing() || m_task->isCleanupTask())
+ m_task->performTask(context);
}
WorkerRunLoop::Task::Task(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
diff --git a/WebCore/workers/WorkerThread.cpp b/WebCore/workers/WorkerThread.cpp
index 467157b..fbeb95b 100644
--- a/WebCore/workers/WorkerThread.cpp
+++ b/WebCore/workers/WorkerThread.cpp
@@ -30,6 +30,7 @@
#include "WorkerThread.h"
+#include "DatabaseTask.h"
#include "DedicatedWorkerContext.h"
#include "KURL.h"
#include "PlatformString.h"
@@ -135,9 +136,8 @@ void* WorkerThread::workerThread()
ThreadIdentifier threadID = m_threadID;
- m_workerContext->stopActiveDOMObjects();
- m_workerContext->clearScript();
ASSERT(m_workerContext->hasOneRef());
+
// The below assignment will destroy the context, which will in turn notify messaging proxy.
// We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
m_workerContext = 0;
@@ -154,17 +154,70 @@ void WorkerThread::runEventLoop()
m_runLoop.run(m_workerContext.get());
}
+class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
+ {
+ return new WorkerThreadShutdownFinishTask();
+ }
+
+ virtual void performTask(ScriptExecutionContext *context)
+ {
+ ASSERT(context->isWorkerContext());
+ WorkerContext* workerContext = static_cast<WorkerContext*>(context);
+ workerContext->thread()->runLoop().terminate();
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+};
+
+class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<WorkerThreadShutdownStartTask> create()
+ {
+ return new WorkerThreadShutdownStartTask();
+ }
+
+ virtual void performTask(ScriptExecutionContext *context)
+ {
+ ASSERT(context->isWorkerContext());
+ WorkerContext* workerContext = static_cast<WorkerContext*>(context);
+
+ // We currently ignore any DatabasePolicy used for the document's
+ // databases; if it's actually used anywhere, this should be revisited.
+ DatabaseTaskSynchronizer cleanupSync;
+ workerContext->stopDatabases(&cleanupSync);
+
+ workerContext->stopActiveDOMObjects();
+ workerContext->clearScript();
+
+ // We wait for the database thread to clean up all its stuff so that we
+ // can do more stringent leak checks as we exit.
+ cleanupSync.waitForTaskCompletion();
+
+ // Stick a shutdown command at the end of the queue, so that we deal
+ // with all the cleanup tasks the databases post first.
+ workerContext->postTask(WorkerThreadShutdownFinishTask::create());
+ }
+
+ virtual bool isCleanupTask() const { return true; }
+};
+
void WorkerThread::stop()
{
// Mutex protection is necessary because stop() can be called before the context is fully created.
MutexLocker lock(m_threadCreationMutex);
// Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
- if (m_workerContext)
+ if (m_workerContext) {
m_workerContext->script()->forbidExecution();
// FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction.
- m_runLoop.terminate();
+ // This can likely use the same mechanism as used for databases above.
+
+ m_runLoop.postTask(WorkerThreadShutdownStartTask::create());
+ } else
+ m_runLoop.terminate();
}
} // namespace WebCore
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list