Home | History | Annotate | Download | only in webdatabase
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2011 Google, Inc. All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  *
     26  */
     27 
     28 #include "config.h"
     29 #include "modules/webdatabase/DatabaseContext.h"
     30 
     31 #include "core/dom/Document.h"
     32 #include "core/dom/ExecutionContext.h"
     33 #include "modules/webdatabase/Database.h"
     34 #include "modules/webdatabase/DatabaseManager.h"
     35 #include "modules/webdatabase/DatabaseTask.h"
     36 #include "modules/webdatabase/DatabaseThread.h"
     37 #include "platform/weborigin/SchemeRegistry.h"
     38 #include "platform/weborigin/SecurityOrigin.h"
     39 #include "wtf/Assertions.h"
     40 
     41 namespace blink {
     42 
     43 // How the DatabaseContext Life-Cycle works?
     44 // ========================================
     45 // ... in other words, who's keeping the DatabaseContext alive and how long does
     46 // it need to stay alive?
     47 //
     48 // The DatabaseContext is referenced from RefPtrs in:
     49 // 1. ExecutionContext
     50 // 2. Database
     51 //
     52 // At Birth:
     53 // ========
     54 // We create a DatabaseContext only when there is a need i.e. the script tries to
     55 // open a Database via DatabaseManager::openDatabase().
     56 //
     57 // The DatabaseContext constructor will call ref(). This lets DatabaseContext keep itself alive.
     58 // Note that paired deref() is called from contextDestroyed().
     59 //
     60 // Once a DatabaseContext is associated with a ExecutionContext, it will
     61 // live until after the ExecutionContext destructs. This is true even if
     62 // we don't succeed in opening any Databases for that context. When we do
     63 // succeed in opening Databases for this ExecutionContext, the Database
     64 // will re-use the same DatabaseContext.
     65 //
     66 // At Shutdown:
     67 // ===========
     68 // During shutdown, the DatabaseContext needs to:
     69 // 1. "outlive" the ExecutionContext.
     70 //    - This is needed because the DatabaseContext needs to remove itself from the
     71 //      ExecutionContext's ActiveDOMObject list and ContextLifecycleObserver
     72 //      list. This removal needs to be executed on the script's thread. Hence, we
     73 //      rely on the ExecutionContext's shutdown process to call
     74 //      stop() and contextDestroyed() to give us a chance to clean these up from
     75 //      the script thread.
     76 //
     77 // 2. "outlive" the Databases.
     78 //    - This is because they may make use of the DatabaseContext to execute a close
     79 //      task and shutdown in an orderly manner. When the Databases are destructed,
     80 //      they will deref the DatabaseContext from the DatabaseThread.
     81 //
     82 // During shutdown, the ExecutionContext is shutting down on the script thread
     83 // while the Databases are shutting down on the DatabaseThread. Hence, there can be
     84 // a race condition as to whether the ExecutionContext or the Databases
     85 // destruct first.
     86 //
     87 // The RefPtrs in the Databases and ExecutionContext will ensure that the
     88 // DatabaseContext will outlive both regardless of which of the 2 destructs first.
     89 
     90 PassRefPtrWillBeRawPtr<DatabaseContext> DatabaseContext::create(ExecutionContext* context)
     91 {
     92     RefPtrWillBeRawPtr<DatabaseContext> self = adoptRefWillBeNoop(new DatabaseContext(context));
     93     DatabaseManager::manager().registerDatabaseContext(self.get());
     94     return self.release();
     95 }
     96 
     97 DatabaseContext::DatabaseContext(ExecutionContext* context)
     98     : ActiveDOMObject(context)
     99     , m_hasOpenDatabases(false)
    100     , m_hasRequestedTermination(false)
    101 {
    102     // ActiveDOMObject expects this to be called to set internal flags.
    103     suspendIfNeeded();
    104 
    105     // For debug accounting only. We must do this before we register the
    106     // instance. The assertions assume this.
    107     DatabaseManager::manager().didConstructDatabaseContext();
    108 }
    109 
    110 DatabaseContext::~DatabaseContext()
    111 {
    112     // For debug accounting only. We must call this last. The assertions assume
    113     // this.
    114     DatabaseManager::manager().didDestructDatabaseContext();
    115 }
    116 
    117 void DatabaseContext::trace(Visitor* visitor)
    118 {
    119 #if ENABLE(OILPAN)
    120     visitor->trace(m_databaseThread);
    121 #endif
    122 }
    123 
    124 // This is called if the associated ExecutionContext is destructing while
    125 // we're still associated with it. That's our cue to disassociate and shutdown.
    126 // To do this, we stop the database and let everything shutdown naturally
    127 // because the database closing process may still make use of this context.
    128 // It is not safe to just delete the context here.
    129 void DatabaseContext::contextDestroyed()
    130 {
    131     RefPtrWillBeRawPtr<DatabaseContext> protector(this);
    132     stopDatabases();
    133     DatabaseManager::manager().unregisterDatabaseContext(this);
    134     ActiveDOMObject::contextDestroyed();
    135 }
    136 
    137 // stop() is from stopActiveDOMObjects() which indicates that the owner
    138 // LocalFrame is shutting down. Initiate the orderly shutdown by stopping the
    139 // associated databases.
    140 void DatabaseContext::stop()
    141 {
    142     stopDatabases();
    143 }
    144 
    145 DatabaseContext* DatabaseContext::backend()
    146 {
    147     return this;
    148 }
    149 
    150 DatabaseThread* DatabaseContext::databaseThread()
    151 {
    152     if (!m_databaseThread && !m_hasOpenDatabases) {
    153         // It's OK to ask for the m_databaseThread after we've requested
    154         // termination because we're still using it to execute the closing
    155         // of the database. However, it is NOT OK to create a new thread
    156         // after we've requested termination.
    157         ASSERT(!m_hasRequestedTermination);
    158 
    159         // Create the database thread on first request - but not if at least one database was already opened,
    160         // because in that case we already had a database thread and terminated it and should not create another.
    161         m_databaseThread = DatabaseThread::create();
    162         m_databaseThread->start();
    163     }
    164 
    165     return m_databaseThread.get();
    166 }
    167 
    168 bool DatabaseContext::databaseThreadAvailable()
    169 {
    170     return databaseThread() && !m_hasRequestedTermination;
    171 }
    172 
    173 void DatabaseContext::stopDatabases()
    174 {
    175     // Though we initiate termination of the DatabaseThread here in
    176     // stopDatabases(), we can't clear the m_databaseThread ref till we get to
    177     // the destructor. This is because the Databases that are managed by
    178     // DatabaseThread still rely on this ref between the context and the thread
    179     // to execute the task for closing the database. By the time we get to the
    180     // destructor, we're guaranteed that the databases are destructed (which is
    181     // why our ref count is 0 then and we're destructing). Then, the
    182     // m_databaseThread RefPtr destructor will deref and delete the
    183     // DatabaseThread.
    184 
    185     if (databaseThreadAvailable()) {
    186         m_hasRequestedTermination = true;
    187         // This blocks until the database thread finishes the cleanup task.
    188         m_databaseThread->terminate();
    189     }
    190 }
    191 
    192 bool DatabaseContext::allowDatabaseAccess() const
    193 {
    194     return toDocument(executionContext())->isActive();
    195 }
    196 
    197 SecurityOrigin* DatabaseContext::securityOrigin() const
    198 {
    199     return executionContext()->securityOrigin();
    200 }
    201 
    202 bool DatabaseContext::isContextThread() const
    203 {
    204     return executionContext()->isContextThread();
    205 }
    206 
    207 } // namespace blink
    208