[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

dumi at chromium.org dumi at chromium.org
Wed Dec 22 11:35:07 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit c78b68c8c5a894179d900e0787e4efeeba63aa7a
Author: dumi at chromium.org <dumi at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Jul 29 22:30:20 2010 +0000

    JavaScriptCore: Added a yield() function.
    https://bugs.webkit.org/show_bug.cgi?id=42843
    
    Reviewed by David Levin.
    
    * JavaScriptCore.exp:
    * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
    * wtf/Threading.h:
    * wtf/ThreadingPthreads.cpp:
    (WTF::yield):
    * wtf/ThreadingWin.cpp:
    (WTF::yield):
    * wtf/gtk/ThreadingGtk.cpp:
    (WTF::yield):
    * wtf/qt/ThreadingQt.cpp:
    (WTF::yield):
    
    WebCore: Interrupt all DB operations when the worker is terminating.
    https://bugs.webkit.org/show_bug.cgi?id=42843
    
    Reviewed by David Levin.
    
    Tests: fast/workers/storage/interrupt-database-sync.html
           fast/workers/storage/interrupt-database.html
    
    * bindings/js/JSCustomVoidCallback.cpp:
    (WebCore::JSCustomVoidCallback::~JSCustomVoidCallback): If the
    destructor is called on the context thread, delete m_data directly
    instead of posting a task to do that. We need to do that to make
    sure that all JS objects are destroyed before
    WorkerThreadShutdownFinishTask (in WorkerThread.cpp) calls
    WorkerContext::clearScript().
    
    * bindings/scripts/CodeGeneratorJS.pm: Same change as above, for
    all auto-generated callbacks.
    
    * bindings/scripts/test/JS/JSTestCallback.cpp:
    (WebCore::JSTestCallback::~JSTestCallback): Updated the
    expectations for run-bindings-tests.
    
    * platform/sql/SQLiteDatabase.cpp: Added the ability to interrupt
    all DB operations in progress, unless the database was closed or
    is being closed. Unlike sqlite3_interrupt(),
    SQLiteDatabase::interrupt() is sticky: once it's called, trying to
    run any statement on that database will fail with a
    SQLITE_INTERRUPT error code.
    (WebCore::SQLiteDatabase::SQLiteDatabase):
    (WebCore::SQLiteDatabase::close):
    (WebCore::SQLiteDatabase::interrupt):
    (WebCore::SQLiteDatabase::isInterrupted):
    
    * platform/sql/SQLiteDatabase.h: Added a mutex that can used by
    SQLiteStatement to check if the database was interrupted.
    (WebCore::SQLiteDatabase::databaseMutex):
    
    * platform/sql/SQLiteStatement.cpp: Changed prepare() and step()
    to check if the database was interrupted, before trying to prepare
    or run the statement. The other methods don't need to hold on to
    the DB lock while running, because they're fast, so we don't need
    to interrupt them.
    (WebCore::SQLiteStatement::prepare):
    (WebCore::SQLiteStatement::step):
    
    * storage/AbstractDatabase.cpp: Made SQLiteDatabase::interrupt()
    and isInterrupted() visible to WebSQLDatabases classes.
    (WebCore::AbstractDatabase::interrupt):
    (WebCore::AbstractDatabase::isInterrupted):
    * storage/AbstractDatabase.h:
    
    * storage/DatabaseTracker.cpp: Added a method to interrupt all
    databases in a given context.
    (WebCore::DatabaseTracker::interruptAllDatabasesForContext):
    * storage/DatabaseTracker.h:
    
    * storage/SQLStatement.cpp: Changed the exception/error reported
    when a statement is interrupted.
    (WebCore::SQLStatement::execute):
    * storage/SQLStatementSync.cpp:
    (WebCore::SQLStatementSync::execute):
    
    * storage/SQLTransaction.cpp: Changed the code to release the
    callback objects as soon as they're not needed.
    (WebCore::SQLTransaction::checkAndHandleClosedOrInterruptedDatabase):
    Changed this method to not schedule the next transaction step when
    the database is interrupted.
    (WebCore::SQLTransaction::performNextStep):
    (WebCore::SQLTransaction::performPendingCallback):
    (WebCore::SQLTransaction::deliverTransactionCallback):
    (WebCore::SQLTransaction::postflightAndCommit):
    (WebCore::SQLTransaction::deliverTransactionErrorCallback):
    (WebCore::SQLTransaction::cleanupAfterTransactionErrorCallback):
    * storage/SQLTransaction.h:
    
    * storage/chromium/DatabaseTrackerChromium.cpp: Added a method to
    interrupt all databases in a given context.
    (WebCore::DatabaseTracker::interruptAllDatabasesForContext):
    
    * workers/WorkerThread.cpp:
    (WebCore::WorkerThread::stop): Added a call to
    DatabaseTracker::interruptAllDatabasesForContext().
    
    LayoutTests: Test that terminating a worker interrupts all DB operations in that worker.
    https://bugs.webkit.org/show_bug.cgi?id=42843
    
    Reviewed by David Levin.
    
    * fast/workers/storage/interrupt-database-expected.txt: Added.
    * fast/workers/storage/interrupt-database-sync-expected.txt: Added.
    * fast/workers/storage/interrupt-database-sync.html: Added.
    * fast/workers/storage/interrupt-database.html: Added.
    * fast/workers/storage/resources/interrupt-database-sync.js: Added.
    * fast/workers/storage/resources/interrupt-database.js: Added.
    (runTransaction):
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64313 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 77f90e6..09af266 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,22 @@
+2010-07-28  Dumitru Daniliuc  <dumi at chromium.org>
+
+        Reviewed by David Levin.
+
+        Added a yield() function.
+        https://bugs.webkit.org/show_bug.cgi?id=42843
+
+        * JavaScriptCore.exp:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+        * wtf/Threading.h:
+        * wtf/ThreadingPthreads.cpp:
+        (WTF::yield):
+        * wtf/ThreadingWin.cpp:
+        (WTF::yield):
+        * wtf/gtk/ThreadingGtk.cpp:
+        (WTF::yield):
+        * wtf/qt/ThreadingQt.cpp:
+        (WTF::yield):
+
 2010-07-29  Michael Saboff  <msaboff at apple.com>
 
         Reviewed by Oliver Hunt.
diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp
index 93e01e2..b66d8df 100644
--- a/JavaScriptCore/JavaScriptCore.exp
+++ b/JavaScriptCore/JavaScriptCore.exp
@@ -367,6 +367,7 @@ __ZN3WTF5Mutex6unlockEv
 __ZN3WTF5Mutex7tryLockEv
 __ZN3WTF5MutexC1Ev
 __ZN3WTF5MutexD1Ev
+__ZN3WTF5yieldEv
 __ZN3WTF6strtodEPKcPPc
 __ZN3WTF7CString11mutableDataEv
 __ZN3WTF7CString16newUninitializedEmRPc
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index a6ff1c2..a478725 100644
--- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -330,6 +330,7 @@ EXPORTS
     ?wait at ThreadCondition@WTF@@QAEXAAVMutex at 2@@Z
     ?waitForThreadCompletion at WTF@@YAHIPAPAX at Z
     ?writable at PropertyDescriptor@JSC@@QBE_NXZ
+    ?yield at WTF@@YAXXZ
     WTFLog
     WTFLogVerbose
     WTFReportArgumentAssertionFailure
diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h
index 415a8fc..044365f 100644
--- a/JavaScriptCore/wtf/Threading.h
+++ b/JavaScriptCore/wtf/Threading.h
@@ -101,6 +101,7 @@ ThreadIdentifier currentThread();
 int waitForThreadCompletion(ThreadIdentifier, void**);
 void detachThread(ThreadIdentifier);
 
+void yield();
 
 void lockAtomicallyInitializedStaticMutex();
 void unlockAtomicallyInitializedStaticMutex();
@@ -112,5 +113,6 @@ using WTF::createThread;
 using WTF::currentThread;
 using WTF::detachThread;
 using WTF::waitForThreadCompletion;
+using WTF::yield;
 
 #endif // Threading_h
diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp
index d01cc4a..98286d3 100644
--- a/JavaScriptCore/wtf/ThreadingPthreads.cpp
+++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp
@@ -44,6 +44,7 @@
 
 #if !COMPILER(MSVC)
 #include <limits.h>
+#include <sched.h>
 #include <sys/time.h>
 #endif
 
@@ -221,6 +222,11 @@ void detachThread(ThreadIdentifier threadID)
     pthread_detach(pthreadHandle);
 }
 
+void yield()
+{
+    sched_yield();
+}
+
 ThreadIdentifier currentThread()
 {
     ThreadIdentifier id = ThreadIdentifierData::identifier();
diff --git a/JavaScriptCore/wtf/ThreadingWin.cpp b/JavaScriptCore/wtf/ThreadingWin.cpp
index c16be5a..a29fbbb 100644
--- a/JavaScriptCore/wtf/ThreadingWin.cpp
+++ b/JavaScriptCore/wtf/ThreadingWin.cpp
@@ -266,6 +266,11 @@ void detachThread(ThreadIdentifier threadID)
     clearThreadHandleForIdentifier(threadID);
 }
 
+void yield()
+{
+    ::Sleep(1);
+}
+
 ThreadIdentifier currentThread()
 {
     return static_cast<ThreadIdentifier>(GetCurrentThreadId());
diff --git a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp
index 981eacb..863ee81 100644
--- a/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp
+++ b/JavaScriptCore/wtf/gtk/ThreadingGtk.cpp
@@ -167,6 +167,11 @@ ThreadIdentifier currentThread()
     return establishIdentifierForThread(currentThread);
 }
 
+void yield()
+{
+    g_thread_yield();
+}
+
 Mutex::Mutex()
     : m_mutex(g_mutex_new())
 {
diff --git a/JavaScriptCore/wtf/qt/ThreadingQt.cpp b/JavaScriptCore/wtf/qt/ThreadingQt.cpp
index 7f81646..8041dea 100644
--- a/JavaScriptCore/wtf/qt/ThreadingQt.cpp
+++ b/JavaScriptCore/wtf/qt/ThreadingQt.cpp
@@ -208,6 +208,11 @@ ThreadIdentifier currentThread()
     return establishIdentifierForThread(currentThread);
 }
 
+void yield()
+{
+    QThread::yieldCurrentThread();
+}
+
 Mutex::Mutex()
     : m_mutex(new QMutex())
 {
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index ffc9729..9e60565 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,18 @@
+2010-07-28  Dumitru Daniliuc  <dumi at chromium.org>
+
+        Reviewed by David Levin.
+
+        Test that terminating a worker interrupts all DB operations in that worker.
+        https://bugs.webkit.org/show_bug.cgi?id=42843
+
+        * fast/workers/storage/interrupt-database-expected.txt: Added.
+        * fast/workers/storage/interrupt-database-sync-expected.txt: Added.
+        * fast/workers/storage/interrupt-database-sync.html: Added.
+        * fast/workers/storage/interrupt-database.html: Added.
+        * fast/workers/storage/resources/interrupt-database-sync.js: Added.
+        * fast/workers/storage/resources/interrupt-database.js: Added.
+        (runTransaction):
+
 2010-07-29  Victor Wang  <victorw at chromium.org>
 
         Unreviewed. Update chromium expectation for test:
diff --git a/LayoutTests/fast/workers/storage/interrupt-database-expected.txt b/LayoutTests/fast/workers/storage/interrupt-database-expected.txt
new file mode 100644
index 0000000..460a756
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/interrupt-database-expected.txt
@@ -0,0 +1,3 @@
+This test makes sure that all async database operations are immediately interrupted when the worker needs to terminate.
+PASS: database operations interrupted.
+
diff --git a/LayoutTests/fast/workers/storage/interrupt-database-sync-expected.txt b/LayoutTests/fast/workers/storage/interrupt-database-sync-expected.txt
new file mode 100644
index 0000000..3139ddc
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/interrupt-database-sync-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 7: DATABASE_ERR: DOM SQL Exception 1: The operation failed for some reason related to the database.
+CONSOLE MESSAGE: line 11: UNKNOWN_ERR: DOM SQL Exception 0: The operation failed for reasons unrelated to the database.
+This test makes sure that all sync database operations are immediately interrupted when the worker needs to terminate.
+PASS: database operations interrupted.
+
diff --git a/LayoutTests/fast/workers/storage/interrupt-database-sync.html b/LayoutTests/fast/workers/storage/interrupt-database-sync.html
new file mode 100644
index 0000000..deabee0
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/interrupt-database-sync.html
@@ -0,0 +1,48 @@
+<html>
+<head>
+<script src="../resources/worker-util.js"></script>
+<script>
+var worker;
+
+function log(message)
+{
+    document.getElementById("console").innerHTML += message + "<br>";
+}
+
+function finishTest()
+{
+    log("PASS: database operations interrupted.");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function terminateWorker()
+{
+    worker.terminate();
+    waitUntilWorkerThreadsExit(finishTest)
+}
+
+function runTest()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    worker = new Worker('resources/interrupt-database-sync.js');
+    worker.onmessage = function(event) {
+        if (event.data == "terminate")
+            terminateWorker();
+        else
+            log(event.data);
+    };
+}
+</script>
+</head>
+
+<body onload="runTest()">
+This test makes sure that all sync database operations are immediately interrupted when the worker needs to terminate.
+<pre id="console">
+</pre>
+</body>
+</html>
diff --git a/LayoutTests/fast/workers/storage/interrupt-database.html b/LayoutTests/fast/workers/storage/interrupt-database.html
new file mode 100644
index 0000000..2ff4d45
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/interrupt-database.html
@@ -0,0 +1,48 @@
+<html>
+<head>
+<script src="../resources/worker-util.js"></script>
+<script>
+var worker;
+
+function log(message)
+{
+    document.getElementById("console").innerHTML += message + "<br>";
+}
+
+function finishTest()
+{
+    log("PASS: database operations interrupted.");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+
+function terminateWorker()
+{
+    worker.terminate();
+    waitUntilWorkerThreadsExit(finishTest)
+}
+
+function runTest()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    worker = new Worker('resources/interrupt-database.js');
+    worker.onmessage = function(event) {
+        if (event.data == "terminate")
+            terminateWorker();
+        else
+            log(event.data);
+    };
+}
+</script>
+</head>
+
+<body onload="runTest()">
+This test makes sure that all async database operations are immediately interrupted when the worker needs to terminate.
+<pre id="console">
+</pre>
+</body>
+</html>
diff --git a/LayoutTests/fast/workers/storage/resources/interrupt-database-sync.js b/LayoutTests/fast/workers/storage/resources/interrupt-database-sync.js
new file mode 100644
index 0000000..e533f08
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/resources/interrupt-database-sync.js
@@ -0,0 +1,11 @@
+var db = openDatabaseSync("InterruptDatabaseSyncTest", "1", "", 1);
+db.transaction(function(tx) {
+    tx.executeSql("CREATE TABLE IF NOT EXISTS Test (Foo INT)");
+    var counter = 0;
+    while (true) {
+        // Put both statements on the same line, to make sure the exception is always reported on the same line.
+        tx.executeSql("INSERT INTO Test VALUES (1)"); tx.executeSql("DELETE FROM Test WHERE Foo = 1");
+        if (++counter == 100)
+            postMessage("terminate");
+    }
+});
diff --git a/LayoutTests/fast/workers/storage/resources/interrupt-database.js b/LayoutTests/fast/workers/storage/resources/interrupt-database.js
new file mode 100644
index 0000000..3f71a45
--- /dev/null
+++ b/LayoutTests/fast/workers/storage/resources/interrupt-database.js
@@ -0,0 +1,19 @@
+var counter = 0;
+function runTransaction()
+{
+    db.transaction(function(tx) {
+        tx.executeSql("INSERT INTO Test VALUES (1)");
+        tx.executeSql("DELETE FROM Test WHERE Foo = 1");
+        if (++counter == 100)
+            postMessage("terminate");
+    }, null, runTransaction);
+}
+
+var db = openDatabase("InterruptDatabaseTest", "1", "", 1);
+db.transaction(function(tx) {
+    tx.executeSql("CREATE TABLE IF NOT EXISTS Test (Foo INT)");
+}, function(error) {
+    postMessage("Error: " + error.message);
+}, function() {
+    runTransaction();
+});
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 1854cd5..936b940 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,89 @@
+2010-07-28  Dumitru Daniliuc  <dumi at chromium.org>
+
+        Reviewed by David Levin.
+
+        Interrupt all DB operations when the worker is terminating.
+        https://bugs.webkit.org/show_bug.cgi?id=42843
+
+        Tests: fast/workers/storage/interrupt-database-sync.html
+               fast/workers/storage/interrupt-database.html
+
+        * bindings/js/JSCustomVoidCallback.cpp:
+        (WebCore::JSCustomVoidCallback::~JSCustomVoidCallback): If the
+        destructor is called on the context thread, delete m_data directly
+        instead of posting a task to do that. We need to do that to make
+        sure that all JS objects are destroyed before
+        WorkerThreadShutdownFinishTask (in WorkerThread.cpp) calls
+        WorkerContext::clearScript().
+
+        * bindings/scripts/CodeGeneratorJS.pm: Same change as above, for
+        all auto-generated callbacks.
+
+        * bindings/scripts/test/JS/JSTestCallback.cpp:
+        (WebCore::JSTestCallback::~JSTestCallback): Updated the
+        expectations for run-bindings-tests.
+
+        * platform/sql/SQLiteDatabase.cpp: Added the ability to interrupt
+        all DB operations in progress, unless the database was closed or
+        is being closed. Unlike sqlite3_interrupt(),
+        SQLiteDatabase::interrupt() is sticky: once it's called, trying to
+        run any statement on that database will fail with a
+        SQLITE_INTERRUPT error code.
+        (WebCore::SQLiteDatabase::SQLiteDatabase):
+        (WebCore::SQLiteDatabase::close):
+        (WebCore::SQLiteDatabase::interrupt):
+        (WebCore::SQLiteDatabase::isInterrupted):
+
+        * platform/sql/SQLiteDatabase.h: Added a mutex that can used by
+        SQLiteStatement to check if the database was interrupted.
+        (WebCore::SQLiteDatabase::databaseMutex):
+
+        * platform/sql/SQLiteStatement.cpp: Changed prepare() and step()
+        to check if the database was interrupted, before trying to prepare
+        or run the statement. The other methods don't need to hold on to
+        the DB lock while running, because they're fast, so we don't need
+        to interrupt them.
+        (WebCore::SQLiteStatement::prepare):
+        (WebCore::SQLiteStatement::step):
+
+        * storage/AbstractDatabase.cpp: Made SQLiteDatabase::interrupt()
+        and isInterrupted() visible to WebSQLDatabases classes.
+        (WebCore::AbstractDatabase::interrupt):
+        (WebCore::AbstractDatabase::isInterrupted):
+        * storage/AbstractDatabase.h:
+
+        * storage/DatabaseTracker.cpp: Added a method to interrupt all
+        databases in a given context.
+        (WebCore::DatabaseTracker::interruptAllDatabasesForContext):
+        * storage/DatabaseTracker.h:
+
+        * storage/SQLStatement.cpp: Changed the exception/error reported
+        when a statement is interrupted.
+        (WebCore::SQLStatement::execute):
+        * storage/SQLStatementSync.cpp:
+        (WebCore::SQLStatementSync::execute):
+
+        * storage/SQLTransaction.cpp: Changed the code to release the
+        callback objects as soon as they're not needed.
+        (WebCore::SQLTransaction::checkAndHandleClosedOrInterruptedDatabase):
+        Changed this method to not schedule the next transaction step when
+        the database is interrupted.
+        (WebCore::SQLTransaction::performNextStep):
+        (WebCore::SQLTransaction::performPendingCallback):
+        (WebCore::SQLTransaction::deliverTransactionCallback):
+        (WebCore::SQLTransaction::postflightAndCommit):
+        (WebCore::SQLTransaction::deliverTransactionErrorCallback):
+        (WebCore::SQLTransaction::cleanupAfterTransactionErrorCallback):
+        * storage/SQLTransaction.h:
+
+        * storage/chromium/DatabaseTrackerChromium.cpp: Added a method to
+        interrupt all databases in a given context.
+        (WebCore::DatabaseTracker::interruptAllDatabasesForContext):
+
+        * workers/WorkerThread.cpp:
+        (WebCore::WorkerThread::stop): Added a call to
+        DatabaseTracker::interruptAllDatabasesForContext().
+
 2010-07-29  Bernhard Bauer  <bauerb at chromium.org>
 
         Reviewed by Darin Fisher.
diff --git a/WebCore/bindings/js/JSCustomVoidCallback.cpp b/WebCore/bindings/js/JSCustomVoidCallback.cpp
index d5c4ac3..96b5412 100644
--- a/WebCore/bindings/js/JSCustomVoidCallback.cpp
+++ b/WebCore/bindings/js/JSCustomVoidCallback.cpp
@@ -48,7 +48,10 @@ JSCustomVoidCallback::JSCustomVoidCallback(JSObject* callback, JSDOMGlobalObject
 
 JSCustomVoidCallback::~JSCustomVoidCallback()
 {
-    m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));
+    if (m_scriptExecutionContext->isContextThread())
+        delete m_data;
+    else
+        m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));
 #ifndef NDEBUG
     m_data = 0;
 #endif
diff --git a/WebCore/bindings/scripts/CodeGeneratorJS.pm b/WebCore/bindings/scripts/CodeGeneratorJS.pm
index 05f532c..dd8c87c 100644
--- a/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -2151,7 +2151,10 @@ sub GenerateCallbackImplementation
     # Destructor
     push(@implContent, "${className}::~${className}()\n");
     push(@implContent, "{\n");
-    push(@implContent, "    m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));\n");
+    push(@implContent, "    if (m_scriptExecutionContext->isContextThread())\n");
+    push(@implContent, "        delete m_data;\n");
+    push(@implContent, "    else\n");
+    push(@implContent, "        m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));\n");
     push(@implContent, "#ifndef NDEBUG\n");
     push(@implContent, "    m_data = 0;\n");
     push(@implContent, "#endif\n");
diff --git a/WebCore/bindings/scripts/test/JS/JSTestCallback.cpp b/WebCore/bindings/scripts/test/JS/JSTestCallback.cpp
index 043a6ed..6f6b568 100644
--- a/WebCore/bindings/scripts/test/JS/JSTestCallback.cpp
+++ b/WebCore/bindings/scripts/test/JS/JSTestCallback.cpp
@@ -43,7 +43,10 @@ JSTestCallback::JSTestCallback(JSObject* callback, JSDOMGlobalObject* globalObje
 
 JSTestCallback::~JSTestCallback()
 {
-    m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));
+    if (m_scriptExecutionContext->isContextThread())
+        delete m_data;
+    else
+        m_scriptExecutionContext->postTask(DeleteCallbackDataTask::create(m_data));
 #ifndef NDEBUG
     m_data = 0;
 #endif
diff --git a/WebCore/platform/sql/SQLiteDatabase.cpp b/WebCore/platform/sql/SQLiteDatabase.cpp
index 75fc032..2ca5ba4 100644
--- a/WebCore/platform/sql/SQLiteDatabase.cpp
+++ b/WebCore/platform/sql/SQLiteDatabase.cpp
@@ -31,8 +31,8 @@
 #include "Logging.h"
 #include "SQLiteFileSystem.h"
 #include "SQLiteStatement.h"
-
 #include <sqlite3.h>
+#include <wtf/Threading.h>
 
 namespace WebCore {
 
@@ -42,7 +42,7 @@ const int SQLResultOk = SQLITE_OK;
 const int SQLResultRow = SQLITE_ROW;
 const int SQLResultSchema = SQLITE_SCHEMA;
 const int SQLResultFull = SQLITE_FULL;
-
+const int SQLResultInterrupt = SQLITE_INTERRUPT;
 
 SQLiteDatabase::SQLiteDatabase()
     : m_db(0)
@@ -50,6 +50,7 @@ SQLiteDatabase::SQLiteDatabase()
     , m_transactionInProgress(false)
     , m_sharable(false)
     , m_openingThread(0)
+    , m_interrupted(false)
 {
 }
 
@@ -83,15 +84,38 @@ bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase)
 void SQLiteDatabase::close()
 {
     if (m_db) {
-        // FIXME: This is being called on themain thread during JS GC. <rdar://problem/5739818>
-        // ASSERT(currentThread() == m_openingThread);
-        sqlite3_close(m_db);
-        m_db = 0;
+        ASSERT(currentThread() == m_openingThread);
+        sqlite3* db = m_db;
+        {
+            MutexLocker locker(m_databaseClosingMutex);
+            m_db = 0;
+        }
+        sqlite3_close(db);
     }
 
     m_openingThread = 0;
 }
 
+void SQLiteDatabase::interrupt()
+{
+    m_interrupted = true;
+    while (!m_lockingMutex.tryLock()) {
+        MutexLocker locker(m_databaseClosingMutex);
+        if (!m_db)
+            return;
+        sqlite3_interrupt(m_db);
+        yield();
+    }
+
+    m_lockingMutex.unlock();
+}
+
+bool SQLiteDatabase::isInterrupted()
+{
+    ASSERT(!m_lockingMutex.tryLock());
+    return m_interrupted;
+}
+
 void SQLiteDatabase::setFullsync(bool fsync) 
 {
     if (fsync) 
@@ -397,16 +421,6 @@ void SQLiteDatabase::enableAuthorizer(bool enable)
         sqlite3_set_authorizer(m_db, NULL, 0);
 }
 
-void SQLiteDatabase::lock()
-{
-    m_lockingMutex.lock();
-}
-
-void SQLiteDatabase::unlock()
-{
-    m_lockingMutex.unlock();
-}
-
 bool SQLiteDatabase::isAutoCommitOn() const
 {
     return sqlite3_get_autocommit(m_db);
diff --git a/WebCore/platform/sql/SQLiteDatabase.h b/WebCore/platform/sql/SQLiteDatabase.h
index c5924c0..8151380 100644
--- a/WebCore/platform/sql/SQLiteDatabase.h
+++ b/WebCore/platform/sql/SQLiteDatabase.h
@@ -48,6 +48,7 @@ extern const int SQLResultOk;
 extern const int SQLResultRow;
 extern const int SQLResultSchema;
 extern const int SQLResultFull;
+extern const int SQLResultInterrupt;
 
 class SQLiteDatabase : public Noncopyable {
     friend class SQLiteTransaction;
@@ -58,6 +59,8 @@ public:
     bool open(const String& filename, bool forWebSQLDatabase = false);
     bool isOpen() const { return m_db; }
     void close();
+    void interrupt();
+    bool isInterrupted();
 
     bool executeCommand(const String&);
     bool returnsAtLeastOneResult(const String&);
@@ -105,9 +108,7 @@ public:
     
     void setAuthorizer(PassRefPtr<DatabaseAuthorizer>);
 
-    // (un)locks the database like a mutex
-    void lock();
-    void unlock();
+    Mutex& databaseMutex() { return m_lockingMutex; }
     bool isAutoCommitOn() const;
 
     // The SQLite AUTO_VACUUM pragma can be either NONE, FULL, or INCREMENTAL.
@@ -149,7 +150,9 @@ private:
 
     Mutex m_lockingMutex;
     ThreadIdentifier m_openingThread;
-    
+
+    Mutex m_databaseClosingMutex;
+    bool m_interrupted;
 }; // class SQLiteDatabase
 
 } // namespace WebCore
diff --git a/WebCore/platform/sql/SQLiteStatement.cpp b/WebCore/platform/sql/SQLiteStatement.cpp
index 78bbfeb..ac467a6 100644
--- a/WebCore/platform/sql/SQLiteStatement.cpp
+++ b/WebCore/platform/sql/SQLiteStatement.cpp
@@ -61,6 +61,11 @@ SQLiteStatement::~SQLiteStatement()
 int SQLiteStatement::prepare()
 {
     ASSERT(!m_isPrepared);
+
+    MutexLocker databaseLock(m_database.databaseMutex());
+    if (m_database.isInterrupted())
+        return SQLITE_INTERRUPT;
+
     const void* tail = 0;
     LOG(SQLDatabase, "SQL - prepare - %s", m_query.ascii().data());
     String strippedQuery = m_query.stripWhiteSpace();
@@ -88,6 +93,11 @@ int SQLiteStatement::prepare()
 int SQLiteStatement::step()
 {
     ASSERT(m_isPrepared);
+
+    MutexLocker databaseLock(m_database.databaseMutex());
+    if (m_database.isInterrupted())
+        return SQLITE_INTERRUPT;
+
     if (!m_statement)
         return SQLITE_OK;
     LOG(SQLDatabase, "SQL - step - %s", m_query.ascii().data());
diff --git a/WebCore/storage/AbstractDatabase.cpp b/WebCore/storage/AbstractDatabase.cpp
index bcc5d06..7827ec8 100644
--- a/WebCore/storage/AbstractDatabase.cpp
+++ b/WebCore/storage/AbstractDatabase.cpp
@@ -474,6 +474,17 @@ void AbstractDatabase::incrementalVacuumIfNeeded()
         m_sqliteDatabase.runIncrementalVacuumCommand();
 }
 
+void AbstractDatabase::interrupt()
+{
+    m_sqliteDatabase.interrupt();
+}
+
+bool AbstractDatabase::isInterrupted()
+{
+    MutexLocker locker(m_sqliteDatabase.databaseMutex());
+    return m_sqliteDatabase.isInterrupted();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/AbstractDatabase.h b/WebCore/storage/AbstractDatabase.h
index e302909..3d8d363 100644
--- a/WebCore/storage/AbstractDatabase.h
+++ b/WebCore/storage/AbstractDatabase.h
@@ -68,6 +68,8 @@ public:
 
     unsigned long long maximumSize() const;
     void incrementalVacuumIfNeeded();
+    void interrupt();
+    bool isInterrupted();
 
     // FIXME: move all version-related methods to a DatabaseVersionTracker class
     bool versionMatchesExpected() const;
diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp
index de38ec3..0764db0 100644
--- a/WebCore/storage/DatabaseTracker.cpp
+++ b/WebCore/storage/DatabaseTracker.cpp
@@ -235,6 +235,35 @@ void DatabaseTracker::databaseChanged(AbstractDatabase* database)
     originQuotaManager().markDatabase(database);
 }
 
+void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
+{
+    Vector<RefPtr<AbstractDatabase> > openDatabases;
+    {
+        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+        if (!m_openDatabaseMap)
+            return;
+
+        DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin());
+        if (!nameMap)
+            return;
+
+        DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
+        for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
+            DatabaseSet* databaseSet = dbNameMapIt->second;
+            DatabaseSet::const_iterator dbSetEndIt = databaseSet->end();
+            for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) {
+                if ((*dbSetIt)->scriptExecutionContext() == context)
+                    openDatabases.append(*dbSetIt);
+            }
+        }
+    }
+
+    Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesEndIt = openDatabases.end();
+    for (Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt)
+        (*openDatabasesIt)->interrupt();
+}
+
 String DatabaseTracker::originPath(SecurityOrigin* origin) const
 {
     return SQLiteFileSystem::appendDatabaseFileNameToPath(m_databaseDirectoryPath.threadsafeCopy(), origin->databaseIdentifier());
diff --git a/WebCore/storage/DatabaseTracker.h b/WebCore/storage/DatabaseTracker.h
index 094ee66..1557f0a 100644
--- a/WebCore/storage/DatabaseTracker.h
+++ b/WebCore/storage/DatabaseTracker.h
@@ -78,6 +78,8 @@ public:
     unsigned long long getMaxSizeForDatabase(const AbstractDatabase*);
     void databaseChanged(AbstractDatabase*);
 
+    void interruptAllDatabasesForContext(const ScriptExecutionContext*);
+
 private:
     DatabaseTracker(const String& databasePath);
 
diff --git a/WebCore/storage/SQLStatement.cpp b/WebCore/storage/SQLStatement.cpp
index 2d7d78e..9dd249a 100644
--- a/WebCore/storage/SQLStatement.cpp
+++ b/WebCore/storage/SQLStatement.cpp
@@ -78,7 +78,7 @@ bool SQLStatement::execute(Database* db)
 
     if (result != SQLResultOk) {
         LOG(StorageAPI, "Unable to verify correctness of statement %s - error %i (%s)", m_statement.ascii().data(), result, database->lastErrorMsg());
-        m_error = SQLError::create(SQLError::SYNTAX_ERR, database->lastErrorMsg());
+        m_error = SQLError::create(result == SQLResultInterrupt ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, database->lastErrorMsg());
         return false;
     }
 
@@ -86,7 +86,7 @@ bool SQLStatement::execute(Database* db)
     // If this is the case, they might be trying to do something fishy or malicious
     if (statement.bindParameterCount() != m_arguments.size()) {
         LOG(StorageAPI, "Bind parameter count doesn't match number of question marks");
-        m_error = SQLError::create(SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count");
+        m_error = SQLError::create(db->isInterrupted() ? SQLError::DATABASE_ERR : SQLError::SYNTAX_ERR, "number of '?'s in statement string does not match argument count");
         return false;
     }
 
diff --git a/WebCore/storage/SQLStatementSync.cpp b/WebCore/storage/SQLStatementSync.cpp
index 7be3f50..e47919f 100644
--- a/WebCore/storage/SQLStatementSync.cpp
+++ b/WebCore/storage/SQLStatementSync.cpp
@@ -61,12 +61,12 @@ PassRefPtr<SQLResultSet> SQLStatementSync::execute(DatabaseSync* db, ExceptionCo
     SQLiteStatement statement(*database, m_statement);
     int result = statement.prepare();
     if (result != SQLResultOk) {
-        ec = SQLException::SYNTAX_ERR;
+        ec = (result == SQLResultInterrupt ? SQLException::DATABASE_ERR : SQLException::SYNTAX_ERR);
         return 0;
     }
 
     if (statement.bindParameterCount() != m_arguments.size()) {
-        ec = SQLException::SYNTAX_ERR;
+        ec = (db->isInterrupted()? SQLException::DATABASE_ERR : SQLException::SYNTAX_ERR);
         return 0;
     }
 
diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp
index e43d844..454ea63 100644
--- a/WebCore/storage/SQLTransaction.cpp
+++ b/WebCore/storage/SQLTransaction.cpp
@@ -146,17 +146,22 @@ const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod
 }
 #endif
 
-void SQLTransaction::checkAndHandleClosedDatabase()
+void SQLTransaction::checkAndHandleClosedOrInterruptedDatabase()
 {
-    if (m_database->opened())
+    if (m_database->opened() && !m_database->isInterrupted())
         return;
 
     // If the database was stopped, don't do anything and cancel queued work
-    LOG(StorageAPI, "Database was stopped - cancelling work for this transaction");
+    LOG(StorageAPI, "Database was stopped or interrupted - cancelling work for this transaction");
     MutexLocker locker(m_statementMutex);
     m_statementQueue.clear();
     m_nextStep = 0;
 
+    // Release the unneeded callbacks, to break reference cycles.
+    m_callback = 0;
+    m_successCallback = 0;
+    m_errorCallback = 0;
+
     // The next steps should be executed only if we're on the DB thread.
     if (currentThread() != database()->scriptExecutionContext()->databaseThread()->getThreadID())
         return;
@@ -183,7 +188,7 @@ bool SQLTransaction::performNextStep()
            m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback ||
            m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback);
 
-    checkAndHandleClosedDatabase();
+    checkAndHandleClosedOrInterruptedDatabase();
 
     if (m_nextStep)
         (this->*m_nextStep)();
@@ -202,7 +207,7 @@ void SQLTransaction::performPendingCallback()
            m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback ||
            m_nextStep == &SQLTransaction::deliverSuccessCallback);
 
-    checkAndHandleClosedDatabase();
+    checkAndHandleClosedOrInterruptedDatabase();
 
     if (m_nextStep)
         (this->*m_nextStep)();
@@ -292,6 +297,7 @@ void SQLTransaction::deliverTransactionCallback()
         m_executeSqlAllowed = true;
         shouldDeliverErrorCallback = !m_callback->handleEvent(m_database->scriptExecutionContext(), this);
         m_executeSqlAllowed = false;
+        m_callback = 0;
     }
 
     // Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback
@@ -459,6 +465,7 @@ void SQLTransaction::postflightAndCommit()
 
     // If the commit failed, the transaction will still be marked as "in progress"
     if (m_sqliteTransaction->inProgress()) {
+        m_successCallback = 0;
         m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction");
         handleTransactionError(false);
         return;
@@ -473,7 +480,6 @@ void SQLTransaction::postflightAndCommit()
         m_database->transactionClient()->didCommitWriteTransaction(database());
 
     // Now release our unneeded callbacks, to break reference cycles.
-    m_callback = 0;
     m_errorCallback = 0;
 
     // Transaction Step 10 - Deliver success callback, if there is one
@@ -546,8 +552,10 @@ void SQLTransaction::deliverTransactionErrorCallback()
 
     // Transaction Step 12 - If exists, invoke error callback with the last
     // error to have occurred in this transaction.
-    if (m_errorCallback)
+    if (m_errorCallback) {
         m_errorCallback->handleEvent(m_database->scriptExecutionContext(), m_transactionError.get());
+        m_errorCallback = 0;
+    }
 
     m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback;
     LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this);
@@ -579,10 +587,6 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback()
     ASSERT(!m_database->sqliteDatabase().transactionInProgress());
     m_nextStep = 0;
 
-    // Now release our callbacks, to break reference cycles.
-    m_callback = 0;
-    m_errorCallback = 0;
-
     // Now release the lock on this database
     m_database->transactionCoordinator()->releaseLock(this);
 }
diff --git a/WebCore/storage/SQLTransaction.h b/WebCore/storage/SQLTransaction.h
index 5c62ca2..2eb200b 100644
--- a/WebCore/storage/SQLTransaction.h
+++ b/WebCore/storage/SQLTransaction.h
@@ -87,7 +87,7 @@ private:
 
     void enqueueStatement(PassRefPtr<SQLStatement>);
 
-    void checkAndHandleClosedDatabase();
+    void checkAndHandleClosedOrInterruptedDatabase();
 
     void acquireLock();
     void openTransactionAndPreflight();
diff --git a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
index aad4ed9..361e203 100644
--- a/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
+++ b/WebCore/storage/chromium/DatabaseTrackerChromium.cpp
@@ -174,6 +174,35 @@ unsigned long long DatabaseTracker::getMaxSizeForDatabase(const AbstractDatabase
     return databaseSize + spaceAvailable;
 }
 
+void DatabaseTracker::interruptAllDatabasesForContext(const ScriptExecutionContext* context)
+{
+    Vector<RefPtr<AbstractDatabase> > openDatabases;
+    {
+        MutexLocker openDatabaseMapLock(m_openDatabaseMapGuard);
+
+        if (!m_openDatabaseMap)
+            return;
+
+        DatabaseNameMap* nameMap = m_openDatabaseMap->get(context->securityOrigin());
+        if (!nameMap)
+            return;
+
+        DatabaseNameMap::const_iterator dbNameMapEndIt = nameMap->end();
+        for (DatabaseNameMap::const_iterator dbNameMapIt = nameMap->begin(); dbNameMapIt != dbNameMapEndIt; ++dbNameMapIt) {
+            DatabaseSet* databaseSet = dbNameMapIt->second;
+            DatabaseSet::const_iterator dbSetEndIt = databaseSet->end();
+            for (DatabaseSet::const_iterator dbSetIt = databaseSet->begin(); dbSetIt != dbSetEndIt; ++dbSetIt) {
+                if ((*dbSetIt)->scriptExecutionContext() == context)
+                    openDatabases.append(*dbSetIt);
+            }
+        }
+    }
+
+    Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesEndIt = openDatabases.end();
+    for (Vector<RefPtr<AbstractDatabase> >::const_iterator openDatabasesIt = openDatabases.begin(); openDatabasesIt != openDatabasesEndIt; ++openDatabasesIt)
+        (*openDatabasesIt)->interrupt();
+}
+
 }
 
 #endif // ENABLE(DATABASE)
diff --git a/WebCore/workers/WorkerThread.cpp b/WebCore/workers/WorkerThread.cpp
index 96ca89b..d6a1e05 100644
--- a/WebCore/workers/WorkerThread.cpp
+++ b/WebCore/workers/WorkerThread.cpp
@@ -30,7 +30,6 @@
 
 #include "WorkerThread.h"
 
-#include "DatabaseTask.h"
 #include "DedicatedWorkerContext.h"
 #include "KURL.h"
 #include "PlatformString.h"
@@ -41,6 +40,11 @@
 #include <utility>
 #include <wtf/Noncopyable.h>
 
+#if ENABLE(DATABASE)
+#include "DatabaseTask.h"
+#include "DatabaseTracker.h"
+#endif
+
 namespace WebCore {
 
 static Mutex& threadCountMutex()
@@ -225,6 +229,10 @@ void WorkerThread::stop()
     if (m_workerContext) {
         m_workerContext->script()->forbidExecution(WorkerScriptController::TerminateRunningScript);
 
+#if ENABLE(DATABASE)
+        DatabaseTracker::tracker().interruptAllDatabasesForContext(m_workerContext.get());
+#endif
+
     // FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction.
     // This can likely use the same mechanism as used for databases above.
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list