diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-05-09 17:21:39 +0100 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-05-09 17:21:39 +0100 |
commit | 577e648bdb524d1984659baf1bd6165de2edae83 (patch) | |
tree | 7c5e59e610be8da6f3ffca922824687caebd0592 /util | |
parent | 271477b59e723250f17a7e20f139262057921b6a (diff) | |
parent | ef709860ea12ec59c4cd7373bd2fd7a4e50143ee (diff) | |
download | qemu-577e648bdb524d1984659baf1bd6165de2edae83.zip qemu-577e648bdb524d1984659baf1bd6165de2edae83.tar.gz qemu-577e648bdb524d1984659baf1bd6165de2edae83.tar.bz2 |
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* target/i386: improved EPYC models
* more removal of mb_read/mb_set
* bump _WIN32_WINNT to the Windows 8 API
* fix for modular builds with --disable-system
# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmRZK7wUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroObngf8D6A5l1QQAnImRrZAny6HZV/9xseD
# 9QhkUW3fxXlUhb8tXomv2BlT8h9GzLIN6aWvcCotT+xK3kAX7mRcYKgPMr9CYL7y
# vev/hh+B6RY1CJ/xPT09/BMVjkj50AL0O/OuWMhcQ5nCO7F2sdMjMrsYqqeZcjYf
# zx9RTX7gVGt+wWFHxgCgdfL0kfgzexK55YuZU0vLzcA+pYsZWoEfW+fKBIf4rzDV
# r9M6mDBUkHBQ0rIVC3QFloAXnYb1JrpeqqL2i2qwhAkLz8LyGqk3lZF20hE/04im
# XZcZjWO5pxAxIEPeTken+2x1n8tn2BLkMtvwJdV5TpvICCFRtPZlbH79qw==
# =rXLN
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 08 May 2023 06:05:00 PM BST
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [undefined]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* tag 'for-upstream' of https://gitlab.com/bonzini/qemu:
meson: leave unnecessary modules out of the build
docs: clarify --without-default-devices
target/i386: Add EPYC-Genoa model to support Zen 4 processor series
target/i386: Add VNMI and automatic IBRS feature bits
target/i386: Add missing feature bits in EPYC-Milan model
target/i386: Add feature bits for CPUID_Fn80000021_EAX
target/i386: Add a couple of feature bits in 8000_0008_EBX
target/i386: Add new EPYC CPU versions with updated cache_info
target/i386: allow versioned CPUs to specify new cache_info
include/qemu/osdep.h: Bump _WIN32_WINNT to the Windows 8 API
MAINTAINERS: add stanza for Kconfig files
tb-maint: do not use mb_read/mb_set
call_rcu: stop using mb_set/mb_read
test-aio-multithread: simplify test_multi_co_schedule
test-aio-multithread: do not use mb_read/mb_set for simple flags
rcu: remove qatomic_mb_set, expand comments
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/rcu.c | 69 |
1 files changed, 43 insertions, 26 deletions
@@ -83,12 +83,6 @@ static void wait_for_readers(void) */ qemu_event_reset(&rcu_gp_event); - /* Instead of using qatomic_mb_set for index->waiting, and - * qatomic_mb_read for index->ctr, memory barriers are placed - * manually since writes to different threads are independent. - * qemu_event_reset has acquire semantics, so no memory barrier - * is needed here. - */ QLIST_FOREACH(index, ®istry, node) { qatomic_set(&index->waiting, true); } @@ -96,6 +90,10 @@ static void wait_for_readers(void) /* Here, order the stores to index->waiting before the loads of * index->ctr. Pairs with smp_mb_placeholder() in rcu_read_unlock(), * ensuring that the loads of index->ctr are sequentially consistent. + * + * If this is the last iteration, this barrier also prevents + * frees from seeping upwards, and orders the two wait phases + * on architectures with 32-bit longs; see synchronize_rcu(). */ smp_mb_global(); @@ -104,7 +102,7 @@ static void wait_for_readers(void) QLIST_REMOVE(index, node); QLIST_INSERT_HEAD(&qsreaders, index, node); - /* No need for mb_set here, worst of all we + /* No need for memory barriers here, worst of all we * get some extra futex wakeups. */ qatomic_set(&index->waiting, false); @@ -149,26 +147,26 @@ void synchronize_rcu(void) /* Write RCU-protected pointers before reading p_rcu_reader->ctr. * Pairs with smp_mb_placeholder() in rcu_read_lock(). + * + * Also orders write to RCU-protected pointers before + * write to rcu_gp_ctr. */ smp_mb_global(); QEMU_LOCK_GUARD(&rcu_registry_lock); if (!QLIST_EMPTY(®istry)) { - /* In either case, the qatomic_mb_set below blocks stores that free - * old RCU-protected pointers. - */ if (sizeof(rcu_gp_ctr) < 8) { /* For architectures with 32-bit longs, a two-subphases algorithm * ensures we do not encounter overflow bugs. * * Switch parity: 0 -> 1, 1 -> 0. */ - qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + qatomic_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); wait_for_readers(); - qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + qatomic_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); } else { /* Increment current grace period. */ - qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR); + qatomic_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR); } wait_for_readers(); @@ -191,8 +189,22 @@ static void enqueue(struct rcu_head *node) struct rcu_head **old_tail; node->next = NULL; + + /* + * Make this node the tail of the list. The node will be + * used by further enqueue operations, but it will not + * be dequeued yet... + */ old_tail = qatomic_xchg(&tail, &node->next); - qatomic_mb_set(old_tail, node); + + /* + * ... until it is pointed to from another item in the list. + * In the meantime, try_dequeue() will find a NULL next pointer + * and loop. + * + * Synchronizes with qatomic_load_acquire() in try_dequeue(). + */ + qatomic_store_release(old_tail, node); } static struct rcu_head *try_dequeue(void) @@ -200,26 +212,31 @@ static struct rcu_head *try_dequeue(void) struct rcu_head *node, *next; retry: - /* Test for an empty list, which we do not expect. Note that for + /* Head is only written by this thread, so no need for barriers. */ + node = head; + + /* + * If the head node has NULL in its next pointer, the value is + * wrong and we need to wait until its enqueuer finishes the update. + */ + next = qatomic_load_acquire(&node->next); + if (!next) { + return NULL; + } + + /* + * Test for an empty list, which we do not expect. Note that for * the consumer head and tail are always consistent. The head * is consistent because only the consumer reads/writes it. * The tail, because it is the first step in the enqueuing. * It is only the next pointers that might be inconsistent. */ - if (head == &dummy && qatomic_mb_read(&tail) == &dummy.next) { + if (head == &dummy && qatomic_read(&tail) == &dummy.next) { abort(); } - /* If the head node has NULL in its next pointer, the value is - * wrong and we need to wait until its enqueuer finishes the update. - */ - node = head; - next = qatomic_mb_read(&head->next); - if (!next) { - return NULL; - } - - /* Since we are the sole consumer, and we excluded the empty case + /* + * Since we are the sole consumer, and we excluded the empty case * above, the queue will always have at least two nodes: the * dummy node, and the one being removed. So we do not need to update * the tail pointer. |