/* POSIX reader--writer lock: core parts.
Copyright (C) 2016-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <sysdep.h>
#include <pthread.h>
#include <pthreadP.h>
#include <sys/time.h>
#include <stap-probe.h>
#include <atomic.h>
#include <futex-internal.h>
#include <time.h>
/* A reader--writer lock that fulfills the POSIX requirements (but operations
on this lock are not necessarily full barriers, as one may interpret the
POSIX requirement about "synchronizing memory"). All critical sections are
in a total order, writers synchronize with prior writers and readers, and
readers synchronize with prior writers.
A thread is allowed to acquire a read lock recursively (i.e., have rdlock
critical sections that overlap in sequenced-before) unless the kind of the
rwlock is set to PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP.
This lock is built so that workloads of mostly readers can be executed with
low runtime overheads. This matches that the default kind of the lock is
PTHREAD_RWLOCK_PREFER_READER_NP. Acquiring a read lock requires a single
atomic addition if the lock is or was previously acquired by other
readers; releasing the lock is a single CAS if there are no concurrent
writers.
Workloads consisting of mostly writers are of secondary importance.
An uncontended write lock acquisition is as fast as for a normal
exclusive mutex but writer contention is somewhat more costly due to
keeping track of the exact number of writers. If the rwlock kind requests
writers to be preferred (i.e., PTHREAD_RWLOCK_PREFER_WRITER_NP or the
no-recursive-readers variant of it), then writer--to--writer lock ownership
hand-over is fairly fast and bypasses lock acquisition attempts by readers.
The costs of lock ownership transfer between readers and writers vary. If
the program asserts that there are no recursive readers and writers are
preferred, then write lock acquisition attempts will block subsequent read
lock acquisition attempts, so that new incoming readers do not prolong a
phase in which readers have acquired the lock.
The main components of the rwlock are a writer-only lock that allows only
one of the concurrent writers to be the primary writer, and a
single-writer-multiple-readers lock that decides between read phases, in
which readers have acquired the rwlock, and write phases in which a primary
writer or a sequence of different primary writers have acquired the rwlock.
The single-writer-multiple-readers lock is the central piece of state
describing the rwlock and is encoded in the __readers field (see below for
a detailed explanation):
State WP WL R RW Notes
---------------------------
#1 0 0 0 0 Lock is idle (and in a read phase).
#2 0 0 >0 0