mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 12:13:20 -04:00
Running jobs which were entered into the isc_quota queue is the responsibility of the isc_quota_release() function, which, when releasing a previously acquired quota, checks whether the queue is empty, and if it's not, it runs a job from the queue without touching the 'quota->used' counter. This mechanism is susceptible to a possible hangup of a newly queued job in case when between the time a decision has been made to queue it (because used >= max) and the time it was actually queued, the last quota was released. Since there is no more quotas to be released (unless arriving in the future), the newly entered job will be stuck in the queue. Fix the wrong memory ordering for 'quota->used', as the relaxed ordering doesn't ensure that data modifications made by one thread are visible in other threads. Add checks in both isc_quota_release() and isc_quota_acquire_cb() to make sure that the described hangup does not happen. Also see code comments.
79 lines
3.1 KiB
C
79 lines
3.1 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdatomic.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
/*
|
|
* We define a few additional macros to make things easier
|
|
*/
|
|
|
|
/* Relaxed Memory Ordering */
|
|
|
|
#define atomic_store_relaxed(o, v) \
|
|
atomic_store_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_load_relaxed(o) atomic_load_explicit((o), memory_order_relaxed)
|
|
#define atomic_fetch_add_relaxed(o, v) \
|
|
atomic_fetch_add_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_fetch_sub_relaxed(o, v) \
|
|
atomic_fetch_sub_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_fetch_or_relaxed(o, v) \
|
|
atomic_fetch_or_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_fetch_and_relaxed(o, v) \
|
|
atomic_fetch_and_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_exchange_relaxed(o, v) \
|
|
atomic_exchange_explicit((o), (v), memory_order_relaxed)
|
|
#define atomic_compare_exchange_weak_relaxed(o, e, d) \
|
|
atomic_compare_exchange_weak_explicit( \
|
|
(o), (e), (d), memory_order_relaxed, memory_order_relaxed)
|
|
#define atomic_compare_exchange_strong_relaxed(o, e, d) \
|
|
atomic_compare_exchange_strong_explicit( \
|
|
(o), (e), (d), memory_order_relaxed, memory_order_relaxed)
|
|
|
|
/* Acquire-Release Memory Ordering */
|
|
|
|
#define atomic_store_release(o, v) \
|
|
atomic_store_explicit((o), (v), memory_order_release)
|
|
#define atomic_load_acquire(o) atomic_load_explicit((o), memory_order_acquire)
|
|
#define atomic_fetch_add_release(o, v) \
|
|
atomic_fetch_add_explicit((o), (v), memory_order_release)
|
|
#define atomic_fetch_sub_release(o, v) \
|
|
atomic_fetch_sub_explicit((o), (v), memory_order_release)
|
|
#define atomic_fetch_and_release(o, v) \
|
|
atomic_fetch_and_explicit((o), (v), memory_order_release)
|
|
#define atomic_fetch_or_release(o, v) \
|
|
atomic_fetch_or_explicit((o), (v), memory_order_release)
|
|
#define atomic_exchange_acquire(o, v) \
|
|
atomic_exchange_explicit((o), (v), memory_order_acquire)
|
|
#define atomic_exchange_acq_rel(o, v) \
|
|
atomic_exchange_explicit((o), (v), memory_order_acq_rel)
|
|
#define atomic_fetch_add_acq_rel(o, v) \
|
|
atomic_fetch_add_explicit((o), (v), memory_order_acq_rel)
|
|
#define atomic_fetch_sub_acq_rel(o, v) \
|
|
atomic_fetch_sub_explicit((o), (v), memory_order_acq_rel)
|
|
#define atomic_compare_exchange_weak_acq_rel(o, e, d) \
|
|
atomic_compare_exchange_weak_explicit( \
|
|
(o), (e), (d), memory_order_acq_rel, memory_order_acquire)
|
|
#define atomic_compare_exchange_strong_acq_rel(o, e, d) \
|
|
atomic_compare_exchange_strong_explicit( \
|
|
(o), (e), (d), memory_order_acq_rel, memory_order_acquire)
|
|
|
|
/* compare/exchange that MUST succeed */
|
|
#define atomic_compare_exchange_enforced(o, e, d) \
|
|
RUNTIME_CHECK(atomic_compare_exchange_strong((o), (e), (d)))
|
|
|
|
/* more comfortable atomic pointer declarations */
|
|
#define atomic_ptr(type) _Atomic(type *)
|