bool LockManager::unlock(LockRequest* request) { invariant(request->lock); // Fast path for decrementing multiple references of the same lock. It is safe to do this // without locking, because 1) all calls for the same lock request must be done on the same // thread and 2) if there are lock requests hanging of a given LockHead, then this lock // will never disappear. request->recursiveCount--; if ((request->status == LockRequest::STATUS_GRANTED) && (request->recursiveCount > 0)) { return false; } LockHead* lock = request->lock; LockBucket* bucket = _getBucket(lock->resourceId); scoped_spinlock scopedLock(bucket->mutex); invariant(lock->grantedQueue != NULL); invariant(lock->grantedModes != 0); if (request->status == LockRequest::STATUS_WAITING) { // This cancels a pending lock request invariant(request->recursiveCount == 0); lock->removeFromConflictQueue(request); lock->changeConflictModeCount(request->mode, LockHead::Decrement); } else if (request->status == LockRequest::STATUS_CONVERTING) { // This cancels a pending convert request invariant(request->recursiveCount > 0); // Lock only goes from GRANTED to CONVERTING, so cancelling the conversion request // brings it back to the previous granted mode. request->status = LockRequest::STATUS_GRANTED; lock->conversionsCount--; lock->changeGrantedModeCount(request->convertMode, LockHead::Decrement); request->convertMode = MODE_NONE; _onLockModeChanged(lock, lock->grantedCounts[request->convertMode] == 0); } else if (request->status == LockRequest::STATUS_GRANTED) { // This releases a currently held lock and is the most common path, so it should be // as efficient as possible. invariant(request->recursiveCount == 0); // Remove from the granted list lock->removeFromGrantedQueue(request); lock->changeGrantedModeCount(request->mode, LockHead::Decrement); _onLockModeChanged(lock, lock->grantedCounts[request->mode] == 0); } else { // Invalid request status invariant(false); } return (request->recursiveCount == 0); }
void LockManager::downgrade(LockRequest* request, LockMode newMode) { invariant(request->lock); invariant(request->status == LockRequest::STATUS_GRANTED); invariant(request->recursiveCount > 0); // The conflict set of the newMode should be a subset of the conflict set of the old mode. // Can't downgrade from S -> IX for example. invariant((LockConflictsTable[request->mode] | LockConflictsTable[newMode]) == LockConflictsTable[request->mode]); LockHead* lock = request->lock; LockBucket* bucket = _getBucket(lock->resourceId); SimpleMutex::scoped_lock scopedLock(bucket->mutex); invariant(lock->grantedQueueBegin != NULL); invariant(lock->grantedQueueEnd != NULL); invariant(lock->grantedModes != 0); lock->changeGrantedModeCount(newMode, LockHead::Increment); lock->changeGrantedModeCount(request->mode, LockHead::Decrement); request->mode = newMode; _onLockModeChanged(lock, true); }