* Attempt to do a non-blocking upgrade from a read lock to a write * lock. This will only succeed if this thread holds a single read * lock. Returns true if the upgrade succeeded and false otherwise. */
| 1276 | * lock. Returns true if the upgrade succeeded and false otherwise. |
| 1277 | */ |
| 1278 | int |
| 1279 | __rw_try_upgrade_int(struct rwlock *rw LOCK_FILE_LINE_ARG_DEF) |
| 1280 | { |
| 1281 | uintptr_t v, setv, tid; |
| 1282 | struct turnstile *ts; |
| 1283 | int success; |
| 1284 | |
| 1285 | if (SCHEDULER_STOPPED()) |
| 1286 | return (1); |
| 1287 | |
| 1288 | KASSERT(rw->rw_lock != RW_DESTROYED, |
| 1289 | ("rw_try_upgrade() of destroyed rwlock @ %s:%d", file, line)); |
| 1290 | __rw_assert(&rw->rw_lock, RA_RLOCKED, file, line); |
| 1291 | |
| 1292 | /* |
| 1293 | * Attempt to switch from one reader to a writer. If there |
| 1294 | * are any write waiters, then we will have to lock the |
| 1295 | * turnstile first to prevent races with another writer |
| 1296 | * calling turnstile_wait() before we have claimed this |
| 1297 | * turnstile. So, do the simple case of no waiters first. |
| 1298 | */ |
| 1299 | tid = (uintptr_t)curthread; |
| 1300 | success = 0; |
| 1301 | v = RW_READ_VALUE(rw); |
| 1302 | for (;;) { |
| 1303 | if (RW_READERS(v) > 1) |
| 1304 | break; |
| 1305 | if (!(v & RW_LOCK_WAITERS)) { |
| 1306 | success = atomic_fcmpset_acq_ptr(&rw->rw_lock, &v, tid); |
| 1307 | if (!success) |
| 1308 | continue; |
| 1309 | break; |
| 1310 | } |
| 1311 | |
| 1312 | /* |
| 1313 | * Ok, we think we have waiters, so lock the turnstile. |
| 1314 | */ |
| 1315 | ts = turnstile_trywait(&rw->lock_object); |
| 1316 | v = RW_READ_VALUE(rw); |
| 1317 | retry_ts: |
| 1318 | if (RW_READERS(v) > 1) { |
| 1319 | turnstile_cancel(ts); |
| 1320 | break; |
| 1321 | } |
| 1322 | /* |
| 1323 | * Try to switch from one reader to a writer again. This time |
| 1324 | * we honor the current state of the waiters flags. |
| 1325 | * If we obtain the lock with the flags set, then claim |
| 1326 | * ownership of the turnstile. |
| 1327 | */ |
| 1328 | setv = tid | (v & RW_LOCK_WAITERS); |
| 1329 | success = atomic_fcmpset_ptr(&rw->rw_lock, &v, setv); |
| 1330 | if (success) { |
| 1331 | if (v & RW_LOCK_WAITERS) |
| 1332 | turnstile_claim(ts); |
| 1333 | else |
| 1334 | turnstile_cancel(ts); |
| 1335 | break; |
nothing calls this directly
no test coverage detected