Il mer 14 mag 2025, 08:57 Akihiko Odaki <akihiko.od...@daynix.com> ha scritto:
> Honestly, I do not understand why smp_mb() is placed here even in the > futex case. The comment says: > > qemu_event_set has release semantics, but because it *loads* > > ev->value we need a full memory barrier here. > > The barrier is indeed followed by a load: qatomic_read(&ev->value) != > EV_SET > However, the caller of qemu_event_set() should not care whether the > event is already set or not so I'm not sure if smp_mb() is needed in > the first place. The barrier is needed to ensure correct ordering in all cases. You have on one side done=true Set Read ev->value If not EV_SET, set the event+ wake up waiters > And on the other Write EV_FREE Write If not done Wait If one that calls qemu_event_set and the other calls qemu_event_reset, you need to avoid that set reads a previous EV_SET for the value *and* the other side reads done equal to false. The only way to avoid this is for both sides to use a memory barrier before the read. qemu_event_set(): release *if the event is not already set*; otherwise > it has no effect on synchronization so we don't need a barrier either. It needs to be release always. This ensures that, whenever the setter declares the event to be set, the other side sees whatever the setter did before the call. It's the full memory barrier that is only needed, in principle, when the event is not already set. But in practice you cannot know which barrier is needed until you read the value, so you do need smp_mb(). qemu_event_reset(): acquire; this enables checking the state for the > event set before resetting. > > qemu_event_wait(): acquire > These are correct. However, these are the semantics seen by the caller, but (because of the algorithm used with futexes) there is a store-load ordering and full barriers are necessary. Without futexes indeed it's enough to have store-release and load-acquire in set/reset, and the mutex and condvar take care of synchronizing set with wait. Paolo Regards, > Akihiko Odaki > >