On 2025/05/17 19:24, Paolo Bonzini wrote:
Il sab 17 mag 2025, 01:41 Akihiko Odaki <akihiko.od...@daynix.com
<mailto:akihiko.od...@daynix.com>> ha scritto:
I think we only need a store-release, which is ensured even by the C11
read-modify-write operation; we only need to ensure that ev->value is
set to EV_SET after all stores specified earlier appear.
You really need a barrier to order the store against the load
unfortunately. Likewise in qemu_event_wait(). It's really central to
this synchronization pattern, otherwise it's possible that neither side
sees the action of the other (set does not see the request to wake, or
wait does not see EV_SET).
The code I suggested does not order stores before qemu_event_set() and
the load in the function unlike qemu_event_wait(), which orders stores
before the loads in the function. I'll show how the code still satisfies
its goal below.
Below is the list of all relevant memory accesses in the thread calling
qemu_event_set() and the one calling qemu_event_wait():
Thread A:
A1. Specify stores
A2. Call qemu_event_set()
A2-1. Call qatomic_xchg()
A2-1-1. Load ev->value
A2-1-2. Store ev->value
A2-2. Call qemu_futex_wake_all()
A2-2-1. Wake up
Thread B:
B1. Call qemu_event_wait()
B1-1. Call qatomic_load_acquire()
B1-1-1. Load ev->value
B1-2. Call qatomic_cmpxchg()
B1-2-1. Load ev->value
B1-2-2. Store ev->value
B1-3. Call qemu_futex_wait()
B1-3-1. Load ev->value
B1-3-2. Wait
B2. Specify loads
The goal is to satisfy the following two cross-thread ordering:
a) B1-3-2 -> A2-2-1 (start waiting -> wake up)
b) A1 -> B2 (stores before setting -> loads after waiting)
First, I'll show that a) is satisfied. There are three facts to consider:
- There are only two stores for ev->value: A2-1-2 and B1-2-2.
- A2-1-2 stores EV_SET.
- B1-2-2 stores EV_BUSY.
- qemu_futex_wait() atomically performs B1-3-1 and B1-3-2.
- B1-3-1 will not appear if EV_SET was loaded earlier.
- B1-3-2 (wait) appears when B1-3-1 loads EV_BUSY.
These facts ensures one of the following orders when B1-3-2 appears:
B1-2-2 (store EV_BUSY)
-> B1-3-1 (loads EV_BUSY)
-> B1-3-2 (start waiting)
-> A2-1-2 (store EV_SET)
-> A2-2-1 (wake up)
Next, I'll show that b) is satisfied.
- A1 (loads before qemu_event_set()) appears before A2-1-2.
- Only A2-1-2 stores EV_SET.
- B2 (stores after waiting) appears after B1-1-1 or B1-2-1 loads EV_SET.
Therefore, the following order are ensured when B2 appears:
A1 (specify loads before qemu_event_set())
-> A2-1-2 (store EV_SET)
-> B1-1-1 or B1-2-1 (load EV_SET)
-> B2 (specify stores after qemu_event_wait())
Regards,
Akihiko Odaki