blob: 7b6aca4d6c3c3ba90085e59ac62a587e7be72f67 [file] [log] [blame]
Eugene Zemtsovd29b01732024-12-19 21:20:121// Copyright 2024 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/atomicops.h"
6
7#include <atomic>
8
9#include "base/memory/aligned_memory.h"
10
11namespace base::subtle {
12
13void RelaxedAtomicWriteMemcpy(base::span<uint8_t> dst,
14 base::span<const uint8_t> src) {
15 CHECK_EQ(dst.size(), src.size());
16 size_t bytes = dst.size();
17 uint8_t* dst_byte_ptr = dst.data();
18 const uint8_t* src_byte_ptr = src.data();
19 // Make sure that we can at least copy byte by byte with atomics.
20 static_assert(std::atomic_ref<uint8_t>::required_alignment == 1);
21
22 // Alignment for uintmax_t atomics that we use in the happy case.
23 constexpr size_t kDesiredAlignment =
24 std::atomic_ref<uintmax_t>::required_alignment;
25
26 // Copy byte-by-byte until `dst_byte_ptr` is not properly aligned for
27 // the happy case.
28 while (bytes > 0 && !IsAligned(dst_byte_ptr, kDesiredAlignment)) {
29 std::atomic_ref<uint8_t>(*dst_byte_ptr)
30 .store(*src_byte_ptr, std::memory_order_relaxed);
31 // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
32 // to spans of sufficient size.
33 UNSAFE_BUFFERS(++dst_byte_ptr);
34 UNSAFE_BUFFERS(++src_byte_ptr);
35 --bytes;
36 }
37
38 // Happy case where both `src_byte_ptr` and `dst_byte_ptr` are both properly
39 // aligned and the largest possible atomic is used for copying.
40 if (IsAligned(src_byte_ptr, kDesiredAlignment)) {
41 while (bytes >= sizeof(uintmax_t)) {
42 std::atomic_ref<uintmax_t>(*reinterpret_cast<uintmax_t*>(dst_byte_ptr))
43 .store(*reinterpret_cast<const uintmax_t*>(src_byte_ptr),
44 std::memory_order_relaxed);
45 // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
46 // to spans of sufficient size.
47 UNSAFE_BUFFERS(dst_byte_ptr += sizeof(uintmax_t));
48 UNSAFE_BUFFERS(src_byte_ptr += sizeof(uintmax_t));
49 bytes -= sizeof(uintmax_t);
50 }
51 }
52
53 // Copy what's left after the happy-case byte-by-byte.
54 while (bytes > 0) {
55 std::atomic_ref<uint8_t>(*dst_byte_ptr)
56 .store(*src_byte_ptr, std::memory_order_relaxed);
57 // SAFETY: We check above that `dst_byte_ptr` and `src_byte_ptr` point
58 // to spans of sufficient size.
59 UNSAFE_BUFFERS(++dst_byte_ptr);
60 UNSAFE_BUFFERS(++src_byte_ptr);
61 --bytes;
62 }
63}
64
65} // namespace base::subtle