1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "common/vsoc/shm/lock.h" 17 18 #include "common/libs/glog/logging.h" 19 #include "common/vsoc/lib/compat.h" 20 #include "common/vsoc/lib/region_view.h" 21 22 #include <stdlib.h> 23 24 using vsoc::layout::Sides; 25 26 namespace { 27 28 const uint32_t LockFree = 0U; 29 const uint32_t GuestWaitingFlag = (Sides::Guest << 30); 30 const uint32_t HostWaitingFlag = (Sides::Host << 30); 31 const uint32_t OurWaitingFlag = (Sides::OurSide << 30); 32 static_assert(GuestWaitingFlag, "GuestWaitingFlag is 0"); 33 static_assert(HostWaitingFlag, "HostWaitingFlag is 0"); 34 static_assert((GuestWaitingFlag & HostWaitingFlag) == 0, 35 "Waiting flags should not share bits"); 36 37 // Set if the current owner is the host 38 const uint32_t HostIsOwner = 0x20000000U; 39 40 // PID_MAX_LIMIT appears to be 0x00400000U, so we're probably ok here 41 const uint32_t OwnerMask = 0x3FFFFFFFU; 42 43 uint32_t MakeOwnerTid(uint32_t raw_tid) { 44 if (Sides::OurSide == Sides::Host) { 45 return (raw_tid | HostIsOwner) & OwnerMask; 46 } else { 47 return raw_tid & (OwnerMask & ~HostIsOwner); 48 } 49 } 50 51 }; // namespace 52 53 namespace vsoc { 54 /** 55 * This is a generic synchronization primitive that provides space for the 56 * owner of the lock to write platform-specific information. 57 */ 58 bool vsoc::layout::WaitingLockBase::TryLock(uint32_t tid, 59 uint32_t* expected_out) { 60 uint32_t masked_tid = MakeOwnerTid(tid); 61 uint32_t expected = LockFree; 62 while (1) { 63 // First try to lock assuming that the mutex is free 64 if (lock_uint32_.compare_exchange_strong(expected, masked_tid)) { 65 // We got the lock. 66 return true; 67 } 68 // We didn't get the lock and our wait flag is already set. It's safe to 69 // try to sleep 70 if (expected & OurWaitingFlag) { 71 *expected_out = expected; 72 return false; 73 } 74 // Attempt to set the wait flag. This will fail if the lock owner changes. 75 while (1) { 76 uint32_t add_wait_flag = expected | OurWaitingFlag; 77 if (lock_uint32_.compare_exchange_strong(expected, add_wait_flag)) { 78 // We set the waiting flag. Try to sleep. 79 *expected_out = expected; 80 return false; 81 } 82 // The owner changed, but we at least we got the wait flag. 83 // Try sleeping 84 if (expected & OurWaitingFlag) { 85 *expected_out = expected; 86 return false; 87 } 88 // Special case: the lock was just freed. Stop trying to set the 89 // waiting flag and try to grab the lock. 90 if (expected == LockFree) { 91 break; 92 } 93 // The owner changed and we have no wait flag 94 // Try to set the wait flag again 95 } 96 // This only happens if the lock was freed while we attempt the set the 97 // wait flag. Try to grab the lock again 98 } 99 // Never reached. 100 } 101 102 layout::Sides vsoc::layout::WaitingLockBase::UnlockCommon(uint32_t tid) { 103 uint32_t expected_state = lock_uint32_; 104 105 // We didn't hold the lock. This process is insane and must die before it 106 // does damage. 107 uint32_t marked_tid = MakeOwnerTid(tid); 108 if ((marked_tid ^ expected_state) & OwnerMask) { 109 LOG(FATAL) << tid << " unlocking " << this << " owned by " 110 << expected_state; 111 } 112 // If contention is just starting this may fail twice (once for each bit) 113 // expected_state updates on each failure. When this finishes we have 114 // one bit for each waiter 115 while (1) { 116 if (lock_uint32_.compare_exchange_strong(expected_state, LockFree)) { 117 break; 118 } 119 } 120 if ((expected_state ^ marked_tid) & OwnerMask) { 121 LOG(FATAL) << "Lock owner of " << this << " changed from " << tid << " to " 122 << expected_state << " during unlock"; 123 } 124 switch (expected_state & (GuestWaitingFlag | HostWaitingFlag)) { 125 case 0: 126 return Sides::NoSides; 127 case GuestWaitingFlag: 128 return Sides::Guest; 129 case HostWaitingFlag: 130 return Sides::Host; 131 default: 132 return Sides::Both; 133 } 134 } 135 136 bool vsoc::layout::WaitingLockBase::RecoverSingleSided() { 137 // No need to signal because the caller ensured that there were no other 138 // threads... 139 return lock_uint32_.exchange(LockFree) != LockFree; 140 } 141 142 void layout::GuestAndHostLock::Lock(RegionView* region) { 143 uint32_t expected; 144 uint32_t tid = gettid(); 145 while (1) { 146 if (TryLock(tid, &expected)) { 147 return; 148 } 149 region->WaitForSignal(&lock_uint32_, expected); 150 } 151 } 152 153 void layout::GuestAndHostLock::Unlock(RegionView* region) { 154 region->SendSignal(UnlockCommon(gettid()), &lock_uint32_); 155 } 156 157 bool layout::GuestAndHostLock::Recover(RegionView* region) { 158 uint32_t expected_state = lock_uint32_; 159 uint32_t expected_owner_bit = (Sides::OurSide == Sides::Host) ? HostIsOwner : 0; 160 // This avoids check then act by reading exactly once and then 161 // eliminating the states where Recover should be a noop. 162 if (expected_state == LockFree) { 163 return false; 164 } 165 // Owned by the other side, do nothing. 166 if ((expected_state & HostIsOwner) != expected_owner_bit) { 167 return false; 168 } 169 // At this point we know two things: 170 // * The lock was held by our side 171 // * There are no other threads running on our side (precondition 172 // for calling Recover()) 173 // Therefore, we know that the current expected value should still 174 // be in the lock structure. Use the normal unlock logic, providing 175 // the tid that we observed in the lock. 176 region->SendSignal(UnlockCommon(expected_state), &lock_uint32_); 177 return true; 178 } 179 180 } // namespace vsoc 181