// Can't throw. private void wakeConnectionWaitersLocked() { // Unpark all waiters that have requests that we can fulfill. // This method is designed to not throw runtime exceptions, although we might send // a waiter an exception for it to rethrow. ConnectionWaiter predecessor = null; ConnectionWaiter waiter = mConnectionWaiterQueue; boolean primaryConnectionNotAvailable = false; boolean nonPrimaryConnectionNotAvailable = false; while (waiter != null) { boolean unpark = false; if (!mIsOpen) { unpark = true; } else { try { SQLiteConnection connection = null; if (!waiter.mWantPrimaryConnection && !nonPrimaryConnectionNotAvailable) { connection = tryAcquireNonPrimaryConnectionLocked( waiter.mSql, waiter.mConnectionFlags); // might throw if (connection == null) { nonPrimaryConnectionNotAvailable = true; } } if (connection == null && !primaryConnectionNotAvailable) { connection = tryAcquirePrimaryConnectionLocked(waiter.mConnectionFlags); // might throw if (connection == null) { primaryConnectionNotAvailable = true; } } if (connection != null) { waiter.mAssignedConnection = connection; unpark = true; } else if (nonPrimaryConnectionNotAvailable && primaryConnectionNotAvailable) { // There are no connections available and the pool is still open. // We cannot fulfill any more connection requests, so stop here. break; } } catch (RuntimeException ex) { // Let the waiter handle the exception from acquiring a connection. waiter.mException = ex; unpark = true; } } final ConnectionWaiter successor = waiter.mNext; if (unpark) { if (predecessor != null) { predecessor.mNext = successor; } else { mConnectionWaiterQueue = successor; } waiter.mNext = null; LockSupport.unpark(waiter.mThread); } else { predecessor = waiter; } waiter = successor; } }
// Can't throw. private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) { if (waiter.mAssignedConnection != null || waiter.mException != null) { // Waiter is done waiting but has not woken up yet. return; } // Waiter must still be waiting. Dequeue it. ConnectionWaiter predecessor = null; ConnectionWaiter current = mConnectionWaiterQueue; while (current != waiter) { assert current != null; predecessor = current; current = current.mNext; } if (predecessor != null) { predecessor.mNext = waiter.mNext; } else { mConnectionWaiterQueue = waiter.mNext; } // Send the waiter an exception and unpark it. waiter.mException = new OperationCanceledException(); LockSupport.unpark(waiter.mThread); // Check whether removing this waiter will enable other waiters to make progress. wakeConnectionWaitersLocked(); }
private void recycleConnectionWaiterLocked(ConnectionWaiter waiter) { waiter.mNext = mConnectionWaiterPool; waiter.mThread = null; waiter.mSql = null; waiter.mAssignedConnection = null; waiter.mException = null; waiter.mNonce += 1; mConnectionWaiterPool = waiter; }