Diff
Modified: trunk/Source/WebCore/ChangeLog (141165 => 141166)
--- trunk/Source/WebCore/ChangeLog 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/ChangeLog 2013-01-29 22:51:31 UTC (rev 141166)
@@ -1,3 +1,76 @@
+2013-01-29 Mark Lam <mark....@apple.com>
+
+ Change DatabaseContext lookup to be thread-safe.
+ https://bugs.webkit.org/show_bug.cgi?id=107784.
+
+ Reviewed by Geoffrey Garen.
+
+ DatabaseContext will no longer be a Supplement of ScriptExecutionContext.
+ Instead we will maintain a mutex guarded contextMap in the DatabaseManager
+ which maps ScriptExecutionContexts to DatabaseContexts.
+
+ Also cleaned up the shutdown mechanism of the DatabaseContext,
+ DatabaseThread, and Databases when their owner ScriptExecutionContext
+ destructs.
+
+ No new tests.
+
+ * Modules/webdatabase/AbstractDatabase.cpp:
+ (WebCore::AbstractDatabase::AbstractDatabase):
+ * Modules/webdatabase/AbstractDatabase.h:
+ (WebCore::AbstractDatabase::databaseContext):
+ (AbstractDatabase):
+ * Modules/webdatabase/Database.cpp:
+ (WebCore::Database::Database):
+ * Modules/webdatabase/Database.h:
+ (WebCore):
+ (Database):
+ * Modules/webdatabase/DatabaseContext.cpp:
+ (WebCore):
+ (WebCore::DatabaseContext::DatabaseContext):
+ (WebCore::DatabaseContext::~DatabaseContext):
+ (WebCore::DatabaseContext::contextDestroyed):
+ (WebCore::DatabaseContext::stop):
+ (WebCore::DatabaseContext::databaseThread):
+ (WebCore::DatabaseContext::stopDatabases):
+ * Modules/webdatabase/DatabaseContext.h:
+ (DatabaseContext):
+ (WebCore::DatabaseContext::scriptExecutionContext):
+ (WebCore::DatabaseContext::hasOpenDatabases):
+ (WebCore::DatabaseContext::stopDatabases):
+ * Modules/webdatabase/DatabaseManager.cpp:
+ (WebCore::DatabaseManager::manager):
+ (WebCore::DatabaseManager::DatabaseManager):
+ (WebCore::DatabaseManager::getExistingDatabaseContext):
+ (WebCore):
+ (WebCore::DatabaseManager::getDatabaseContext):
+ (WebCore::DatabaseManager::registerDatabaseContext):
+ (WebCore::DatabaseManager::unregisterDatabaseContext):
+ (WebCore::DatabaseManager::notifyDatabaseContextConstructed):
+ (WebCore::DatabaseManager::notifyDatabaseContextDestructed):
+ (WebCore::DatabaseManager::openDatabase):
+ (WebCore::DatabaseManager::openDatabaseSync):
+ (WebCore::DatabaseManager::hasOpenDatabases):
+ (WebCore::DatabaseManager::stopDatabases):
+ (WebCore::DatabaseManager::interruptAllDatabasesForContext):
+ * Modules/webdatabase/DatabaseManager.h:
+ (WebCore):
+ (DatabaseManager):
+ (WebCore::DatabaseManager::notifyDatabaseContextConstructed):
+ (WebCore::DatabaseManager::notifyDatabaseContextDestructed):
+ * Modules/webdatabase/DatabaseSync.cpp:
+ (WebCore::DatabaseSync::DatabaseSync):
+ * Modules/webdatabase/DatabaseSync.h:
+ (WebCore):
+ (DatabaseSync):
+ * Modules/webdatabase/DatabaseThread.cpp:
+ (WebCore::DatabaseThread::~DatabaseThread):
+ (WebCore::DatabaseThread::requestTermination):
+ * Modules/webdatabase/DatabaseTracker.cpp:
+ (WebCore::DatabaseTracker::canEstablishDatabase):
+ * dom/ActiveDOMObject.cpp:
+ (WebCore::ActiveDOMObject::~ActiveDOMObject):
+
2013-01-29 Julien Chaffraix <jchaffr...@webkit.org>
[CSS Grid Layout] Make resolveContentBasedTrackSizingFunctionsForItems reuse distributeSpaceToTracks
Modified: trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -174,10 +174,10 @@
return infoTableName;
}
-AbstractDatabase::AbstractDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
+AbstractDatabase::AbstractDatabase(PassRefPtr<DatabaseContext> databaseContext, const String& name, const String& expectedVersion,
const String& displayName, unsigned long estimatedSize, DatabaseType databaseType)
- : m_scriptExecutionContext(context)
- , m_databaseContext(DatabaseContext::from(context))
+ : m_databaseContext(databaseContext)
+ , m_scriptExecutionContext(m_databaseContext->scriptExecutionContext())
, m_name(name.isolatedCopy())
, m_expectedVersion(expectedVersion.isolatedCopy())
, m_displayName(displayName.isolatedCopy())
@@ -187,7 +187,7 @@
, m_new(false)
, m_isSyncDatabase(databaseType == SyncDatabase)
{
- ASSERT(context->isContextThread());
+ ASSERT(m_databaseContext->scriptExecutionContext()->isContextThread());
m_contextThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin()->isolatedCopy();
m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName);
Modified: trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.h (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.h 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/AbstractDatabase.h 2013-01-29 22:51:31 UTC (rev 141166)
@@ -35,6 +35,7 @@
#include "DatabaseDetails.h"
#include "SQLiteDatabase.h"
#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/text/WTFString.h>
@@ -86,7 +87,7 @@
virtual void markAsDeletedAndClose() = 0;
virtual void closeImmediately() = 0;
- DatabaseContext* databaseContext() const { return m_databaseContext; }
+ DatabaseContext* databaseContext() const { return m_databaseContext.get(); }
protected:
friend class ChangeVersionWrapper;
@@ -100,7 +101,7 @@
SyncDatabase
};
- AbstractDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ AbstractDatabase(PassRefPtr<DatabaseContext>, const String& name, const String& expectedVersion,
const String& displayName, unsigned long estimatedSize, DatabaseType);
void closeDatabase();
@@ -127,8 +128,8 @@
static const char* databaseInfoTableName();
RefPtr<SecurityOrigin> m_contextThreadSecurityOrigin;
+ RefPtr<DatabaseContext> m_databaseContext; // Associated with m_scriptExecutionContext.
RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
- DatabaseContext* m_databaseContext; // Owned by m_scriptExecutionContext.
String m_name;
String m_expectedVersion;
Modified: trunk/Source/WebCore/Modules/webdatabase/Database.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/Database.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/Database.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -65,8 +65,8 @@
namespace WebCore {
-Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
- : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize, AsyncDatabase)
+Database::Database(PassRefPtr<DatabaseContext> databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
+ : AbstractDatabase(databaseContext, name, expectedVersion, displayName, estimatedSize, AsyncDatabase)
, m_transactionInProgress(false)
, m_isTransactionQueueEnabled(true)
, m_deleted(false)
@@ -74,7 +74,7 @@
m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy();
ScriptController::initializeThreading();
- ASSERT(databaseContext()->databaseThread());
+ ASSERT(m_databaseContext->databaseThread());
}
class DerefContextTask : public ScriptExecutionContext::Task {
Modified: trunk/Source/WebCore/Modules/webdatabase/Database.h (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/Database.h 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/Database.h 2013-01-29 22:51:31 UTC (rev 141166)
@@ -40,7 +40,6 @@
namespace WebCore {
class DatabaseCallback;
-class ScriptExecutionContext;
class SecurityOrigin;
class SQLTransaction;
class SQLTransactionCallback;
@@ -87,7 +86,7 @@
class DatabaseTransactionTask;
class DatabaseTableNamesTask;
- Database(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ Database(PassRefPtr<DatabaseContext>, const String& name, const String& expectedVersion,
const String& displayName, unsigned long estimatedSize);
void runTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper>, bool readOnly);
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -44,44 +44,68 @@
namespace WebCore {
-const char* DatabaseContext::supplementName()
+DatabaseContext::DatabaseContext(ScriptExecutionContext* context)
+ : ActiveDOMObject(context, this)
+ , m_hasOpenDatabases(false)
+ , m_isRegistered(true) // will register on construction below.
+ , m_hasRequestedTermination(false)
{
- return "DatabaseContext";
+ // ActiveDOMObject expects this to be called to set internal flags.
+ suspendIfNeeded();
+
+ // For debug accounting only. We must do this before we register the
+ // instance. The assertions assume this.
+ DatabaseManager::manager().didConstructDatabaseContext();
+
+ DatabaseManager::manager().registerDatabaseContext(this);
}
-DatabaseContext* DatabaseContext::existingDatabaseContextFrom(ScriptExecutionContext* context)
+DatabaseContext::~DatabaseContext()
{
- return static_cast<DatabaseContext*>(Supplement<ScriptExecutionContext>::from(context, supplementName()));
+ stopDatabases();
+ ASSERT(!m_databaseThread || m_databaseThread->terminationRequested());
+
+ // For debug accounting only. We must call this last. The assertions assume
+ // this.
+ DatabaseManager::manager().didDestructDatabaseContext();
}
-DatabaseContext::DatabaseContext(ScriptExecutionContext* context)
- : m_scriptExecutionContext(context)
- , m_hasOpenDatabases(false)
+// This is called if the associated ScriptExecutionContext is destructing while
+// we're still associated with it. That's our cue to disassociate and shutdown.
+// To do this, we stop the database and let everything shutdown naturally
+// because the database closing process may still make use of this context.
+// It is not safe to just delete the context here.
+void DatabaseContext::contextDestroyed()
{
-}
+ stopDatabases();
-DatabaseContext::~DatabaseContext()
-{
- if (m_databaseThread) {
- ASSERT(m_databaseThread->terminationRequested());
- m_databaseThread = 0;
- }
+ // Normally, willDestroyActiveDOMObject() is called in ~ActiveDOMObject().
+ // However, we're here because the destructor hasn't been called, and the
+ // ScriptExecutionContext we're associated with is about to be destructed.
+ // So, go ahead an unregister self from the ActiveDOMObject list, and
+ // set m_scriptExecutionContext to 0 so that ~ActiveDOMObject() doesn't
+ // try to do so again.
+ m_scriptExecutionContext->willDestroyActiveDOMObject(this);
+ m_scriptExecutionContext = 0;
}
-DatabaseContext* DatabaseContext::from(ScriptExecutionContext* context)
+// stop() is from stopActiveDOMObjects() which indicates that the owner Frame
+// or WorkerThread is shutting down. Initiate the orderly shutdown by stopping
+// the associated databases.
+void DatabaseContext::stop()
{
- DatabaseContext* supplement = existingDatabaseContextFrom(context);
- if (!supplement) {
- supplement = new DatabaseContext(context);
- provideTo(context, supplementName(), adoptPtr(supplement));
- ASSERT(supplement == existingDatabaseContextFrom(context));
- }
- return supplement;
+ stopDatabases();
}
DatabaseThread* DatabaseContext::databaseThread()
{
if (!m_databaseThread && !m_hasOpenDatabases) {
+ // It's OK to ask for the m_databaseThread after we've requested
+ // termination because we're still using it to execute the closing
+ // of the database. However, it is NOT OK to create a new thread
+ // after we've requested termination.
+ ASSERT(!m_hasRequestedTermination);
+
// 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();
@@ -92,26 +116,29 @@
return m_databaseThread.get();
}
-bool DatabaseContext::hasOpenDatabases(ScriptExecutionContext* context)
+bool DatabaseContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
{
- // We don't use DatabaseContext::from because we don't want to cause
- // DatabaseContext to be allocated if we don't have one already.
- DatabaseContext* databaseContext = existingDatabaseContextFrom(context);
- if (!databaseContext)
- return false;
- return databaseContext->m_hasOpenDatabases;
-}
+ if (m_isRegistered) {
+ DatabaseManager::manager().unregisterDatabaseContext(this);
+ m_isRegistered = false;
+ }
-void DatabaseContext::stopDatabases(ScriptExecutionContext* context, DatabaseTaskSynchronizer* cleanupSync)
-{
- // We don't use DatabaseContext::from because we don't want to cause
- // DatabaseContext to be allocated if we don't have one already.
- DatabaseContext* databaseContext = existingDatabaseContextFrom(context);
+ // Though we initiate termination of the DatabaseThread here in
+ // stopDatabases(), we can't clear the m_databaseThread ref till we get to
+ // the destructor. This is because the Databases that are managed by
+ // DatabaseThread still rely on this ref between the context and the thread
+ // to execute the task for closing the database. By the time we get to the
+ // destructor, we're guaranteed that the databases are destructed (which is
+ // why our ref count is 0 then and we're destructing). Then, the
+ // m_databaseThread RefPtr destructor will deref and delete the
+ // DatabaseThread.
- if (databaseContext && databaseContext->m_databaseThread)
- databaseContext->m_databaseThread->requestTermination(cleanupSync);
- else if (cleanupSync)
- cleanupSync->taskCompleted();
+ if (m_databaseThread && !m_hasRequestedTermination) {
+ m_databaseThread->requestTermination(cleanupSync);
+ m_hasRequestedTermination = true;
+ return true;
+ }
+ return false;
}
bool DatabaseContext::allowDatabaseAccess() const
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.h (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.h 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseContext.h 2013-01-29 22:51:31 UTC (rev 141166)
@@ -30,8 +30,10 @@
#if ENABLE(SQL_DATABASE)
+#include "ActiveDOMObject.h"
#include "DatabaseDetails.h"
-#include "Supplementable.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
@@ -40,31 +42,37 @@
class DatabaseThread;
class ScriptExecutionContext;
-class DatabaseContext : public Supplement<ScriptExecutionContext> {
+class DatabaseContext : public RefCounted<DatabaseContext>, ActiveDOMObject {
public:
virtual ~DatabaseContext();
- static DatabaseContext* from(ScriptExecutionContext*);
+ // For life-cycle management (inherited from ActiveDOMObject):
+ virtual void contextDestroyed();
+ virtual void stop();
+
+ ScriptExecutionContext* scriptExecutionContext() { return m_scriptExecutionContext; }
DatabaseThread* databaseThread();
void setHasOpenDatabases() { m_hasOpenDatabases = true; }
+ bool hasOpenDatabases() { return m_hasOpenDatabases; }
- static bool hasOpenDatabases(ScriptExecutionContext*);
-
// When the database cleanup is done, cleanupSync will be signalled.
- static void stopDatabases(ScriptExecutionContext*, DatabaseTaskSynchronizer*);
+ bool stopDatabases(DatabaseTaskSynchronizer*);
bool allowDatabaseAccess() const;
void databaseExceededQuota(const String& name, DatabaseDetails);
private:
explicit DatabaseContext(ScriptExecutionContext*);
- static const char* supplementName();
- static DatabaseContext* existingDatabaseContextFrom(ScriptExecutionContext*);
- ScriptExecutionContext* m_scriptExecutionContext;
+ void stopDatabases() { stopDatabases(0); }
+
RefPtr<DatabaseThread> m_databaseThread;
bool m_hasOpenDatabases; // This never changes back to false, even after the database thread is closed.
+ bool m_isRegistered;
+ bool m_hasRequestedTermination;
+
+ friend class DatabaseManager;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -33,6 +33,7 @@
#include "DatabaseCallback.h"
#include "DatabaseContext.h"
#include "DatabaseSync.h"
+#include "DatabaseTask.h"
#include "InspectorDatabaseInstrumentation.h"
#include "Logging.h"
#include "ScriptExecutionContext.h"
@@ -50,6 +51,8 @@
DatabaseManager& DatabaseManager::manager()
{
static DatabaseManager* dbManager = 0;
+ // FIXME: The following is vulnerable to a race between threads. Need to
+ // implement a thread safe on-first-use static initializer.
if (!dbManager)
dbManager = new DatabaseManager();
@@ -59,6 +62,10 @@
DatabaseManager::DatabaseManager()
: m_client(0)
, m_databaseIsAvailable(true)
+#if !ASSERT_DISABLED
+ , m_databaseContextRegisteredCount(0)
+ , m_databaseContextInstanceCount(0)
+#endif
{
#if USE(PLATFORM_STRATEGIES)
m_server = platformStrategies()->databaseStrategy()->getDatabaseServer();
@@ -122,26 +129,95 @@
RefPtr<DatabaseCallback> m_creationCallback;
};
+PassRefPtr<DatabaseContext> DatabaseManager::existingDatabaseContextFor(ScriptExecutionContext* context)
+{
+ MutexLocker locker(m_contextMapLock);
+
+ ASSERT(m_databaseContextRegisteredCount >= 0);
+ ASSERT(m_databaseContextInstanceCount >= 0);
+ ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount);
+
+ RefPtr<DatabaseContext> databaseContext = adoptRef(m_contextMap.get(context));
+ if (databaseContext) {
+ // If we're instantiating a new DatabaseContext, the new instance would
+ // carry a new refCount of 1. The client expects this and will simply
+ // adoptRef the databaseContext without ref'ing it.
+ // However, instead of instantiating a new instance, we're reusing
+ // an existing one that corresponds to the specified ScriptExecutionContext.
+ // Hence, that new refCount need to be attributed to the reused instance
+ // to ensure that the refCount is accurate when the client adopts the ref.
+ // We do this by ref'ing the reused databaseContext before returning it.
+ databaseContext->ref();
+ }
+ return databaseContext.release();
+}
+
+PassRefPtr<DatabaseContext> DatabaseManager::databaseContextFor(ScriptExecutionContext* context)
+{
+ RefPtr<DatabaseContext> databaseContext = existingDatabaseContextFor(context);
+ if (!databaseContext)
+ databaseContext = adoptRef(new DatabaseContext(context));
+ return databaseContext.release();
+}
+
+void DatabaseManager::registerDatabaseContext(DatabaseContext* databaseContext)
+{
+ MutexLocker locker(m_contextMapLock);
+ ScriptExecutionContext* context = databaseContext->scriptExecutionContext();
+ m_contextMap.set(context, databaseContext);
+#if !ASSERT_DISABLED
+ m_databaseContextRegisteredCount++;
+#endif
+}
+
+void DatabaseManager::unregisterDatabaseContext(DatabaseContext* databaseContext)
+{
+ MutexLocker locker(m_contextMapLock);
+ ScriptExecutionContext* context = databaseContext->scriptExecutionContext();
+ ASSERT(m_contextMap.get(context));
+#if !ASSERT_DISABLED
+ m_databaseContextRegisteredCount--;
+#endif
+ m_contextMap.remove(context);
+}
+
+#if !ASSERT_DISABLED
+void DatabaseManager::didConstructDatabaseContext()
+{
+ MutexLocker lock(m_contextMapLock);
+ m_databaseContextInstanceCount++;
+}
+
+void DatabaseManager::didDestructDatabaseContext()
+{
+ MutexLocker lock(m_contextMapLock);
+ m_databaseContextInstanceCount--;
+ ASSERT(m_databaseContextRegisteredCount <= m_databaseContextInstanceCount);
+}
+#endif
+
PassRefPtr<Database> DatabaseManager::openDatabase(ScriptExecutionContext* context,
const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& e)
{
+ RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
+
if (!canEstablishDatabase(context, name, displayName, estimatedSize)) {
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(context, name, expectedVersion, displayName, estimatedSize));
+ RefPtr<Database> database = adoptRef(new Database(databaseContext, name, expectedVersion, displayName, estimatedSize));
String errorMessage;
if (!database->openAndVerifyVersion(!creationCallback, e, errorMessage)) {
database->logErrorMessage(errorMessage);
- DatabaseManager::manager().removeOpenDatabase(database.get());
+ removeOpenDatabase(database.get());
return 0;
}
- DatabaseManager::manager().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
- DatabaseManager::manager().setHasOpenDatabases(context);
+ setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+ databaseContext->setHasOpenDatabases();
InspectorInstrumentation::didOpenDatabase(context, database, context->securityOrigin()->host(), name, expectedVersion);
@@ -150,13 +226,14 @@
database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database, creationCallback));
}
- return database;
+ return database.release();
}
PassRefPtr<DatabaseSync> DatabaseManager::openDatabaseSync(ScriptExecutionContext* context,
const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec)
{
+ RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
ASSERT(context->isContextThread());
if (!canEstablishDatabase(context, name, displayName, estimatedSize)) {
@@ -164,38 +241,39 @@
return 0;
}
- RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(context, name, expectedVersion, displayName, estimatedSize));
+ RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(databaseContext, name, expectedVersion, displayName, estimatedSize));
String errorMessage;
if (!database->performOpenAndVerify(!creationCallback, ec, errorMessage)) {
database->logErrorMessage(errorMessage);
- DatabaseManager::manager().removeOpenDatabase(database.get());
+ removeOpenDatabase(database.get());
return 0;
}
- DatabaseManager::manager().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
+ setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
if (database->isNew() && creationCallback.get()) {
LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get());
creationCallback->handleEvent(database.get());
}
- return database;
+ return database.release();
}
bool DatabaseManager::hasOpenDatabases(ScriptExecutionContext* context)
{
- return DatabaseContext::hasOpenDatabases(context);
+ RefPtr<DatabaseContext> databaseContext = existingDatabaseContextFor(context);
+ if (!databaseContext)
+ return false;
+ return databaseContext->m_hasOpenDatabases;
}
-void DatabaseManager::setHasOpenDatabases(ScriptExecutionContext* context)
-{
- DatabaseContext::from(context)->setHasOpenDatabases();
-}
-
void DatabaseManager::stopDatabases(ScriptExecutionContext* context, DatabaseTaskSynchronizer* synchronizer)
{
- DatabaseContext::stopDatabases(context, synchronizer);
+ RefPtr<DatabaseContext> databaseContext = existingDatabaseContextFor(context);
+ if (!databaseContext || !databaseContext->stopDatabases(synchronizer))
+ if (synchronizer)
+ synchronizer->taskCompleted();
}
String DatabaseManager::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfDoesNotExist)
@@ -272,9 +350,11 @@
}
#endif // PLATFORM(CHROMIUM)
-void DatabaseManager::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
+void DatabaseManager::interruptAllDatabasesForContext(ScriptExecutionContext* context)
{
- m_server->interruptAllDatabasesForContext(context);
+ RefPtr<DatabaseContext> databaseContext = existingDatabaseContextFor(context);
+ if (databaseContext)
+ m_server->interruptAllDatabasesForContext(context);
}
bool DatabaseManager::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize)
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.h (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.h 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseManager.h 2013-01-29 22:51:31 UTC (rev 141166)
@@ -30,13 +30,17 @@
#include "AbstractDatabaseServer.h"
#include "DatabaseBasicTypes.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
namespace WebCore {
class AbstractDatabaseServer;
class Database;
class DatabaseCallback;
+class DatabaseContext;
class DatabaseManagerClient;
class DatabaseSync;
class DatabaseTaskSynchronizer;
@@ -56,11 +60,27 @@
bool isAvailable();
void setIsAvailable(bool);
+ // This gets a DatabaseContext for the specified ScriptExecutionContext.
+ // If one doesn't already exist, it will create a new one.
+ PassRefPtr<DatabaseContext> databaseContextFor(ScriptExecutionContext*);
+
+ // These 2 methods are for DatabaseContext (un)registration, and should only
+ // be called by the DatabaseContext constructor and destructor.
+ void registerDatabaseContext(DatabaseContext*);
+ void unregisterDatabaseContext(DatabaseContext*);
+
+#if !ASSERT_DISABLED
+ void didConstructDatabaseContext();
+ void didDestructDatabaseContext();
+#else
+ void didConstructDatabaseContext() { }
+ void didDestructDatabaseContext() { }
+#endif
+
PassRefPtr<Database> openDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
PassRefPtr<DatabaseSync> openDatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, ExceptionCode&);
bool hasOpenDatabases(ScriptExecutionContext*);
- void setHasOpenDatabases(ScriptExecutionContext*);
void stopDatabases(ScriptExecutionContext*, DatabaseTaskSynchronizer*);
String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true);
@@ -89,7 +109,7 @@
void closeDatabasesImmediately(const String& originIdentifier, const String& name);
#endif // PLATFORM(CHROMIUM)
- void interruptAllDatabasesForContext(const ScriptExecutionContext*);
+ void interruptAllDatabasesForContext(ScriptExecutionContext*);
bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize);
void addOpenDatabase(AbstractDatabase*);
@@ -102,9 +122,22 @@
DatabaseManager();
~DatabaseManager() { }
+ // This gets a DatabaseContext for the specified ScriptExecutionContext if
+ // it already exist previously. Otherwise, it returns 0.
+ PassRefPtr<DatabaseContext> existingDatabaseContextFor(ScriptExecutionContext*);
+
AbstractDatabaseServer* m_server;
DatabaseManagerClient* m_client;
bool m_databaseIsAvailable;
+
+ // Access to the following fields require locking m_contextMapLock:
+ typedef HashMap<ScriptExecutionContext*, DatabaseContext*> ContextMap;
+ ContextMap m_contextMap;
+#if !ASSERT_DISABLED
+ int m_databaseContextRegisteredCount;
+ int m_databaseContextInstanceCount;
+#endif
+ Mutex m_contextMapLock;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -34,6 +34,7 @@
#if ENABLE(SQL_DATABASE)
#include "DatabaseCallback.h"
+#include "DatabaseContext.h"
#include "DatabaseManager.h"
#include "Logging.h"
#include "SQLException.h"
@@ -47,9 +48,9 @@
namespace WebCore {
-DatabaseSync::DatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
+DatabaseSync::DatabaseSync(PassRefPtr<DatabaseContext> databaseContext, const String& name, const String& expectedVersion,
const String& displayName, unsigned long estimatedSize)
- : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize, SyncDatabase)
+ : AbstractDatabase(databaseContext, name, expectedVersion, displayName, estimatedSize, SyncDatabase)
{
}
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.h (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.h 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseSync.h 2013-01-29 22:51:31 UTC (rev 141166)
@@ -47,7 +47,6 @@
class DatabaseCallback;
class SQLTransactionSync;
class SQLTransactionSyncCallback;
-class ScriptExecutionContext;
class SecurityOrigin;
// Instances of this class should be created and used only on the worker's context thread.
@@ -74,7 +73,7 @@
}
private:
- DatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion,
+ DatabaseSync(PassRefPtr<DatabaseContext>, const String& name, const String& expectedVersion,
const String& displayName, unsigned long estimatedSize);
void runTransaction(PassRefPtr<SQLTransactionSyncCallback>, bool readOnly, ExceptionCode&);
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseThread.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseThread.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseThread.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -52,7 +52,13 @@
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.
+ // The DatabaseThread will only be destructed when both its owner
+ // DatabaseContext has deref'ed it, and the databaseThread() thread function
+ // has deref'ed the DatabaseThread object. The DatabaseContext destructor
+ // will take care of ensuring that a termination request has been issued.
+ // The termination request will trigger an orderly shutdown of the thread
+ // function databaseThread(). In shutdown, databaseThread() will deref the
+ // DatabaseThread before returning.
ASSERT(terminationRequested());
}
@@ -70,7 +76,6 @@
void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
{
- ASSERT(!m_cleanupSync);
m_cleanupSync = cleanupSync;
LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
m_queue.kill();
Modified: trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp (141165 => 141166)
--- trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/Modules/webdatabase/DatabaseTracker.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -35,6 +35,7 @@
#include "Chrome.h"
#include "ChromeClient.h"
#include "DatabaseContext.h"
+#include "DatabaseManager.h"
#include "DatabaseManagerClient.h"
#include "DatabaseThread.h"
#include "Logging.h"
@@ -167,7 +168,8 @@
// Give the chrome client a chance to increase the quota.
// Drop all locks before calling out; we don't know what they'll do.
- DatabaseContext::from(context)->databaseExceededQuota(name, DatabaseDetails(name.isolatedCopy(), displayName.isolatedCopy(), estimatedSize, 0));
+ RefPtr<DatabaseContext> databaseContext = DatabaseManager::manager().databaseContextFor(context);
+ databaseContext->databaseExceededQuota(name, DatabaseDetails(name.isolatedCopy(), displayName.isolatedCopy(), estimatedSize, 0));
MutexLocker lockDatabase(m_databaseGuard);
Modified: trunk/Source/WebCore/dom/ActiveDOMObject.cpp (141165 => 141166)
--- trunk/Source/WebCore/dom/ActiveDOMObject.cpp 2013-01-29 22:24:55 UTC (rev 141165)
+++ trunk/Source/WebCore/dom/ActiveDOMObject.cpp 2013-01-29 22:51:31 UTC (rev 141166)
@@ -54,8 +54,17 @@
return;
ASSERT(m_suspendIfNeededCalled);
- ASSERT(m_scriptExecutionContext->isContextThread());
- m_scriptExecutionContext->willDestroyActiveDOMObject(this);
+
+ // ActiveDOMObject may be inherited by a sub-class whose life-cycle
+ // exceeds that of the associated ScriptExecutionContext. In those cases,
+ // m_scriptExecutionContext would/should have been nullified by
+ // ContextDestructionObserver::contextDestroyed() (which we implement /
+ // inherit). Hence, we should ensure that this is not 0 before use it
+ // here.
+ if (m_scriptExecutionContext) {
+ ASSERT(m_scriptExecutionContext->isContextThread());
+ m_scriptExecutionContext->willDestroyActiveDOMObject(this);
+ }
}
void ActiveDOMObject::suspendIfNeeded()