A version of java.util.concurrent.locks.ReadWriteLock that can be acquired and released on separate threads. label is the human-readable name used in waiting/blocking messages; uniqueness across locks is the registry's responsibility (e.g. LauncherLockRegistry's map key), not the lock's.
Block on the lock's monitor for up to timeoutMs, returning when any lock state change occurs (close/downgrade notifyAlls) or the timeout fires. Used by LockUpgrade.readThenWrite's retry loop to sleep efficiently between try-Write attempts: the lock already notifies on every state change, so the retry wakes exactly when a re-probe might newly succeed. The timeout bounds the worst-case sleep and protects against missed notifications.
Block on the lock's monitor for up to timeoutMs, returning when any lock state change occurs (close/downgrade notifyAlls) or the timeout fires. Used by LockUpgrade.readThenWrite's retry loop to sleep efficiently between try-Write attempts: the lock already notifies on every state change, so the retry wakes exactly when a re-probe might newly succeed. The timeout bounds the worst-case sleep and protects against missed notifications.
Non-blocking, non-queued Write attempt. Returns Right with a Lease if Write is immediately available (no active writer, no readers); Left with a human-readable description of the current blocker otherwise.
Non-blocking, non-queued Write attempt. Returns Right with a Lease if Write is immediately available (no active writer, no readers); Left with a human-readable description of the current blocker otherwise.
Crucially: a failed try does NOT increment waitingWriters, so the caller's subsequent Read attempts won't trip writer-priority (canAcquireRead = !writerActive && waitingWriters == 0). This is what makes the retryable read-then-write pattern in LockUpgrade.readThenWrite work: a launcher can fail to grab Write, fall back to Read, and re-probe shared state without poisoning its own next Read attempt.