Changeset 53595 in webkit


Ignore:
Timestamp:
Jan 20, 2010 7:49:51 PM (14 years ago)
Author:
eric@webkit.org
Message:

2010-01-20 Eric Uhrhane <ericu@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):
Location:
trunk/WebCore
Files:
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r53592 r53595  
     12010-01-20  Eric Uhrhane  <ericu@chromium.org>
     2
     3        Reviewed by Dmitry Titov.
     4
     5        Refactoring and plumbing to get the HTML5 SQL Database API accessible to
     6        web workers.  No new functionality is exposed yet; this just gets the
     7        infrastructure in place.  It touches a lot of files in small ways; here
     8        are the main changes:
     9
     10        1) Database members and methods move from Document up to
     11        ScriptExecutionContext.  Each of Document and WorkerContext must
     12        implement a few virtual methods where the Database code requires
     13        differentiation.
     14        2) Worker thread shutdown got changed a bunch to handle Database cleanup
     15        and thread synchronization issues.  Database cleanup tasks need to post
     16        some cleanup tasks to the JavaScript thread.  However, since database
     17        cleanup may happen due to the destruction of the WorkerThread, I added a
     18        handshake [involving WorkerThreadShutdownStartTask,
     19        WorkerThreadShutdownFinishTask, and a DatabaseTaskSynchronizer] between
     20        the Database thread and WorkerThread that cleans up all the Database
     21        stuff before the WorkerThread's runLoop can exit.
     22        3) The runtime enabler for the Database moved to a static variable
     23        accessible through Database::isAvailable, following the model used by
     24        WebSocket.
     25        4) Worker threads don't run their JavaScript on the Main thread, so
     26        Database code that differentiated between the Main thread and the
     27        Database thread now need to deal with a third possibility.
     28        5) Most of the other changes have to do with having a
     29        ScriptExecutionContext pointer instead of a Document pointer when
     30        dealing with a Database.  In many cases it's just a string replacement,
     31        but in some it required the creation of a new virtual function [e.g.
     32        databaseExceededQuota, isDatabaseReadOnly]
     33
     34        https://bugs.webkit.org/show_bug.cgi?id=22725
     35
     36        No new tests; in a future patch I'll add JSC and V8 bindings and new
     37        layout tests to exercise them.
     38
     39        * bindings/v8/custom/V8DOMWindowCustom.cpp:
     40        (WebCore::V8DOMWindow::OpenDatabaseEnabled):
     41        * dom/Document.cpp:
     42        (WebCore::Document::Document):
     43        (WebCore::Document::~Document):
     44        (WebCore::Document::isDatabaseReadOnly):
     45        (WebCore::Document::databaseExceededQuota):
     46        (WebCore::Document::isContextThread):
     47        * dom/Document.h:
     48        * dom/ScriptExecutionContext.cpp:
     49        (WebCore::ScriptExecutionContext::ScriptExecutionContext):
     50        (WebCore::ScriptExecutionContext::~ScriptExecutionContext):
     51        (WebCore::ScriptExecutionContext::databaseThread):
     52        (WebCore::ScriptExecutionContext::addOpenDatabase):
     53        (WebCore::ScriptExecutionContext::removeOpenDatabase):
     54        (WebCore::ScriptExecutionContext::stopDatabases):
     55        * dom/ScriptExecutionContext.h:
     56        (WebCore::ScriptExecutionContext::setHasOpenDatabases):
     57        (WebCore::ScriptExecutionContext::hasOpenDatabases):
     58        (WebCore::ScriptExecutionContext::Task::isCleanupTask):
     59        * loader/FrameLoader.cpp:
     60        (WebCore::FrameLoader::stopLoading):
     61        * storage/Database.cpp:
     62        (WebCore::Database::setIsAvailable):
     63        (WebCore::Database::isAvailable):
     64        (WebCore::Database::openDatabase):
     65        (WebCore::Database::Database):
     66        (WebCore::DerefContextTask::create):
     67        (WebCore::DerefContextTask::performTask):
     68        (WebCore::DerefContextTask::isCleanupTask):
     69        (WebCore::Database::~Database):
     70        (WebCore::Database::openAndVerifyVersion):
     71        (WebCore::Database::markAsDeletedAndClose):
     72        (WebCore::ContextRemoveOpenDatabaseTask::create):
     73        (WebCore::ContextRemoveOpenDatabaseTask::performTask):
     74        (WebCore::ContextRemoveOpenDatabaseTask::isCleanupTask):
     75        (WebCore::ContextRemoveOpenDatabaseTask::ContextRemoveOpenDatabaseTask):
     76        (WebCore::Database::close):
     77        (WebCore::Database::performOpenAndVerify):
     78        (WebCore::Database::scheduleTransaction):
     79        (WebCore::Database::scheduleTransactionStep):
     80        (WebCore::DeliverPendingCallbackTask::create):
     81        (WebCore::DeliverPendingCallbackTask::performTask):
     82        (WebCore::DeliverPendingCallbackTask::DeliverPendingCallbackTask):
     83        (WebCore::Database::scheduleTransactionCallback):
     84        (WebCore::Database::transactionClient):
     85        (WebCore::Database::transactionCoordinator):
     86        (WebCore::Database::tableNames):
     87        (WebCore::Database::securityOrigin):
     88        * storage/Database.h:
     89        (WebCore::Database::scriptExecutionContext):
     90        * storage/DatabaseTask.h:
     91        * storage/DatabaseThread.cpp:
     92        (WebCore::DatabaseThread::DatabaseThread):
     93        (WebCore::DatabaseThread::~DatabaseThread):
     94        (WebCore::DatabaseThread::requestTermination):
     95        (WebCore::DatabaseThread::databaseThread):
     96        (WebCore::DatabaseThread::unscheduleDatabaseTasks):
     97        * storage/DatabaseThread.h:
     98        * storage/DatabaseTracker.cpp:
     99        (WebCore::DatabaseTracker::canEstablishDatabase):
     100        (WebCore::DatabaseTracker::getMaxSizeForDatabase):
     101        * storage/DatabaseTracker.h:
     102        * storage/SQLTransaction.cpp:
     103        (WebCore::SQLTransaction::executeSQL):
     104        * storage/SQLTransactionClient.cpp:
     105        (WebCore::SQLTransactionClient::didCommitTransaction):
     106        (WebCore::SQLTransactionClient::didExecuteStatement):
     107        (WebCore::SQLTransactionClient::didExceedQuota):
     108        * storage/chromium/DatabaseTrackerChromium.cpp:
     109        (WebCore::DatabaseTracker::canEstablishDatabase):
     110        (WebCore::DatabaseTracker::addOpenDatabase):
     111        (WebCore::TrackerRemoveOpenDatabaseTask::create):
     112        (WebCore::TrackerRemoveOpenDatabaseTask::performTask):
     113        (WebCore::TrackerRemoveOpenDatabaseTask::TrackerRemoveOpenDatabaseTask):
     114        (WebCore::DatabaseTracker::removeOpenDatabase):
     115        (WebCore::DatabaseTracker::getMaxSizeForDatabase):
     116        * storage/chromium/SQLTransactionClientChromium.cpp:
     117        (WebCore::NotifyDatabaseChangedTask::create):
     118        (WebCore::NotifyDatabaseChangedTask::performTask):
     119        (WebCore::NotifyDatabaseChangedTask::NotifyDatabaseChangedTask):
     120        (WebCore::SQLTransactionClient::didCommitTransaction):
     121        (WebCore::SQLTransactionClient::didExecuteStatement):
     122        (WebCore::SQLTransactionClient::didExceedQuota):
     123        * workers/WorkerContext.cpp:
     124        (WebCore::WorkerContext::openDatabase):
     125        (WebCore::WorkerContext::isContextThread):
     126        * workers/WorkerContext.h:
     127        (WebCore::WorkerContext::clearScript):
     128        (WebCore::WorkerContext::thread):
     129        (WebCore::WorkerContext::isDatabaseReadOnly):
     130        (WebCore::WorkerContext::databaseExceededQuota):
     131        * workers/WorkerRunLoop.cpp:
     132        (WebCore::WorkerRunLoop::runInMode):
     133        (WebCore::WorkerRunLoop::Task::performTask):
     134        * workers/WorkerThread.cpp:
     135        (WebCore::WorkerThread::workerThread):
     136        (WebCore::WorkerThreadShutdownFinishTask::create):
     137        (WebCore::WorkerThreadShutdownFinishTask::performTask):
     138        (WebCore::WorkerThreadShutdownFinishTask::isCleanupTask):
     139        (WebCore::WorkerThreadShutdownStartTask::create):
     140        (WebCore::WorkerThreadShutdownStartTask::performTask):
     141        (WebCore::WorkerThreadShutdownStartTask::isCleanupTask):
     142        (WebCore::WorkerThread::stop):
     143
    11442010-01-20  Fumitoshi Ukai  <ukai@chromium.org>
    2145
  • trunk/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp

    r53586 r53595  
    3434#include "Base64.h"
    3535#include "Chrome.h"
     36#include "Database.h"
    3637#include "DOMTimer.h"
    3738#include "DOMWindow.h"
     
    297298bool V8DOMWindow::OpenDatabaseEnabled()
    298299{
    299     return WebCore::RuntimeEnabledFeatures::databaseEnabled();
     300    return Database::isAvailable();
    300301}
    301302#endif
  • trunk/WebCore/dom/Document.cpp

    r53563 r53595  
    3838#include "CachedCSSStyleSheet.h"
    3939#include "Chrome.h"
     40#include "ChromeClient.h"
    4041#include "Comment.h"
    4142#include "Console.h"
     
    139140#include <wtf/StdLibExtras.h>
    140141
    141 #if ENABLE(DATABASE)
    142 #include "Database.h"
    143 #include "DatabaseThread.h"
    144 #endif
    145 
    146142#if ENABLE(SHARED_WORKERS)
    147143#include "SharedWorkerRepository.h"
     
    392388    , m_normalWorldWrapperCache(0)
    393389#endif
    394 #if ENABLE(DATABASE)
    395     , m_hasOpenDatabases(false)
    396 #endif
    397390    , m_usingGeolocation(false)
    398391#if ENABLE(WML)
     
    539532    for (unsigned i = 0; i < count; i++)
    540533        deleteAllValues(m_nameCollectionInfo[i]);
    541 
    542 #if ENABLE(DATABASE)
    543     if (m_databaseThread) {
    544         ASSERT(m_databaseThread->terminationRequested());
    545         m_databaseThread = 0;
    546     }
    547 #endif
    548534
    549535    if (m_styleSheets)
     
    44444430}
    44454431
     4432#if ENABLE(DATABASE)
     4433
     4434bool Document::isDatabaseReadOnly() const
     4435{
     4436    if (!page() || page()->settings()->privateBrowsingEnabled())
     4437        return true;
     4438    return false;
     4439}
     4440
     4441void Document::databaseExceededQuota(const String& name)
     4442{
     4443    Page* currentPage = page();
     4444    if (currentPage)
     4445        currentPage->chrome()->client()->exceededDatabaseQuota(document()->frame(), name);
     4446}
     4447
     4448#endif
     4449
     4450bool Document::isContextThread() const
     4451{
     4452    return isMainThread();
     4453}
     4454
    44464455void Document::updateURLForPushOrReplaceState(const KURL& url)
    44474456{
     
    45434552    return frame() ? frame()->domWindow()->getSelection() : 0;
    45444553}
    4545 
    4546 #if ENABLE(DATABASE)
    4547 
    4548 void Document::addOpenDatabase(Database* database)
    4549 {
    4550     if (!m_openDatabaseSet)
    4551         m_openDatabaseSet.set(new DatabaseSet);
    4552 
    4553     ASSERT(!m_openDatabaseSet->contains(database));
    4554     m_openDatabaseSet->add(database);
    4555 }
    4556 
    4557 void Document::removeOpenDatabase(Database* database)
    4558 {
    4559     ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
    4560     if (!m_openDatabaseSet)
    4561         return;
    4562        
    4563     m_openDatabaseSet->remove(database);
    4564 }
    4565 
    4566 DatabaseThread* Document::databaseThread()
    4567 {
    4568     if (!m_databaseThread && !m_hasOpenDatabases) {
    4569         // Create the database thread on first request - but not if at least one database was already opened,
    4570         // because in that case we already had a database thread and terminated it and should not create another.
    4571         m_databaseThread = DatabaseThread::create();
    4572         if (!m_databaseThread->start())
    4573             m_databaseThread = 0;
    4574     }
    4575 
    4576     return m_databaseThread.get();
    4577 }
    4578 
    4579 void Document::stopDatabases()
    4580 {
    4581     if (m_openDatabaseSet) {
    4582         DatabaseSet::iterator i = m_openDatabaseSet->begin();
    4583         DatabaseSet::iterator end = m_openDatabaseSet->end();
    4584         for (; i != end; ++i) {
    4585             (*i)->stop();
    4586             if (m_databaseThread)
    4587                 m_databaseThread->unscheduleDatabaseTasks(*i);
    4588         }
    4589     }
    4590    
    4591     if (m_databaseThread)
    4592         m_databaseThread->requestTermination();
    4593 }
    4594 
    4595 #endif
    45964554
    45974555#if ENABLE(WML)
  • trunk/WebCore/dom/Document.h

    r53563 r53595  
    913913
    914914#if ENABLE(DATABASE)
    915     void addOpenDatabase(Database*);
    916     void removeOpenDatabase(Database*);
    917     DatabaseThread* databaseThread();   // Creates the thread as needed, but not if it has been already terminated.
    918     void setHasOpenDatabases() { m_hasOpenDatabases = true; }
    919     bool hasOpenDatabases() { return m_hasOpenDatabases; }
    920     void stopDatabases();
    921 #endif
     915    virtual bool isDatabaseReadOnly() const;
     916    virtual void databaseExceededQuota(const String& name);
     917#endif
     918
     919    virtual bool isContextThread() const;
    922920
    923921    void setUsingGeolocation(bool f) { m_usingGeolocation = f; }
     
    11841182#endif
    11851183
    1186 #if ENABLE(DATABASE)
    1187     RefPtr<DatabaseThread> m_databaseThread;
    1188     bool m_hasOpenDatabases;    // This never changes back to false, even as the database thread is closed.
    1189     typedef HashSet<Database*> DatabaseSet;
    1190     OwnPtr<DatabaseSet> m_openDatabaseSet;
    1191 #endif
    1192    
    11931184    bool m_usingGeolocation;
    11941185
  • trunk/WebCore/dom/ScriptExecutionContext.cpp

    r51127 r53595  
    2929
    3030#include "ActiveDOMObject.h"
    31 #include "Document.h"
     31#include "DatabaseTask.h"
     32#include "DatabaseThread.h"
    3233#include "MessagePort.h"
    3334#include "SecurityOrigin.h"
     
    5758
    5859ScriptExecutionContext::ScriptExecutionContext()
     60#if ENABLE(DATABASE)
     61    : m_hasOpenDatabases(false)
     62#endif
    5963{
    6064}
     
    7377        (*iter)->contextDestroyed();
    7478    }
    75 }
     79    if (m_databaseThread) {
     80        ASSERT(m_databaseThread->terminationRequested());
     81        m_databaseThread = 0;
     82    }
     83}
     84
     85#if ENABLE(DATABASE)
     86
     87DatabaseThread* ScriptExecutionContext::databaseThread()
     88{
     89    if (!m_databaseThread && !m_hasOpenDatabases) {
     90        // Create the database thread on first request - but not if at least one database was already opened,
     91        // because in that case we already had a database thread and terminated it and should not create another.
     92        m_databaseThread = DatabaseThread::create();
     93        if (!m_databaseThread->start())
     94            m_databaseThread = 0;
     95    }
     96
     97    return m_databaseThread.get();
     98}
     99
     100void ScriptExecutionContext::addOpenDatabase(Database* database)
     101{
     102    ASSERT(isContextThread());
     103    if (!m_openDatabaseSet)
     104        m_openDatabaseSet.set(new DatabaseSet());
     105
     106    ASSERT(!m_openDatabaseSet->contains(database));
     107    m_openDatabaseSet->add(database);
     108}
     109
     110void ScriptExecutionContext::removeOpenDatabase(Database* database)
     111{
     112    ASSERT(isContextThread());
     113    ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
     114    if (!m_openDatabaseSet)
     115        return;
     116    m_openDatabaseSet->remove(database);
     117}
     118
     119void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
     120{
     121    ASSERT(isContextThread());
     122    if (m_openDatabaseSet) {
     123        DatabaseSet::iterator i = m_openDatabaseSet->begin();
     124        DatabaseSet::iterator end = m_openDatabaseSet->end();
     125        for (; i != end; ++i) {
     126            (*i)->stop();
     127            if (m_databaseThread)
     128                m_databaseThread->unscheduleDatabaseTasks(*i);
     129        }
     130    }
     131   
     132    if (m_databaseThread)
     133        m_databaseThread->requestTermination(cleanupSync);
     134    else if (cleanupSync)
     135        cleanupSync->taskCompleted();
     136}
     137
     138#endif
    76139
    77140void ScriptExecutionContext::processMessagePortMessagesSoon()
  • trunk/WebCore/dom/ScriptExecutionContext.h

    r51793 r53595  
    3434#include <wtf/PassOwnPtr.h>
    3535#include <wtf/PassRefPtr.h>
     36#include <wtf/RefPtr.h>
    3637#include <wtf/Threading.h>
    3738
     
    3940
    4041    class ActiveDOMObject;
     42#if ENABLE(DATABASE)
     43    class Database;
     44    class DatabaseTaskSynchronizer;
     45    class DatabaseThread;
     46#endif
    4147    class DOMTimer;
    4248    class MessagePort;
     
    5965        virtual bool isDocument() const { return false; }
    6066        virtual bool isWorkerContext() const { return false; }
     67
     68#if ENABLE(DATABASE)
     69        virtual bool isDatabaseReadOnly() const = 0;
     70        virtual void databaseExceededQuota(const String& name) = 0;
     71        DatabaseThread* databaseThread();
     72        void setHasOpenDatabases() { m_hasOpenDatabases = true; }
     73        bool hasOpenDatabases() const { return m_hasOpenDatabases; }
     74        void addOpenDatabase(Database*);
     75        void removeOpenDatabase(Database*);
     76        // When the database cleanup is done, cleanupSync will be signalled.
     77        void stopDatabases(DatabaseTaskSynchronizer*);
     78#endif
     79        virtual bool isContextThread() const = 0;
    6180
    6281        const KURL& url() const { return virtualURL(); }
     
    98117            virtual ~Task();
    99118            virtual void performTask(ScriptExecutionContext*) = 0;
     119            // Certain tasks get marked specially so that they aren't discarded, and are executed, when the context is shutting down its message queue.
     120            virtual bool isCleanupTask() const { return false; }
    100121        };
    101122
     
    130151        virtual void refScriptExecutionContext() = 0;
    131152        virtual void derefScriptExecutionContext() = 0;
     153
     154#if ENABLE(DATABASE)
     155        RefPtr<DatabaseThread> m_databaseThread;
     156        bool m_hasOpenDatabases; // This never changes back to false, even after the database thread is closed.
     157        typedef HashSet<Database* > DatabaseSet;
     158        OwnPtr<DatabaseSet> m_openDatabaseSet;
     159#endif
    132160    };
    133161
  • trunk/WebCore/loader/FrameLoader.cpp

    r53590 r53595  
    567567#if ENABLE(DATABASE)
    568568        if (databasePolicy == DatabasePolicyStop)
    569             doc->stopDatabases();
     569            doc->stopDatabases(0);
    570570#else
    571571    UNUSED_PARAM(databasePolicy);
  • trunk/WebCore/storage/Database.cpp

    r52631 r53595  
    5454#include "SQLTransactionClient.h"
    5555#include "SQLTransactionCoordinator.h"
    56 #include <wtf/MainThread.h>
    57 #endif
     56
     57#endif // ENABLE(DATABASE)
    5858
    5959#if USE(JSC)
     
    7373
    7474#if ENABLE(DATABASE)
     75
     76static bool isDatabaseAvailable = false;
     77
     78void Database::setIsAvailable(bool available)
     79{
     80    isDatabaseAvailable = available;
     81}
     82
     83bool Database::isAvailable()
     84{
     85    return isDatabaseAvailable;
     86}
    7587
    7688static Mutex& guidMutex()
     
    121133static int guidForOriginAndName(const String& origin, const String& name);
    122134
    123 PassRefPtr<Database> Database::openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
    124 {
    125     if (!DatabaseTracker::tracker().canEstablishDatabase(document, name, displayName, estimatedSize)) {
     135PassRefPtr<Database> Database::openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode& e)
     136{
     137    if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) {
    126138        // FIXME: There should be an exception raised here in addition to returning a null Database object.  The question has been raised with the WHATWG.
    127         LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), document->securityOrigin()->toString().ascii().data());
     139        LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
    128140        return 0;
    129141    }
    130142
    131     RefPtr<Database> database = adoptRef(new Database(document, name, expectedVersion, displayName, estimatedSize));
     143    RefPtr<Database> database = adoptRef(new Database(context, name, expectedVersion, displayName, estimatedSize));
    132144
    133145    if (!database->openAndVerifyVersion(e)) {
    134146        LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
    135         document->removeOpenDatabase(database.get());
     147        context->removeOpenDatabase(database.get());
    136148        DatabaseTracker::tracker().removeOpenDatabase(database.get());
    137149        return 0;
    138150    }
    139151
    140     DatabaseTracker::tracker().setDatabaseDetails(document->securityOrigin(), name, displayName, estimatedSize);
    141 
    142     document->setHasOpenDatabases();
    143 
     152    DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
     153
     154    context->setHasOpenDatabases();
    144155#if ENABLE(INSPECTOR)
    145     if (Page* page = document->frame()->page())
    146         page->inspectorController()->didOpenDatabase(database.get(), document->securityOrigin()->host(), name, expectedVersion);
     156    if (context->isDocument()) {
     157        Document* document = static_cast<Document*>(context);
     158        if (Page* page = document->page())
     159            page->inspectorController()->didOpenDatabase(database.get(), context->securityOrigin()->host(), name, expectedVersion);
     160    }
    147161#endif
    148162
     
    150164}
    151165
    152 Database::Database(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
     166Database::Database(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
    153167    : m_transactionInProgress(false)
    154168    , m_isTransactionQueueEnabled(true)
    155     , m_document(document)
     169    , m_scriptExecutionContext(context)
    156170    , m_name(name.crossThreadString())
    157171    , m_guid(0)
     
    163177    , m_opened(false)
    164178{
    165     ASSERT(document);
    166     m_mainThreadSecurityOrigin = document->securityOrigin();
     179    ASSERT(m_scriptExecutionContext.get());
     180    m_mainThreadSecurityOrigin = m_scriptExecutionContext->securityOrigin();
    167181    m_databaseThreadSecurityOrigin = m_mainThreadSecurityOrigin->threadsafeCopy();
    168 
    169182    if (m_name.isNull())
    170183        m_name = "";
     
    172185    ScriptController::initializeThreading();
    173186
    174     m_guid = guidForOriginAndName(m_mainThreadSecurityOrigin->toString(), name);
     187    m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
    175188
    176189    {
     
    186199    }
    187200
    188     ASSERT(m_document->databaseThread());
    189 
    190     m_filename = DatabaseTracker::tracker().fullPathForDatabase(m_mainThreadSecurityOrigin.get(), m_name);
     201    ASSERT(m_scriptExecutionContext->databaseThread());
     202    m_filename = DatabaseTracker::tracker().fullPathForDatabase(securityOrigin(), m_name);
    191203
    192204    DatabaseTracker::tracker().addOpenDatabase(this);
    193     m_document->addOpenDatabase(this);
    194 }
    195 
    196 static void derefDocument(void* document)
    197 {
    198     static_cast<Document*>(document)->deref();
    199 }
     205    context->addOpenDatabase(this);
     206}
     207
     208class DerefContextTask : public ScriptExecutionContext::Task {
     209public:
     210    static PassOwnPtr<DerefContextTask> create()
     211    {
     212        return new DerefContextTask();
     213    }
     214
     215    virtual void performTask(ScriptExecutionContext* context)
     216    {
     217        context->deref();
     218    }
     219
     220    virtual bool isCleanupTask() const { return true; }
     221};
    200222
    201223Database::~Database()
    202224{
    203     // Deref m_document on the main thread.
    204     callOnMainThread(derefDocument, m_document.release().releaseRef());
     225    // 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.
     226    if (!m_scriptExecutionContext->isContextThread()) {
     227        m_scriptExecutionContext->postTask(DerefContextTask::create());
     228        m_scriptExecutionContext.release().releaseRef();
     229    }
    205230}
    206231
    207232bool Database::openAndVerifyVersion(ExceptionCode& e)
    208233{
    209     if (!m_document->databaseThread())
     234    if (!m_scriptExecutionContext->databaseThread())
    210235        return false;
    211236    m_databaseAuthorizer = DatabaseAuthorizer::create();
     
    215240    OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, &synchronizer, e, success);
    216241
    217     m_document->databaseThread()->scheduleImmediateTask(task.release());
     242    m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
    218243    synchronizer.waitForTaskCompletion();
    219244
     
    310335void Database::markAsDeletedAndClose()
    311336{
    312     if (m_deleted || !m_document->databaseThread())
     337    if (m_deleted || !m_scriptExecutionContext->databaseThread())
    313338        return;
    314339
     
    316341    m_deleted = true;
    317342
    318     if (m_document->databaseThread()->terminationRequested()) {
     343    if (m_scriptExecutionContext->databaseThread()->terminationRequested()) {
    319344        LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
    320345        return;
    321346    }
    322347
    323     m_document->databaseThread()->unscheduleDatabaseTasks(this);
     348    m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
    324349
    325350    DatabaseTaskSynchronizer synchronizer;
    326351    OwnPtr<DatabaseCloseTask> task = DatabaseCloseTask::create(this, &synchronizer);
    327352
    328     m_document->databaseThread()->scheduleImmediateTask(task.release());
     353    m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
    329354    synchronizer.waitForTaskCompletion();
    330355}
    331356
    332 static void documentRemoveOpenDatabase(void* context)
    333 {
    334     ASSERT(isMainThread());
    335     Database* database = static_cast<Database*>(context);
    336     database->document()->removeOpenDatabase(database);
    337     database->deref();
    338 }
     357class ContextRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
     358public:
     359    static PassOwnPtr<ContextRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
     360    {
     361        return new ContextRemoveOpenDatabaseTask(database);
     362    }
     363
     364    virtual void performTask(ScriptExecutionContext* context)
     365    {
     366        context->removeOpenDatabase(m_database.get());
     367        DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
     368    }
     369
     370    virtual bool isCleanupTask() const { return true; }
     371
     372private:
     373    ContextRemoveOpenDatabaseTask(PassRefPtr<Database> database)
     374        : m_database(database)
     375    {
     376    }
     377
     378    RefPtr<Database> m_database;
     379};
    339380
    340381void Database::close()
    341382{
     383    RefPtr<Database> protect = this;
     384
    342385    if (!m_opened)
    343386        return;
    344387
    345     ASSERT(m_document->databaseThread());
    346     ASSERT(currentThread() == document()->databaseThread()->getThreadID());
     388    ASSERT(m_scriptExecutionContext->databaseThread());
     389    ASSERT(currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID());
    347390    m_sqliteDatabase.close();
    348     m_document->databaseThread()->recordDatabaseClosed(this);
     391    // Must ref() before calling databaseThread()->recordDatabaseClosed().
     392    m_scriptExecutionContext->databaseThread()->recordDatabaseClosed(this);
    349393    m_opened = false;
    350394
     
    363407    }
    364408
    365     m_document->databaseThread()->unscheduleDatabaseTasks(this);
    366 
    367     DatabaseTracker::tracker().removeOpenDatabase(this);
    368     ref();  // deref() called in documentRemoveOpenDatabase()
    369     callOnMainThread(documentRemoveOpenDatabase, this);
     409    m_scriptExecutionContext->databaseThread()->unscheduleDatabaseTasks(this);
     410    m_scriptExecutionContext->postTask(ContextRemoveOpenDatabaseTask::create(this));
    370411}
    371412
     
    533574    // Make sure DatabaseThread closes it when DatabaseThread goes away.
    534575    m_opened = true;
    535     if (m_document->databaseThread())
    536         m_document->databaseThread()->recordDatabaseOpen(this);
     576    if (m_scriptExecutionContext->databaseThread())
     577        m_scriptExecutionContext->databaseThread()->recordDatabaseOpen(this);
    537578
    538579    return true;
     
    568609    }
    569610
    570     if (transaction && m_document->databaseThread()) {
     611    if (transaction && m_scriptExecutionContext->databaseThread()) {
    571612        OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
    572613        LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
    573614        m_transactionInProgress = true;
    574         m_document->databaseThread()->scheduleTask(task.release());
     615        m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
    575616    } else
    576617        m_transactionInProgress = false;
     
    579620void Database::scheduleTransactionStep(SQLTransaction* transaction, bool immediately)
    580621{
    581     if (!m_document->databaseThread())
     622    if (!m_scriptExecutionContext->databaseThread())
    582623        return;
    583624
     
    585626    LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
    586627    if (immediately)
    587         m_document->databaseThread()->scheduleImmediateTask(task.release());
     628        m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
    588629    else
    589         m_document->databaseThread()->scheduleTask(task.release());
    590 }
     630        m_scriptExecutionContext->databaseThread()->scheduleTask(task.release());
     631}
     632
     633class DeliverPendingCallbackTask : public ScriptExecutionContext::Task {
     634public:
     635    static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction)
     636    {
     637        return new DeliverPendingCallbackTask(transaction);
     638    }
     639
     640    virtual void performTask(ScriptExecutionContext*)
     641    {
     642        m_transaction->performPendingCallback();
     643    }
     644
     645private:
     646    DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)
     647        : m_transaction(transaction)
     648    {
     649    }
     650
     651    RefPtr<SQLTransaction> m_transaction;
     652};
    591653
    592654void Database::scheduleTransactionCallback(SQLTransaction* transaction)
    593655{
    594     transaction->ref();
    595     callOnMainThread(deliverPendingCallback, transaction);
     656    m_scriptExecutionContext->postTask(DeliverPendingCallbackTask::create(transaction));
    596657}
    597658
     
    627688SQLTransactionClient* Database::transactionClient() const
    628689{
    629     return m_document->databaseThread()->transactionClient();
     690    return m_scriptExecutionContext->databaseThread()->transactionClient();
    630691}
    631692
    632693SQLTransactionCoordinator* Database::transactionCoordinator() const
    633694{
    634     return m_document->databaseThread()->transactionCoordinator();
     695    return m_scriptExecutionContext->databaseThread()->transactionCoordinator();
    635696}
    636697
     
    643704}
    644705
    645 void Database::deliverPendingCallback(void* context)
    646 {
    647     SQLTransaction* transaction = static_cast<SQLTransaction*>(context);
    648     transaction->performPendingCallback();
    649     transaction->deref(); // Was ref'd in scheduleTransactionCallback().
    650 }
    651 
    652706Vector<String> Database::tableNames()
    653707{
     
    655709    // in dealing with them. However, if the code changes, this may not be true anymore.
    656710    Vector<String> result;
    657     if (!m_document->databaseThread())
     711    if (!m_scriptExecutionContext->databaseThread())
    658712        return result;
    659713
     
    661715    OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
    662716
    663     m_document->databaseThread()->scheduleImmediateTask(task.release());
     717    m_scriptExecutionContext->databaseThread()->scheduleImmediateTask(task.release());
    664718    synchronizer.waitForTaskCompletion();
    665719
     
    677731SecurityOrigin* Database::securityOrigin() const
    678732{
    679     if (isMainThread())
     733    if (scriptExecutionContext()->isContextThread())
    680734        return m_mainThreadSecurityOrigin.get();
    681     if (currentThread() == document()->databaseThread()->getThreadID())
     735    if (currentThread() == m_scriptExecutionContext->databaseThread()->getThreadID())
    682736        return m_databaseThreadSecurityOrigin.get();
    683737    return 0;
     
    707761}
    708762
    709 #endif
    710 
    711 }
     763#endif // ENABLE(DATABASE)
     764
     765} // namespace WebCore
  • trunk/WebCore/storage/Database.h

    r50360 r53595  
    5353class DatabaseAuthorizer;
    5454class DatabaseThread;
    55 class Document;
     55class ScriptExecutionContext;
    5656class SQLResultSet;
    5757class SQLTransactionCallback;
     
    6868    friend class SQLTransaction;
    6969public:
     70    static void setIsAvailable(bool);
     71    static bool isAvailable();
     72
    7073    ~Database();
    7174
    7275// Direct support for the DOM API
    73     static PassRefPtr<Database> openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
     76    static PassRefPtr<Database> openDatabase(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
    7477    String version() const;
    7578    void changeVersion(const String& oldVersion, const String& newVersion,
     
    8891    Vector<String> tableNames();
    8992
    90     Document* document() const { return m_document.get(); }
     93    ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext.get(); }
    9194    SecurityOrigin* securityOrigin() const;
    9295    String stringIdentifier() const;
     
    124127
    125128private:
    126     Database(Document* document, const String& name, const String& expectedVersion,
    127              const String& displayName, unsigned long estimatedSize);
     129    Database(ScriptExecutionContext* context, const String& name,
     130             const String& expectedVersion, const String& displayName,
     131             unsigned long estimatedSize);
    128132
    129133    bool openAndVerifyVersion(ExceptionCode&);
     
    140144    static void deliverPendingCallback(void*);
    141145
    142     RefPtr<Document> m_document;
     146    RefPtr<ScriptExecutionContext> m_scriptExecutionContext;
    143147    RefPtr<SecurityOrigin> m_mainThreadSecurityOrigin;
    144148    RefPtr<SecurityOrigin> m_databaseThreadSecurityOrigin;
  • trunk/WebCore/storage/DatabaseTask.h

    r50427 r53595  
    5151// Has to be passed into DatabaseTask::create to be associated with the task.
    5252class DatabaseTaskSynchronizer : public Noncopyable {
    53     friend class DatabaseTask;
    5453public:
    5554    DatabaseTaskSynchronizer();
     
    5857    void waitForTaskCompletion();
    5958
    60 private:
    6159    // Called by the task.
    6260    void taskCompleted();
     61private:
    6362
    6463    bool m_taskCompleted;
  • trunk/WebCore/storage/DatabaseThread.cpp

    r50427 r53595  
    4545    , m_transactionClient(new SQLTransactionClient())
    4646    , m_transactionCoordinator(new SQLTransactionCoordinator())
     47    , m_cleanupSync(0)
    4748{
    4849    m_selfRef = this;
     
    5253{
    5354    // FIXME: Any cleanup required here?  Since the thread deletes itself after running its detached course, I don't think so.  Lets be sure.
     55    ASSERT(terminationRequested());
    5456}
    5557
     
    6668}
    6769
    68 void DatabaseThread::requestTermination()
     70void DatabaseThread::requestTermination(DatabaseTaskSynchronizer *cleanupSync)
    6971{
     72    ASSERT(!m_cleanupSync);
     73    m_cleanupSync = cleanupSync;
    7074    LOG(StorageAPI, "DatabaseThread %p was asked to terminate\n", this);
    7175    m_queue.kill();
     
    116120    detachThread(m_threadID);
    117121
     122    DatabaseTaskSynchronizer* cleanupSync = m_cleanupSync;
     123   
    118124    // Clear the self refptr, possibly resulting in deletion
    119125    m_selfRef = 0;
     126
     127    if (cleanupSync) // Someone wanted to know when we were done cleaning up.
     128        cleanupSync->taskCompleted();
    120129
    121130    return 0;
     
    163172    m_queue.removeIf(predicate);
    164173}
    165 
    166174} // namespace WebCore
    167175#endif
  • trunk/WebCore/storage/DatabaseThread.h

    r50427 r53595  
    4444class Database;
    4545class DatabaseTask;
     46class DatabaseTaskSynchronizer;
    4647class Document;
    4748class SQLTransactionClient;
     
    5455
    5556    bool start();
    56     void requestTermination();
     57    void requestTermination(DatabaseTaskSynchronizer* cleanupSync);
    5758    bool terminationRequested() const;
    5859
     
    8687    OwnPtr<SQLTransactionClient> m_transactionClient;
    8788    OwnPtr<SQLTransactionCoordinator> m_transactionCoordinator;
     89    DatabaseTaskSynchronizer* m_cleanupSync;
    8890};
    8991
  • trunk/WebCore/storage/DatabaseTracker.cpp

    r52314 r53595  
    3737#include "DatabaseThread.h"
    3838#include "DatabaseTrackerClient.h"
    39 #include "Document.h"
    4039#include "Logging.h"
    4140#include "OriginQuotaManager.h"
    4241#include "Page.h"
     42#include "ScriptExecutionContext.h"
    4343#include "SecurityOrigin.h"
    4444#include "SecurityOriginHash.h"
     
    121121}
    122122
    123 bool DatabaseTracker::canEstablishDatabase(Document* document, const String& name, const String& displayName, unsigned long estimatedSize)
     123bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext* context, const String& name, const String& displayName, unsigned long estimatedSize)
    124124{
    125125    ASSERT(currentThread() == m_thread);
     
    129129    populateOrigins();
    130130
    131     SecurityOrigin* origin = document->securityOrigin();
    132 
    133     // Since we're imminently opening a database within this Document's origin, make sure this origin is being tracked by the QuotaTracker
     131    SecurityOrigin* origin = context->securityOrigin();
     132
     133    // Since we're imminently opening a database within this context's origin, make sure this origin is being tracked by the QuotaTracker
    134134    // by fetching it's current usage now
    135135    unsigned long long usage = usageForOrigin(origin);
     
    148148    // Give the chrome client a chance to increase the quota.
    149149    // Temporarily make the details of the proposed database available, so the client can get at them.
    150     Page* page = document->page();
    151     if (!page)
    152         return false;
    153150    pair<SecurityOrigin*, DatabaseDetails> details(origin, DatabaseDetails(name, displayName, estimatedSize, 0));
    154151    m_proposedDatabase = &details;
    155     page->chrome()->client()->exceededDatabaseQuota(document->frame(), name);
     152    context->databaseExceededQuota(name);
    156153    m_proposedDatabase = 0;
    157154
     
    187184unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
    188185{
    189     ASSERT(currentThread() == database->document()->databaseThread()->getThreadID());
     186    ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
    190187    // The maximum size for a database is the full quota for its origin, minus the current usage within the origin,
    191188    // plus the current usage of the given database
  • trunk/WebCore/storage/DatabaseTracker.h

    r52314 r53595  
    4646
    4747class Database;
    48 class Document;
     48class ScriptExecutionContext;
    4949class SecurityOrigin;
    5050
     
    6060public:
    6161    static DatabaseTracker& tracker();
     62    // FIXME: Due to workers having multiple threads in a single process sharing
     63    // a DatabaseTracker, this singleton will have to be synchronized or moved
     64    // to TLS.
    6265
    63     bool canEstablishDatabase(Document*, const String& name, const String& displayName, unsigned long estimatedSize);
     66    bool canEstablishDatabase(ScriptExecutionContext*, const String& name, const String& displayName, unsigned long estimatedSize);
    6467    void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize);
    6568    String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true);
  • trunk/WebCore/storage/SQLTransaction.cpp

    r50169 r53595  
    3636#include "DatabaseAuthorizer.h"
    3737#include "DatabaseDetails.h"
    38 #include "Document.h"
    3938#include "ExceptionCode.h"
    4039#include "Logging.h"
    4140#include "Page.h"
    4241#include "PlatformString.h"
     42#include "ScriptExecutionContext.h"
    4343#include "Settings.h"
    4444#include "SQLError.h"
     
    9595    bool readOnlyMode = m_readOnly;
    9696    if (!readOnlyMode) {
    97         Page* page = m_database->document()->page();
    98         if (!page || page->settings()->privateBrowsingEnabled())
     97        if (m_database->scriptExecutionContext()->isDatabaseReadOnly())
    9998            readOnlyMode = true;
    10099    }
  • trunk/WebCore/storage/SQLTransactionClient.cpp

    r52314 r53595  
    4848void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
    4949{
    50     ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
     50    ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
    5151    Database* database = transaction->database();
    5252    DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
     
    5656void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
    5757{
    58     ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
     58    ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
    5959    OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
    6060    Locker<OriginQuotaManager> locker(manager);
     
    6464bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
    6565{
    66     ASSERT(isMainThread());
     66    ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
    6767    Database* database = transaction->database();
    68     Page* page = database->document()->page();
    69     ASSERT(page);
    7068
    7169    unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
    72     page->chrome()->client()->exceededDatabaseQuota(database->document()->frame(), database->stringIdentifier());
     70    database->scriptExecutionContext()->databaseExceededQuota(database->stringIdentifier());
    7371    unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(database->securityOrigin());
    7472    return (newQuota > currentQuota);
  • trunk/WebCore/storage/chromium/DatabaseTrackerChromium.cpp

    r52372 r53595  
    3636#include "DatabaseObserver.h"
    3737#include "DatabaseThread.h"
    38 #include "Document.h"
    3938#include "QuotaTracker.h"
     39#include "ScriptExecutionContext.h"
    4040#include "SecurityOrigin.h"
    4141#include "SQLiteFileSystem.h"
     
    5757}
    5858
    59 bool DatabaseTracker::canEstablishDatabase(Document*, const String&, const String&, unsigned long)
     59bool DatabaseTracker::canEstablishDatabase(ScriptExecutionContext*, const String&, const String&, unsigned long)
    6060{
    6161    // In Chromium, a database can always be established (even though we might not
     
    7676void DatabaseTracker::addOpenDatabase(Database* database)
    7777{
    78     ASSERT(isMainThread());
     78    ASSERT(database->scriptExecutionContext()->isContextThread());
    7979    DatabaseObserver::databaseOpened(database);
    8080}
    81 static void removeOpenDatabaseOnMainThread(void* context)
    82 {
    83     Database* database = static_cast<Database*>(context);
    84     DatabaseTracker::tracker().removeOpenDatabase(database);
    85     database->deref();
    86 }
     81
     82class TrackerRemoveOpenDatabaseTask : public ScriptExecutionContext::Task {
     83public:
     84    static PassOwnPtr<TrackerRemoveOpenDatabaseTask> create(PassRefPtr<Database> database)
     85    {
     86        return new TrackerRemoveOpenDatabaseTask(database);
     87    }
     88
     89    virtual void performTask(ScriptExecutionContext* context)
     90    {
     91        DatabaseTracker::tracker().removeOpenDatabase(m_database.get());
     92    }
     93
     94private:
     95    TrackerRemoveOpenDatabaseTask(PassRefPtr<Database> database)
     96        : m_database(database)
     97    {
     98    }
     99
     100    RefPtr<Database> m_database;
     101};
    87102
    88103void DatabaseTracker::removeOpenDatabase(Database* database)
    89104{
    90     if (!isMainThread()) {
    91         database->ref();
    92         callOnMainThread(removeOpenDatabaseOnMainThread, database);
     105    if (!database->scriptExecutionContext()->isContextThread()) {
     106        database->scriptExecutionContext()->postTask(TrackerRemoveOpenDatabaseTask::create(database));
    93107        return;
    94108    }
     
    99113unsigned long long DatabaseTracker::getMaxSizeForDatabase(const Database* database)
    100114{
    101     ASSERT(currentThread() == database->document()->databaseThread()->getThreadID());
     115    ASSERT(currentThread() == database->scriptExecutionContext()->databaseThread()->getThreadID());
    102116    unsigned long long spaceAvailable = 0;
    103117    unsigned long long databaseSize = 0;
  • trunk/WebCore/storage/chromium/SQLTransactionClientChromium.cpp

    r50434 r53595  
    3939#include <wtf/MainThread.h>
    4040
    41 static void notifyDatabaseChanged(void* context) {
    42     WebCore::Database* database = static_cast<WebCore::Database*>(context);
    43     WebCore::DatabaseObserver::databaseModified(database);
    44     database->deref();  // ref()'d in didCommitTransaction()
    45 }
     41namespace WebCore {
    4642
    47 namespace WebCore {
     43class NotifyDatabaseChangedTask : public ScriptExecutionContext::Task {
     44public:
     45    static PassOwnPtr<NotifyDatabaseChangedTask> create(Database *database)
     46    {
     47        return new NotifyDatabaseChangedTask(database);
     48    }
     49
     50    virtual void performTask(ScriptExecutionContext*)
     51    {
     52        WebCore::DatabaseObserver::databaseModified(m_database.get());
     53    }
     54
     55private:
     56    NotifyDatabaseChangedTask(PassRefPtr<Database> database)
     57        : m_database(database)
     58    {
     59    }
     60
     61    RefPtr<Database> m_database;
     62};
    4863
    4964void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
    5065{
    51     ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
     66    ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
    5267    if (!transaction->isReadOnly()) {
    53         transaction->database()->ref();  // deref()'d in notifyDatabaseChanged()
    54         callOnMainThread(notifyDatabaseChanged, transaction->database());
     68        transaction->database()->scriptExecutionContext()->postTask(NotifyDatabaseChangedTask::create(transaction->database()));
    5569    }
    5670}
     
    6074    // This method is called after executing every statement that changes the DB.
    6175    // Chromium doesn't need to do anything at that point.
    62     ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
     76    ASSERT(currentThread() == transaction->database()->scriptExecutionContext()->databaseThread()->getThreadID());
    6377}
    6478
    65 bool SQLTransactionClient::didExceedQuota(SQLTransaction*)
     79bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
    6680{
    6781    // Chromium does not allow users to manually change the quota for an origin (for now, at least).
    6882    // Don't do anything.
    69     ASSERT(isMainThread());
     83    ASSERT(transaction->database()->scriptExecutionContext()->isContextThread());
    7084    return false;
    7185}
  • trunk/WebCore/workers/WorkerContext.cpp

    r50427 r53595  
    3333
    3434#include "ActiveDOMObject.h"
     35#include "Database.h"
    3536#include "DOMTimer.h"
    3637#include "DOMWindow.h"
     
    255256#endif
    256257
     258#if ENABLE(DATABASE)
     259PassRefPtr<Database> WorkerContext::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec)
     260{
     261    if (!securityOrigin()->canAccessDatabase()) {
     262        ec = SECURITY_ERR;
     263        return 0;
     264    }
     265
     266    ASSERT(Database::isAvailable());
     267    if (!Database::isAvailable())
     268        return 0;
     269
     270    return Database::openDatabase(this, name, version, displayName, estimatedSize, ec);
     271}
     272#endif
     273
     274bool WorkerContext::isContextThread() const
     275{
     276    return currentThread() == thread()->threadID();
     277}
     278
    257279EventTargetData* WorkerContext::eventTargetData()
    258280{
  • trunk/WebCore/workers/WorkerContext.h

    r50427 r53595  
    3131
    3232#include "AtomicStringHash.h"
     33#include "Database.h"
    3334#include "EventListener.h"
    3435#include "EventNames.h"
     
    3637#include "ScriptExecutionContext.h"
    3738#include "WorkerScriptController.h"
     39#include <wtf/Assertions.h>
    3840#include <wtf/OwnPtr.h>
    3941#include <wtf/PassRefPtr.h>
     
    4345namespace WebCore {
    4446
     47    class Database;
    4548    class NotificationCenter;
    4649    class ScheduledAction;
     
    6669
    6770        WorkerScriptController* script() { return m_script.get(); }
    68         void clearScript() { return m_script.clear(); }
     71        void clearScript() { m_script.clear(); }
    6972
    70         WorkerThread* thread() { return m_thread; }
     73        WorkerThread* thread() const { return m_thread; }
    7174
    7275        bool hasPendingActivity() const;
     
    101104        NotificationCenter* webkitNotifications() const;
    102105#endif
     106
     107#if ENABLE(DATABASE)
     108        // HTML 5 client-side database
     109        PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
     110        // Not implemented yet.
     111        virtual bool isDatabaseReadOnly() const { return false; }
     112        // Not implemented yet.
     113        virtual void databaseExceededQuota(const String&) { }
     114#endif
     115        virtual bool isContextThread() const;
     116
    103117
    104118        // These methods are used for GC marking. See JSWorkerContext::markChildren(MarkStack&) in
  • trunk/WebCore/workers/WorkerRunLoop.cpp

    r50427 r53595  
    153153    OwnPtr<WorkerRunLoop::Task> task = m_messageQueue.waitForMessageFilteredWithTimeout(result, predicate, absoluteTime);
    154154
    155     // If the context is closing, don't dispatch any further tasks (per section 4.1.1 of the Web Workers spec).
    156     if (context->isClosing())
    157         return result;
     155    // 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.
    158156
    159157    switch (result) {
     
    166164
    167165    case MessageQueueTimeout:
    168         m_sharedTimer->fire();
     166        if (!context->isClosing())
     167            m_sharedTimer->fire();
    169168        break;
    170169    }
     
    195194void WorkerRunLoop::Task::performTask(ScriptExecutionContext* context)
    196195{
    197     m_task->performTask(context);
     196    WorkerContext* workerContext = static_cast<WorkerContext *>(context);
     197    if (!workerContext->isClosing() || m_task->isCleanupTask())
     198        m_task->performTask(context);
    198199}
    199200
  • trunk/WebCore/workers/WorkerThread.cpp

    r49734 r53595  
    3131#include "WorkerThread.h"
    3232
     33#include "DatabaseTask.h"
    3334#include "DedicatedWorkerContext.h"
    3435#include "KURL.h"
     
    136137    ThreadIdentifier threadID = m_threadID;
    137138
    138     m_workerContext->stopActiveDOMObjects();
    139     m_workerContext->clearScript();
    140139    ASSERT(m_workerContext->hasOneRef());
     140
    141141    // The below assignment will destroy the context, which will in turn notify messaging proxy.
    142142    // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
     
    155155}
    156156
     157class WorkerThreadShutdownFinishTask : public ScriptExecutionContext::Task {
     158public:
     159    static PassOwnPtr<WorkerThreadShutdownFinishTask> create()
     160    {
     161        return new WorkerThreadShutdownFinishTask();
     162    }
     163
     164    virtual void performTask(ScriptExecutionContext *context)
     165    {
     166        ASSERT(context->isWorkerContext());
     167        WorkerContext* workerContext = static_cast<WorkerContext*>(context);
     168        workerContext->thread()->runLoop().terminate();
     169    }
     170
     171    virtual bool isCleanupTask() const { return true; }
     172};
     173
     174class WorkerThreadShutdownStartTask : public ScriptExecutionContext::Task {
     175public:
     176    static PassOwnPtr<WorkerThreadShutdownStartTask> create()
     177    {
     178        return new WorkerThreadShutdownStartTask();
     179    }
     180
     181    virtual void performTask(ScriptExecutionContext *context)
     182    {
     183        ASSERT(context->isWorkerContext());
     184        WorkerContext* workerContext = static_cast<WorkerContext*>(context);
     185
     186        // We currently ignore any DatabasePolicy used for the document's
     187        // databases; if it's actually used anywhere, this should be revisited.
     188        DatabaseTaskSynchronizer cleanupSync;
     189        workerContext->stopDatabases(&cleanupSync);
     190
     191        workerContext->stopActiveDOMObjects();
     192        workerContext->clearScript();
     193
     194        // We wait for the database thread to clean up all its stuff so that we
     195        // can do more stringent leak checks as we exit.
     196        cleanupSync.waitForTaskCompletion();
     197
     198        // Stick a shutdown command at the end of the queue, so that we deal
     199        // with all the cleanup tasks the databases post first.
     200        workerContext->postTask(WorkerThreadShutdownFinishTask::create());
     201    }
     202
     203    virtual bool isCleanupTask() const { return true; }
     204};
     205
    157206void WorkerThread::stop()
    158207{
     
    161210
    162211    // 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.
    163     if (m_workerContext)
     212    if (m_workerContext) {
    164213        m_workerContext->script()->forbidExecution();
    165214
    166215    // FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction.
    167     m_runLoop.terminate();
     216    // This can likely use the same mechanism as used for databases above.
     217
     218        m_runLoop.postTask(WorkerThreadShutdownStartTask::create());
     219    } else
     220        m_runLoop.terminate();
    168221}
    169222
Note: See TracChangeset for help on using the changeset viewer.