summaryrefslogtreecommitdiffstats
path: root/core/java/android/database/sqlite
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-04-26 17:36:12 -0700
committerJeff Brown <jeffbrown@google.com>2012-04-26 20:12:44 -0700
commitaeee2f5d7564614da7b5e1aedb8816fc6559b2e9 (patch)
treeca80723e23536b12f8e04740849594bf00fe7e25 /core/java/android/database/sqlite
parent20c4f87b2916d05e860d11568d7db6b2d340e909 (diff)
downloadframeworks_base-aeee2f5d7564614da7b5e1aedb8816fc6559b2e9.zip
frameworks_base-aeee2f5d7564614da7b5e1aedb8816fc6559b2e9.tar.gz
frameworks_base-aeee2f5d7564614da7b5e1aedb8816fc6559b2e9.tar.bz2
Fix CancellationSignal deadlock.
Bug: 6398945 Change-Id: I5a3d4dce74009d6f1d284a8cc54c9f68daa6a9c2
Diffstat (limited to 'core/java/android/database/sqlite')
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java107
1 files changed, 55 insertions, 52 deletions
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 5c8e38b..a175662 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -594,6 +594,7 @@ public final class SQLiteConnectionPool implements Closeable {
(connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
final ConnectionWaiter waiter;
+ final int nonce;
synchronized (mLock) {
throwIfClosedLocked();
@@ -636,73 +637,75 @@ public final class SQLiteConnectionPool implements Closeable {
mConnectionWaiterQueue = waiter;
}
- if (cancellationSignal != null) {
- final int nonce = waiter.mNonce;
- cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
- @Override
- public void onCancel() {
- synchronized (mLock) {
- cancelConnectionWaiterLocked(waiter, nonce);
+ nonce = waiter.mNonce;
+ }
+
+ // Set up the cancellation listener.
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+ @Override
+ public void onCancel() {
+ synchronized (mLock) {
+ if (waiter.mNonce == nonce) {
+ cancelConnectionWaiterLocked(waiter);
}
}
- });
- }
+ }
+ });
}
-
- // Park the thread until a connection is assigned or the pool is closed.
- // Rethrow an exception from the wait, if we got one.
- long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
- long nextBusyTimeoutTime = waiter.mStartTime + busyTimeoutMillis;
- for (;;) {
- // Detect and recover from connection leaks.
- if (mConnectionLeaked.compareAndSet(true, false)) {
- synchronized (mLock) {
- wakeConnectionWaitersLocked();
+ try {
+ // Park the thread until a connection is assigned or the pool is closed.
+ // Rethrow an exception from the wait, if we got one.
+ long busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
+ long nextBusyTimeoutTime = waiter.mStartTime + busyTimeoutMillis;
+ for (;;) {
+ // Detect and recover from connection leaks.
+ if (mConnectionLeaked.compareAndSet(true, false)) {
+ synchronized (mLock) {
+ wakeConnectionWaitersLocked();
+ }
}
- }
- // Wait to be unparked (may already have happened), a timeout, or interruption.
- LockSupport.parkNanos(this, busyTimeoutMillis * 1000000L);
+ // Wait to be unparked (may already have happened), a timeout, or interruption.
+ LockSupport.parkNanos(this, busyTimeoutMillis * 1000000L);
- // Clear the interrupted flag, just in case.
- Thread.interrupted();
+ // Clear the interrupted flag, just in case.
+ Thread.interrupted();
- // Check whether we are done waiting yet.
- synchronized (mLock) {
- throwIfClosedLocked();
-
- final SQLiteConnection connection = waiter.mAssignedConnection;
- final RuntimeException ex = waiter.mException;
- if (connection != null || ex != null) {
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(null);
- }
- recycleConnectionWaiterLocked(waiter);
- if (connection != null) {
- return connection;
+ // Check whether we are done waiting yet.
+ synchronized (mLock) {
+ throwIfClosedLocked();
+
+ final SQLiteConnection connection = waiter.mAssignedConnection;
+ final RuntimeException ex = waiter.mException;
+ if (connection != null || ex != null) {
+ recycleConnectionWaiterLocked(waiter);
+ if (connection != null) {
+ return connection;
+ }
+ throw ex; // rethrow!
}
- throw ex; // rethrow!
- }
- final long now = SystemClock.uptimeMillis();
- if (now < nextBusyTimeoutTime) {
- busyTimeoutMillis = now - nextBusyTimeoutTime;
- } else {
- logConnectionPoolBusyLocked(now - waiter.mStartTime, connectionFlags);
- busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
- nextBusyTimeoutTime = now + busyTimeoutMillis;
+ final long now = SystemClock.uptimeMillis();
+ if (now < nextBusyTimeoutTime) {
+ busyTimeoutMillis = now - nextBusyTimeoutTime;
+ } else {
+ logConnectionPoolBusyLocked(now - waiter.mStartTime, connectionFlags);
+ busyTimeoutMillis = CONNECTION_POOL_BUSY_MILLIS;
+ nextBusyTimeoutTime = now + busyTimeoutMillis;
+ }
}
}
+ } finally {
+ // Remove the cancellation listener.
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(null);
+ }
}
}
// Can't throw.
- private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) {
- if (waiter.mNonce != nonce) {
- // Waiter already removed and recycled.
- return;
- }
-
+ private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) {
if (waiter.mAssignedConnection != null || waiter.mException != null) {
// Waiter is done waiting but has not woken up yet.
return;