MCPcopy Create free account
hub / github.com/F-Stack/f-stack / __rw_downgrade_int

Function __rw_downgrade_int

freebsd/kern/kern_rwlock.c:1361–1423  ·  view source on GitHub ↗

* Downgrade a write lock into a single read lock. */

Source from the content-addressed store, hash-verified

1359 * Downgrade a write lock into a single read lock.
1360 */
1361void
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);

Callers

nothing calls this directly

Calls 8

__rw_assertFunction · 0.85
turnstile_chain_lockFunction · 0.85
turnstile_lookupFunction · 0.85
turnstile_broadcastFunction · 0.85
turnstile_unpendFunction · 0.85
turnstile_disownFunction · 0.85
turnstile_chain_unlockFunction · 0.85
panicFunction · 0.70

Tested by

no test coverage detected