void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*) { IDB_TRACE("IDBTransactionBackendImpl::taskTimerFired"); ASSERT(!isTaskQueueEmpty()); if (m_state == StartPending) { m_transaction.begin(); m_state = Running; } // The last reference to this object may be released while performing the // tasks. Take take a self reference to keep this object alive so that // the loop termination conditions can be checked. RefPtr<IDBTransactionBackendImpl> protect(this); TaskQueue* taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; while (!taskQueue->isEmpty() && m_state != Finished) { ASSERT(m_state == Running); OwnPtr<Operation> task(taskQueue->takeFirst()); task->perform(this); // Event itself may change which queue should be processed next. taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; } // If there are no pending tasks, we haven't already committed/aborted, // and the front-end requested a commit, it is now safe to do so. if (!hasPendingTasks() && m_state != Finished && m_commitPending) commit(); }
void TaskDispatcher4StdThread::awaitTask() { std::unique_lock<std::mutex> lock(mStartTasksProcessing); if (!hasPendingTasks()) { mWaitForTasks.wait(lock); } }
void IDBTransactionBackendImpl::commit() { IDB_TRACE("IDBTransactionBackendImpl::commit"); // In multiprocess ports, front-end may have requested a commit but an abort has already // been initiated asynchronously by the back-end. if (m_state == Finished) return; ASSERT(m_state == Unused || m_state == Running); m_commitPending = true; // Front-end has requested a commit, but there may be tasks like createIndex which // are considered synchronous by the front-end but are processed asynchronously. if (hasPendingTasks()) return; // The last reference to this object may be released while performing the // commit steps below. We therefore take a self reference to keep ourselves // alive while executing this method. RefPtr<IDBTransactionBackendImpl> protect(this); bool unused = m_state == Unused; m_state = Finished; bool committed = unused || m_transaction.commit(); // Backing store resources (held via cursors) must be released before script callbacks // are fired, as the script callbacks may release references and allow the backing store // itself to be released, and order is critical. closeOpenCursors(); m_transaction.reset(); // Transactions must also be marked as completed before the front-end is notified, as // the transaction completion unblocks operations like closing connections. if (!unused) m_database->transactionCoordinator()->didFinishTransaction(this); m_database->transactionFinished(this); if (committed) { m_callbacks->onComplete(m_id); m_database->transactionFinishedAndCompleteFired(this); } else { m_callbacks->onAbort(m_id, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error committing transaction.")); m_database->transactionFinishedAndAbortFired(this); } m_database = 0; }