On Tue, May 31, 2022, 7:52 AM Zebediah Figura wrote:
On 5/30/22 14:20, Jinoh Kang wrote:
> +
> + /* GetOverlappedResultEx() skips waiting for the event/file handle if the
> + * Status field indicates completion, and returns the result from the
> + * Information field.
> + *
> + * Hence, we have to ensure that writes to the Information field are seen
> + * from the other threads *before* writes to the Status field.
> + *
> + * Otherwise, a race condition results: if writing the Status field has
> + * been completed but the subsequent update to the Information field has
> + * not, the application may end up reading stale value from it.
> + *
> + * The race condition can be especially problematic with applications that
> + * use the HasOverlappedIoCompleted() macro in a tight loop to busy-wait
> + * for completion of overlapped I/O.
> + */
> + MemoryBarrier(); /* TODO: consider replacing with a store-release. */
> + *(volatile NTSTATUS *)status_ptr = status;
> }
>
> static inline client_ptr_t iosb_client_ptr( IO_STATUS_BLOCK *io )
Unpaired MemoryBarrier() is pretty much always wrong. (In fact, I think
unpaired anything would be, here.)
By pairing, do you mean that another MemoryBarrier() should follow the status write?
It also doesn't seem clear to me that it's actually better than a
store-release, as you point out. Ideally what we want is ReadAcquire()
and WriteRelease(), but even setting that aside, a pair of interlocked
operations will probably be an improvement by themselves.
As in, convert both status and information writes to interlocked operations, or replace the barrier with a dummy atomic op?