* Downgrade a write lock into a single read lock. */
| 1359 | * Downgrade a write lock into a single read lock. |
| 1360 | */ |
| 1361 | void |
| 1362 | __rw_downgrade_int(struct rwlock *rw LOCK_FILE_LINE_ARG_DEF) |
| 1363 | { |
| 1364 | struct turnstile *ts; |
| 1365 | uintptr_t tid, v; |
| 1366 | int rwait, wwait; |
| 1367 | |
| 1368 | if (SCHEDULER_STOPPED()) |
| 1369 | return; |
| 1370 | |
| 1371 | KASSERT(rw->rw_lock != RW_DESTROYED, |
| 1372 | ("rw_downgrade() of destroyed rwlock @ %s:%d", file, line)); |
| 1373 | __rw_assert(&rw->rw_lock, RA_WLOCKED | RA_NOTRECURSED, file, line); |
| 1374 | #ifndef INVARIANTS |
| 1375 | if (rw_recursed(rw)) |
| 1376 | panic("downgrade of a recursed lock"); |
| 1377 | #endif |
| 1378 | |
| 1379 | WITNESS_DOWNGRADE(&rw->lock_object, 0, file, line); |
| 1380 | |
| 1381 | /* |
| 1382 | * Convert from a writer to a single reader. First we handle |
| 1383 | * the easy case with no waiters. If there are any waiters, we |
| 1384 | * lock the turnstile and "disown" the lock. |
| 1385 | */ |
| 1386 | tid = (uintptr_t)curthread; |
| 1387 | if (atomic_cmpset_rel_ptr(&rw->rw_lock, tid, RW_READERS_LOCK(1))) |
| 1388 | goto out; |
| 1389 | |
| 1390 | /* |
| 1391 | * Ok, we think we have waiters, so lock the turnstile so we can |
| 1392 | * read the waiter flags without any races. |
| 1393 | */ |
| 1394 | turnstile_chain_lock(&rw->lock_object); |
| 1395 | v = rw->rw_lock & RW_LOCK_WAITERS; |
| 1396 | rwait = v & RW_LOCK_READ_WAITERS; |
| 1397 | wwait = v & RW_LOCK_WRITE_WAITERS; |
| 1398 | MPASS(rwait | wwait); |
| 1399 | |
| 1400 | /* |
| 1401 | * Downgrade from a write lock while preserving waiters flag |
| 1402 | * and give up ownership of the turnstile. |
| 1403 | */ |
| 1404 | ts = turnstile_lookup(&rw->lock_object); |
| 1405 | MPASS(ts != NULL); |
| 1406 | if (!wwait) |
| 1407 | v &= ~RW_LOCK_READ_WAITERS; |
| 1408 | atomic_store_rel_ptr(&rw->rw_lock, RW_READERS_LOCK(1) | v); |
| 1409 | /* |
| 1410 | * Wake other readers if there are no writers pending. Otherwise they |
| 1411 | * won't be able to acquire the lock anyway. |
| 1412 | */ |
| 1413 | if (rwait && !wwait) { |
| 1414 | turnstile_broadcast(ts, TS_SHARED_QUEUE); |
| 1415 | turnstile_unpend(ts); |
| 1416 | } else |
| 1417 | turnstile_disown(ts); |
| 1418 | turnstile_chain_unlock(&rw->lock_object); |
nothing calls this directly
no test coverage detected