2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 04:58:04 +00:00

111 Commits

Author SHA1 Message Date
Ondřej Surý
dcd60215ac
Add tracing probes to the custom isc_rwlock implementation
Add tracing probes to ISC own isc_rwlock implementation to allow
fine-grained tracing.  The pthread rwlock already has probes inside
glibc, and it's difficult to add probes to headers included from the
other libraries.
2023-08-21 18:39:53 +02:00
Ondřej Surý
6ffda5920e
Add the reader-writer synchronization with modified C-RW-WP
This changes the internal isc_rwlock implementation to:

  Irina Calciu, Dave Dice, Yossi Lev, Victor Luchangco, Virendra
  J. Marathe, and Nir Shavit.  2013.  NUMA-aware reader-writer locks.
  SIGPLAN Not. 48, 8 (August 2013), 157–166.
  DOI:https://doi.org/10.1145/2517327.24425

(The full article available from:
  http://mcg.cs.tau.ac.il/papers/ppopp2013-rwlocks.pdf)

The implementation is based on the The Writer-Preference Lock (C-RW-WP)
variant (see the 3.4 section of the paper for the rationale).

The implemented algorithm has been modified for simplicity and for usage
patterns in rbtdb.c.

The changes compared to the original algorithm:

  * We haven't implemented the cohort locks because that would require a
    knowledge of NUMA nodes, instead a simple atomic_bool is used as
    synchronization point for writer lock.

  * The per-thread reader counters are not being used - this would
    require the internal thread id (isc_tid_v) to be always initialized,
    even in the utilities; the change has a slight performance penalty,
    so we might revisit this change in the future.  However, this change
    also saves a lot of memory, because cache-line aligned counters were
    used, so on 32-core machine, the rwlock would be 4096+ bytes big.

  * The readers use a writer_barrier that will raise after a while when
    readers lock can't be acquired to prevent readers starvation.

  * Separate ingress and egress readers counters queues to reduce both
    inter and intra-thread contention.
2023-02-15 09:30:04 +01:00
Tony Finch
436b76bb17 Improve the spinloop pause / yield hint
Unfortunately, C still lacks a standard function for pause (x86,
sparc) or yeild (arm) instructions, for use in spin lock or CAS loops.
BIND has its own based on vendor intrinsics or inline asm.

Previously, it was buried in the `isc_rwlock` implementation. This
commit renames `isc_rwlock_pause()` to `isc_pause()` and moves
it into <isc/pause.h>.

This commit also fixes the configure script so that it detects ARM
yield support on systems that identify as `aarch*` instead of `arm*`.

On 64-bit ARM systems we now use the ISB (instruction synchronization
barrier) instruction in preference to yield. The ISB instruction
pauses the CPU for longer, several nanoseconds, which is more like the
x86 pause instruction. There are more details in a Rust pull request,
which also refers to MySQL making the same change:
https://github.com/rust-lang/rust/pull/84725
2023-02-14 17:13:24 +00:00
Michal Nowak
afdb41a5aa
Update sources to Clang 15 formatting 2022-11-29 08:54:34 +01:00
Ondřej Surý
0492bbf590
Make the pthread_rwlock implementation header-only macros [2/2]
While using mutrace, the phtread-rwlock based isc_rwlock implementation
would be all tracked in the rwlock.c unit losing all useful information
as all rwlocks would be traced in a single place.  Rewrite the
pthread_rwlock based implementation to be header-only macros, so we can
use mutrace to properly track the rwlock contention without heavily
patching mutrace to understand the libisc synchronization primitives.
2022-11-02 10:34:10 +01:00
Ondřej Surý
6bd201ccec
Remove one level of indirection from isc_rwlock [1/2]
Instead of checking the PTHREAD_RUNTIME_CHECK from the header, move it
to the pthread_rwlock implementation functions.  The internal isc_rwlock
actually cannot fail, so the checks in the header was useless anyway.
2022-11-02 10:27:09 +01:00
Ondřej Surý
98b7a93772
Remove isc_rwlock_downgrade() from isc_rwlock
The isc_rwlock_downgrade() is not used anywhere, so we can remove it and
make the pthread_rwlock implementation simpler.
2022-11-02 09:05:37 +01:00
Tony Finch
ec50c58f52 De-duplicate __FILE__, __LINE__
Mostly generated automatically with the following semantic patch,
except where coccinelle was confused by #ifdef in lib/isc/net.c

@@ expression list args; @@
- UNEXPECTED_ERROR(__FILE__, __LINE__, args)
+ UNEXPECTED_ERROR(args)
@@ expression list args; @@
- FATAL_ERROR(__FILE__, __LINE__, args)
+ FATAL_ERROR(args)
2022-10-17 11:58:26 +01:00
Michał Kępień
7009f9d270 Improve reporting for read-write lock errors
Replace direct uses of implementation-specific rwlock functions in
lib/isc/include/isc/rwlock.h with preprocessor macros that use
ERRNO_CHECK(), in order to augment rwlock-related error messages with
file/line/caller information and the error string corresponding to
errno.  Adjust the implementation-specific functions for pthreads-based
rwlocks so that they return any errors encountered to the caller instead
of aborting execution immediately using RUNTIME_CHECK().

To keep code modifications simple, make the non-pthreads-based
implementation-specific rwlock functions always return 0; these
functions continue to handle errors using less verbose run-time
assertions as they do not set errno anyway.
2022-07-13 13:19:32 +02:00
Ondřej Surý
e4606da2c6 Enable tracking of pthreads rwlocks
Some POSIX threads implementations (e.g. FreeBSD's libthr) allocate
memory on the heap when pthread_rwlock_init() is called.  Every call to
that function must be accompanied by a corresponding call to
pthread_rwlock_destroy() or else the memory allocated for the rwlock
will leak.

jemalloc can be used for detecting memory allocations which are not
released by a process when it exits.  Unfortunately, since jemalloc is
also the system allocator on FreeBSD and a special (profiling-enabled)
build of jemalloc is required for memory leak detection, this method
cannot be used for detecting leaked memory allocated by libthr on a
stock FreeBSD installation.

However, libthr's behavior can be emulated on any platform by
implementing alternative versions of libisc functions for creating and
destroying rwlocks that allocate memory using malloc() and release it
using free().  This enables using jemalloc for detecting missing
pthread_rwlock_destroy() calls on any platform on which it works
reliably.

When the newly introduced ISC_TRACK_PTHREADS_OBJECTS preprocessor macro
is set (and --enable-pthread-rwlock is used), allocate isc_rwlock_t
structures on the heap in isc_rwlock_init() and free them in
isc_rwlock_destroy().  Reuse existing functions defined in
lib/isc/rwlock.c for other operations, but rename them first, so that
they contain triple underscores (to indicate that these functions are
implementation-specific, unlike their mutex and condition variable
counterparts, which always use the pthreads implementation).  Define the
isc__rwlock_init() macro so that it is a logical counterpart of
isc__mutex_init() and isc__condition_init(); adjust isc___rwlock_init()
accordingly.  Remove a redundant function prototype for
isc__rwlock_lock() and rename that (static) function to rwlock_lock() in
order to avoid having to use quadruple underscores.
2022-07-13 13:19:32 +02:00
Ondřej Surý
deae974366 Directly cause assertion failure on pthreads primitives failure
Instead of returning error values from isc_rwlock_*(), isc_mutex_*(),
and isc_condition_*() macros/functions and subsequently carrying out
runtime assertion checks on the return values in the calling code,
trigger assertion failures directly in those macros/functions whenever
any pthread function returns an error, as there is no point in
continuing execution in such a case anyway.
2022-07-13 13:19:32 +02:00
Michał Kępień
5759ace07f Handle pthread_*_init() failures consistently
isc_rwlock_init() currently detects pthread_rwlock_init() failures using
a REQUIRE() assertion.  Use the ERRNO_CHECK() macro for that purpose
instead, so that read-write lock initialization failures are handled
identically as condition variable (pthread_cond_init()) and mutex
(pthread_mutex_init()) initialization failures.
2022-07-13 13:19:32 +02:00
Ondřej Surý
4dceab142d Consistenly use UNREACHABLE() instead of ISC_UNREACHABLE()
In couple places, we have missed INSIST(0) or ISC_UNREACHABLE()
replacement on some branches with UNREACHABLE().  Replace all
ISC_UNREACHABLE() or INSIST(0) calls with UNREACHABLE().
2022-03-28 23:26:08 +02:00
Ondřej Surý
584f0d7a7e Simplify way we tag unreachable code with only ISC_UNREACHABLE()
Previously, the unreachable code paths would have to be tagged with:

    INSIST(0);
    ISC_UNREACHABLE();

There was also older parts of the code that used comment annotation:

    /* NOTREACHED */

Unify the handling of unreachable code paths to just use:

    UNREACHABLE();

The UNREACHABLE() macro now asserts when reached and also uses
__builtin_unreachable(); when such builtin is available in the compiler.
2022-03-25 08:33:43 +01:00
Ondřej Surý
58bd26b6cf Update the copyright information in all files in the repository
This commit converts the license handling to adhere to the REUSE
specification.  It specifically:

1. Adds used licnses to LICENSES/ directory

2. Add "isc" template for adding the copyright boilerplate

3. Changes all source files to include copyright and SPDX license
   header, this includes all the C sources, documentation, zone files,
   configuration files.  There are notes in the doc/dev/copyrights file
   on how to add correct headers to the new files.

4. Handle the rest that can't be modified via .reuse/dep5 file.  The
   binary (or otherwise unmodifiable) files could have license places
   next to them in <foo>.license file, but this would lead to cluttered
   repository and most of the files handled in the .reuse/dep5 file are
   system test files.
2022-01-11 09:05:02 +01:00
Mark Andrews
ce5207699d Fix unchecked return of isc_rwlock_lock and isc_rwlock_unlock
(cherry picked from commit bcaf23dd2799e30cfee1b5d39dec0fbc8e5f7193)
2021-07-12 13:26:29 +10:00
Ondřej Surý
29c2e52484 The isc/platform.h header has been completely removed
The isc/platform.h header was left empty which things either already
moved to config.h or to appropriate headers.  This is just the final
cleanup commit.
2021-07-06 05:33:48 +00:00
Ondřej Surý
a0181056a8 Change the isc_thread_self() return type to uintptr_t
The pthread_self(), thrd_current() or GetCurrentThreadId() could
actually be a pointer, so we should rather convert the value into
uintptr_t instead of unsigned long.
2021-02-25 16:21:10 +01:00
Mark Andrews
3b11bacbb7 Cleanup redundant isc_rwlock_init() result checks 2021-02-03 12:22:33 +11:00
Evan Hunt
dcee985b7f update all copyright headers to eliminate the typo 2020-09-14 16:20:40 -07:00
Ondřej Surý
4cf275ba8a Replace non-loop usage of atomic_compare_exchange_weak with strong variant
While testing BIND 9 on arm64 8+ core machine, it was discovered that
the weak variants in fact does spuriously fail, we haven't observed that
on other architectures.

This commit replaces all non-loop usage of atomic_compare_exchange_weak
with atomic_compare_exchange_strong.
2020-02-16 18:09:19 +01:00
Ondřej Surý
5777c44ad0 Reformat using the new rules 2020-02-14 09:31:05 +01:00
Evan Hunt
e851ed0bb5 apply the modified style 2020-02-13 15:05:06 -08:00
Ondřej Surý
056e133c4c Use clang-tidy to add curly braces around one-line statements
The command used to reformat the files in this commit was:

./util/run-clang-tidy \
	-clang-tidy-binary clang-tidy-11
	-clang-apply-replacements-binary clang-apply-replacements-11 \
	-checks=-*,readability-braces-around-statements \
	-j 9 \
	-fix \
	-format \
	-style=file \
	-quiet
clang-format -i --style=format $(git ls-files '*.c' '*.h')
uncrustify -c .uncrustify.cfg --replace --no-backup $(git ls-files '*.c' '*.h')
clang-format -i --style=format $(git ls-files '*.c' '*.h')
2020-02-13 22:07:21 +01:00
Ondřej Surý
f50b1e0685 Use clang-format to reformat the source files 2020-02-12 15:04:17 +01:00
Ondřej Surý
b43f5e0238 Convert all atomic operations in isc_rwlock to release-acquire memory ordering
The memory ordering in the rwlock was all wrong, I am copying excerpts
from the https://en.cppreference.com/w/c/atomic/memory_order#Relaxed_ordering
for the convenience of the reader:

  Relaxed ordering

  Atomic operations tagged memory_order_relaxed are not synchronization
  operations; they do not impose an order among concurrent memory
  accesses. They only guarantee atomicity and modification order
  consistency.

  Release-Acquire ordering

  If an atomic store in thread A is tagged memory_order_release and an
  atomic load in thread B from the same variable is tagged
  memory_order_acquire, all memory writes (non-atomic and relaxed atomic)
  that happened-before the atomic store from the point of view of thread
  A, become visible side-effects in thread B. That is, once the atomic
  load is completed, thread B is guaranteed to see everything thread A
  wrote to memory.

  The synchronization is established only between the threads releasing
  and acquiring the same atomic variable. Other threads can see different
  order of memory accesses than either or both of the synchronized
  threads.

Which basically means that we had no or weak synchronization between
threads using the same variables in the rwlock structure.  There should
not be a significant performance drop because the critical sections were
already protected by:

  while(1) {
    if (relaxed_atomic_operation) {
      break;
    }
    LOCK(lock);
    if (!relaxed_atomic_operation) {
      WAIT(sem, lock);
    }
    UNLOCK(lock)l
  }

I would add one more thing to "Don't do your own crypto, folks.":

  - Also don't do your own locking, folks.
2020-02-11 11:10:55 +01:00
Sergei Trofimovich
a5ad6b16c5 configure.ac: autodetect 'pause' instruction presence on sparc
The change fixes the following build failure on sparc T3 and older CPUs:

```
sparc-unknown-linux-gnu-gcc ... -O2 -mcpu=niagara2 ... -c rwlock.c
{standard input}: Assembler messages:
{standard input}:398: Error: Architecture mismatch on "pause ".
{standard input}:398: (Requires v9e|v9v|v9m|m8; requested architecture is v9b.)
make[1]: *** [Makefile:280: rwlock.o] Error 1
```

`pause` insutruction exists only on `-mcpu=niagara4` (`T4`) and upper.

The change adds `pause` configure-time autodetection and uses it if available.
config.h.in got new `HAVE_SPARC_PAUSE` knob. Fallback is a fall-through no-op.

Build-tested on:

- sparc-unknown-linux-gnu-gcc (no `pause`, build succeeds)
- sparc-unknown-linux-gnu-gcc -mcpu=niagara4 (`pause`, build succeeds)

Reported-by: Rolf Eike Beer
Bug: https://bugs.gentoo.org/691708
Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
2019-08-08 07:15:04 -04:00
Ondřej Surý
49462cf974 Make isc_rwlock.c thread-safe
The ThreadSanitizer found several possible data races in our rwlock
implementation.  This commit changes all the unprotected variables to atomic and
also changes the explicit memory ordering (atomic_<foo>_explicit(..., <order>)
functions to use our convenience macros (atomic_<foo>_<order>).
2019-07-03 00:05:34 -04:00
Ondřej Surý
1e2f40d01b Fixup the atomic code in pthread_rwlock branch of lib/isc/rwlock.c 2019-06-05 11:17:19 -07:00
Witold Kręcicki
02bbf1e2b9 Add --enable-pthread-rwlock option 2019-05-30 16:10:16 +02:00
Ondřej Surý
4501f646ee Implement isc_rwlock_downgrade using pthreads and single atomic_bool 2019-05-30 16:10:16 +02:00
Ondřej Surý
64fbffbbaa Use simple pthread_rwlock in place of our custom adaptive rwlock 2019-05-30 16:10:16 +02:00
Mark Andrews
f546769b8b arm: just use the compiler's default yield support 2019-05-12 21:39:43 -04:00
Ondřej Surý
78d0cb0a7d Use coccinelle to remove explicit '#include <config.h>' from the source files 2019-03-08 15:15:05 +01:00
Mark Andrews
2be55f5c05 use smt_pause instead of pause on sparc 2019-01-15 20:29:27 -05:00
Ondřej Surý
e2cdf066ea Remove message catalogs 2019-01-09 23:44:26 +01:00
Michał Kępień
62ca7743ae Fix compilation on CentOS 6 (i386)
The stock toolchain available on CentOS 6 for i386 is unable to use the
_mm_pause() intrinsic.  Fix by using "rep; nop" assembly instructions on
that platform instead.
2018-11-26 10:57:14 +01:00
Witold Kręcicki
929ea7c2c4 - Make isc_mutex_destroy return void
- Make isc_mutexblock_init/destroy return void
- Minor cleanups
2018-11-22 11:52:08 +00:00
Ondřej Surý
2f3eee5a4f isc_mutex_init returns 'void' 2018-11-22 11:51:49 +00:00
Ondřej Surý
73a8999d1c isc_condition_init returns 'void' 2018-11-22 11:51:49 +00:00
Ondřej Surý
4b47958163 Fix typo in isc_rwlock_pause() on sparc 2018-10-23 09:29:03 +02:00
Ondřej Surý
22e5231f99 Remove ISC_PLATFORM_BUSYWAITNOP in favour of direct isc_rwlock_pause() define 2018-09-07 12:17:29 +02:00
Ondřej Surý
9d5df99a9d Directly use return value of atomic_compare_exchange_strong_explicit insteaf of comparing expected value 2018-08-28 12:15:39 +02:00
Ondřej Surý
b5709e5531 Explicitly load atomic values in lib/isc/rwlock.c 2018-08-28 12:15:39 +02:00
Ondřej Surý
e9e55cbd03 Remove isc_atomic usage from rwlock.c and stats.c 2018-08-28 12:15:39 +02:00
Witold Kręcicki
5cdb38c2c7 Remove unthreaded support 2018-08-16 17:18:52 +02:00
Ondřej Surý
994e656977 Replace custom isc_boolean_t with C standard bool type 2018-08-08 09:37:30 +02:00
Ondřej Surý
cb6a185c69 Replace custom isc_u?intNN_t types with C99 u?intNN_t types 2018-08-08 09:37:28 +02:00
Ondřej Surý
55a10b7acd Remove $Id markers, Principal Author and Reviewed tags from the full source tree 2018-05-11 13:17:46 +02:00
Ondřej Surý
843d389661 Update license headers to not include years in copyright in all applicable files 2018-02-23 10:12:02 +01:00