Index: compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h +++ compiler-rt/trunk/lib/xray/xray_fdr_log_writer.h @@ -63,6 +63,10 @@ template void writeRecord(const T &R) { internal_memcpy(NextRecord, reinterpret_cast(&R), sizeof(T)); NextRecord += sizeof(T); + // We need this atomic fence here to ensure that other threads attempting to + // read the bytes in the buffer will see the writes committed before the + // extents are updated. + atomic_thread_fence(memory_order_release); atomic_fetch_add(&Buffer.Extents, sizeof(T), memory_order_acq_rel); } @@ -89,6 +93,10 @@ constexpr auto Size = sizeof(MetadataRecord) * N; internal_memcpy(NextRecord, reinterpret_cast(Recs), Size); NextRecord += Size; + // We need this atomic fence here to ensure that other threads attempting to + // read the bytes in the buffer will see the writes committed before the + // extents are updated. + atomic_thread_fence(memory_order_release); atomic_fetch_add(&Buffer.Extents, Size, memory_order_acq_rel); return Size; } @@ -129,6 +137,10 @@ NextRecord = reinterpret_cast(internal_memcpy( NextRecord, reinterpret_cast(&A), sizeof(A))) + sizeof(A); + // We need this atomic fence here to ensure that other threads attempting to + // read the bytes in the buffer will see the writes committed before the + // extents are updated. + atomic_thread_fence(memory_order_release); atomic_fetch_add(&Buffer.Extents, sizeof(R) + sizeof(A), memory_order_acq_rel); return true; @@ -149,6 +161,11 @@ NextRecord = reinterpret_cast( internal_memcpy(NextRecord, Event, EventSize)) + EventSize; + + // We need this atomic fence here to ensure that other threads attempting to + // read the bytes in the buffer will see the writes committed before the + // extents are updated. + atomic_thread_fence(memory_order_release); atomic_fetch_add(&Buffer.Extents, sizeof(R) + EventSize, memory_order_acq_rel); return true; @@ -167,6 +184,11 @@ NextRecord = reinterpret_cast( internal_memcpy(NextRecord, Event, EventSize)) + EventSize; + + // We need this atomic fence here to ensure that other threads attempting to + // read the bytes in the buffer will see the writes committed before the + // extents are updated. + atomic_thread_fence(memory_order_release); atomic_fetch_add(&Buffer.Extents, EventSize, memory_order_acq_rel); return true; } Index: compiler-rt/trunk/lib/xray/xray_fdr_logging.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_fdr_logging.cc +++ compiler-rt/trunk/lib/xray/xray_fdr_logging.cc @@ -243,6 +243,13 @@ // out to disk. The difference here would be that we still write "empty" // buffers, or at least go through the iterators faithfully to let the // handlers see the empty buffers in the queue. + // + // We need this atomic fence here to ensure that writes happening to the + // buffer have been committed before we load the extents atomically. Because + // the buffer is not explicitly synchronised across threads, we rely on the + // fence ordering to ensure that writes we expect to have been completed + // before the fence are fully committed before we read the extents. + atomic_thread_fence(memory_order_acquire); auto BufferSize = atomic_load(&It->Extents, memory_order_acquire); SerializedBufferSize = BufferSize + sizeof(MetadataRecord); CurrentBuffer = allocateBuffer(SerializedBufferSize);