1// Copyright 2017 The Fuchsia Authors. All rights reserved. 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 <fbl/atomic.h> 6 7#include <fbl/limits.h> 8#include <unittest/unittest.h> 9 10namespace { 11 12// A struct with an interesting size for pointer arithmetic tests. 13struct S { 14 char bytes[48]; 15}; 16 17using function_pointer = void(*)(); 18 19bool atomic_explicit_declarations_test() { 20 BEGIN_TEST; 21 22 [[gnu::unused]] fbl::atomic<char> zero_char(0); 23 [[gnu::unused]] fbl::atomic<signed char> zero_schar(0); 24 [[gnu::unused]] fbl::atomic<unsigned char> zero_uchar(0); 25 [[gnu::unused]] fbl::atomic<short> zero_short(0); 26 [[gnu::unused]] fbl::atomic<unsigned short> zero_ushort(0); 27 [[gnu::unused]] fbl::atomic<int> zero_int(0); 28 [[gnu::unused]] fbl::atomic<unsigned int> zero_uint(0); 29 [[gnu::unused]] fbl::atomic<long> zero_long(0); 30 [[gnu::unused]] fbl::atomic<unsigned long> zero_ulong(0); 31 [[gnu::unused]] fbl::atomic<long long> zero_llong(0); 32 [[gnu::unused]] fbl::atomic<unsigned long long> zero_ullong(0); 33 34 [[gnu::unused]] fbl::atomic<intptr_t> zero_intptr_t(0); 35 [[gnu::unused]] fbl::atomic<uintptr_t> zero_uintptr_t(0); 36 [[gnu::unused]] fbl::atomic<size_t> zero_size_t(0); 37 [[gnu::unused]] fbl::atomic<ptrdiff_t> zero_ptrdiff_t(0); 38 [[gnu::unused]] fbl::atomic<intmax_t> zero_intmax_t(0); 39 [[gnu::unused]] fbl::atomic<uintmax_t> zero_uintmax_t(0); 40 41 [[gnu::unused]] fbl::atomic<int8_t> zero_int8_t(0); 42 [[gnu::unused]] fbl::atomic<uint8_t> zero_uint8_t(0); 43 [[gnu::unused]] fbl::atomic<int16_t> zero_int16_t(0); 44 [[gnu::unused]] fbl::atomic<uint16_t> zero_uint16_t(0); 45 [[gnu::unused]] fbl::atomic<int32_t> zero_int32_t(0); 46 [[gnu::unused]] fbl::atomic<uint32_t> zero_uint32_t(0); 47 [[gnu::unused]] fbl::atomic<int64_t> zero_int64_t(0); 48 [[gnu::unused]] fbl::atomic<uint64_t> zero_uint64_t(0); 49 50 [[gnu::unused]] fbl::atomic<int_least8_t> zero_int_least8_t(0); 51 [[gnu::unused]] fbl::atomic<uint_least8_t> zero_uint_least8_t(0); 52 [[gnu::unused]] fbl::atomic<int_least16_t> zero_int_least16_t(0); 53 [[gnu::unused]] fbl::atomic<uint_least16_t> zero_uint_least16_t(0); 54 [[gnu::unused]] fbl::atomic<int_least32_t> zero_int_least32_t(0); 55 [[gnu::unused]] fbl::atomic<uint_least32_t> zero_uint_least32_t(0); 56 [[gnu::unused]] fbl::atomic<int_least64_t> zero_int_least64_t(0); 57 [[gnu::unused]] fbl::atomic<uint_least64_t> zero_uint_least64_t(0); 58 [[gnu::unused]] fbl::atomic<int_fast8_t> zero_int_fast8_t(0); 59 [[gnu::unused]] fbl::atomic<uint_fast8_t> zero_uint_fast8_t(0); 60 [[gnu::unused]] fbl::atomic<int_fast16_t> zero_int_fast16_t(0); 61 [[gnu::unused]] fbl::atomic<uint_fast16_t> zero_uint_fast16_t(0); 62 [[gnu::unused]] fbl::atomic<int_fast32_t> zero_int_fast32_t(0); 63 [[gnu::unused]] fbl::atomic<uint_fast32_t> zero_uint_fast32_t(0); 64 [[gnu::unused]] fbl::atomic<int_fast64_t> zero_int_fast64_t(0); 65 [[gnu::unused]] fbl::atomic<uint_fast64_t> zero_uint_fast64_t(0); 66 67 [[gnu::unused]] fbl::atomic<bool> zero_bool(false); 68 69 [[gnu::unused]] fbl::atomic<void*> zero_void_pointer(nullptr); 70 [[gnu::unused]] fbl::atomic<const void*> zero_const_void_pointer(nullptr); 71 [[gnu::unused]] fbl::atomic<volatile void*> zero_volatile_void_pointer(nullptr); 72 [[gnu::unused]] fbl::atomic<const volatile void*> zero_const_volatile_void_pointer(nullptr); 73 [[gnu::unused]] fbl::atomic<int*> zero_int_pointer(nullptr); 74 [[gnu::unused]] fbl::atomic<const int*> zero_const_int_pointer(nullptr); 75 [[gnu::unused]] fbl::atomic<volatile int*> zero_volatile_int_pointer(nullptr); 76 [[gnu::unused]] fbl::atomic<const volatile int*> zero_const_volatile_int_pointer(nullptr); 77 [[gnu::unused]] fbl::atomic<S*> zero_S_pointer(nullptr); 78 [[gnu::unused]] fbl::atomic<const S*> zero_const_S_pointer(nullptr); 79 [[gnu::unused]] fbl::atomic<volatile S*> zero_volatile_S_pointer(nullptr); 80 [[gnu::unused]] fbl::atomic<const volatile S*> zero_const_volatile_S_pointer(nullptr); 81 [[gnu::unused]] fbl::atomic<function_pointer> zero_function_pointer(nullptr); 82 83 END_TEST; 84} 85 86bool atomic_using_declarations_test() { 87 BEGIN_TEST; 88 89 [[gnu::unused]] fbl::atomic_char zero_char(0); 90 [[gnu::unused]] fbl::atomic_schar zero_schar(0); 91 [[gnu::unused]] fbl::atomic_uchar zero_uchar(0); 92 [[gnu::unused]] fbl::atomic_short zero_short(0); 93 [[gnu::unused]] fbl::atomic_ushort zero_ushort(0); 94 [[gnu::unused]] fbl::atomic_int zero_int(0); 95 [[gnu::unused]] fbl::atomic_uint zero_uint(0); 96 [[gnu::unused]] fbl::atomic_long zero_long(0); 97 [[gnu::unused]] fbl::atomic_ulong zero_ulong(0); 98 [[gnu::unused]] fbl::atomic_llong zero_llong(0); 99 [[gnu::unused]] fbl::atomic_ullong zero_ullong(0); 100 101 [[gnu::unused]] fbl::atomic_intptr_t zero_intptr_t(0); 102 [[gnu::unused]] fbl::atomic_uintptr_t zero_uintptr_t(0); 103 [[gnu::unused]] fbl::atomic_size_t zero_size_t(0); 104 [[gnu::unused]] fbl::atomic_ptrdiff_t zero_ptrdiff_t(0); 105 [[gnu::unused]] fbl::atomic_intmax_t zero_intmax_t(0); 106 [[gnu::unused]] fbl::atomic_uintmax_t zero_uintmax_t(0); 107 108 [[gnu::unused]] fbl::atomic_int8_t zero_int8_t(0); 109 [[gnu::unused]] fbl::atomic_uint8_t zero_uint8_t(0); 110 [[gnu::unused]] fbl::atomic_int16_t zero_int16_t(0); 111 [[gnu::unused]] fbl::atomic_uint16_t zero_uint16_t(0); 112 [[gnu::unused]] fbl::atomic_int32_t zero_int32_t(0); 113 [[gnu::unused]] fbl::atomic_uint32_t zero_uint32_t(0); 114 [[gnu::unused]] fbl::atomic_int64_t zero_int64_t(0); 115 [[gnu::unused]] fbl::atomic_uint64_t zero_uint64_t(0); 116 117 [[gnu::unused]] fbl::atomic_int_least8_t zero_int_least8_t(0); 118 [[gnu::unused]] fbl::atomic_uint_least8_t zero_uint_least8_t(0); 119 [[gnu::unused]] fbl::atomic_int_least16_t zero_int_least16_t(0); 120 [[gnu::unused]] fbl::atomic_uint_least16_t zero_uint_least16_t(0); 121 [[gnu::unused]] fbl::atomic_int_least32_t zero_int_least32_t(0); 122 [[gnu::unused]] fbl::atomic_uint_least32_t zero_uint_least32_t(0); 123 [[gnu::unused]] fbl::atomic_int_least64_t zero_int_least64_t(0); 124 [[gnu::unused]] fbl::atomic_uint_least64_t zero_uint_least64_t(0); 125 [[gnu::unused]] fbl::atomic_int_fast8_t zero_int_fast8_t(0); 126 [[gnu::unused]] fbl::atomic_uint_fast8_t zero_uint_fast8_t(0); 127 [[gnu::unused]] fbl::atomic_int_fast16_t zero_int_fast16_t(0); 128 [[gnu::unused]] fbl::atomic_uint_fast16_t zero_uint_fast16_t(0); 129 [[gnu::unused]] fbl::atomic_int_fast32_t zero_int_fast32_t(0); 130 [[gnu::unused]] fbl::atomic_uint_fast32_t zero_uint_fast32_t(0); 131 [[gnu::unused]] fbl::atomic_int_fast64_t zero_int_fast64_t(0); 132 [[gnu::unused]] fbl::atomic_uint_fast64_t zero_uint_fast64_t(0); 133 134 [[gnu::unused]] fbl::atomic_bool zero_bool(false); 135 136 END_TEST; 137} 138 139// To increase test readability after this point, static_assert that 140// most of these are the same as fbl::atomic<some other type>. That 141// way no one has to read a million lines of test code about 142// fbl::atomic_uint_least32_t. 143 144template <typename T> 145constexpr bool IsSameAsSomeBuiltin() { 146 return fbl::is_same<T, fbl::atomic_char>::value || 147 fbl::is_same<T, fbl::atomic_schar>::value || 148 fbl::is_same<T, fbl::atomic_uchar>::value || 149 fbl::is_same<T, fbl::atomic_short>::value || 150 fbl::is_same<T, fbl::atomic_ushort>::value || 151 fbl::is_same<T, fbl::atomic_int>::value || 152 fbl::is_same<T, fbl::atomic_uint>::value || 153 fbl::is_same<T, fbl::atomic_long>::value || 154 fbl::is_same<T, fbl::atomic_ulong>::value || 155 fbl::is_same<T, fbl::atomic_llong>::value || 156 fbl::is_same<T, fbl::atomic_ullong>::value || 157 fbl::is_same<T, fbl::atomic_bool>::value; 158} 159 160static_assert(IsSameAsSomeBuiltin<fbl::atomic_intptr_t>(), ""); 161static_assert(IsSameAsSomeBuiltin<fbl::atomic_uintptr_t>(), ""); 162static_assert(IsSameAsSomeBuiltin<fbl::atomic_size_t>(), ""); 163static_assert(IsSameAsSomeBuiltin<fbl::atomic_ptrdiff_t>(), ""); 164static_assert(IsSameAsSomeBuiltin<fbl::atomic_intmax_t>(), ""); 165static_assert(IsSameAsSomeBuiltin<fbl::atomic_uintmax_t>(), ""); 166 167static_assert(IsSameAsSomeBuiltin<fbl::atomic_int8_t>(), ""); 168static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint8_t>(), ""); 169static_assert(IsSameAsSomeBuiltin<fbl::atomic_int16_t>(), ""); 170static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint16_t>(), ""); 171static_assert(IsSameAsSomeBuiltin<fbl::atomic_int32_t>(), ""); 172static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint32_t>(), ""); 173static_assert(IsSameAsSomeBuiltin<fbl::atomic_int64_t>(), ""); 174static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint64_t>(), ""); 175 176static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least8_t>(), ""); 177static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least8_t>(), ""); 178static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least16_t>(), ""); 179static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least16_t>(), ""); 180static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least32_t>(), ""); 181static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least32_t>(), ""); 182static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_least64_t>(), ""); 183static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_least64_t>(), ""); 184static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast8_t>(), ""); 185static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast8_t>(), ""); 186static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast16_t>(), ""); 187static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast16_t>(), ""); 188static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast32_t>(), ""); 189static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast32_t>(), ""); 190static_assert(IsSameAsSomeBuiltin<fbl::atomic_int_fast64_t>(), ""); 191static_assert(IsSameAsSomeBuiltin<fbl::atomic_uint_fast64_t>(), ""); 192 193// We should be able to instantiate fbl::atomics of enum type as well. 194 195enum unspecified_enum { 196 kUnspecifiedValue = 23, 197}; 198__UNUSED fbl::atomic<unspecified_enum> atomic_unspecified_enum; 199 200enum specified_enum_char : char { 201 kSpecifiedValue_char = 23, 202}; 203__UNUSED fbl::atomic<specified_enum_char> atomic_specified_enum_char; 204 205enum specified_enum_signed_char : signed char { 206 kSpecifiedValue_signed_char = 23, 207}; 208__UNUSED fbl::atomic<specified_enum_signed_char> atomic_specified_enum_signed_char; 209 210enum specified_enum_unsigned_char : unsigned char { 211 kSpecifiedValue_unsigned_char = 23, 212}; 213__UNUSED fbl::atomic<specified_enum_unsigned_char> atomic_specified_enum_unsigned_char; 214 215enum specified_enum_short : short { 216 kSpecifiedValue_short = 23, 217}; 218__UNUSED fbl::atomic<specified_enum_short> atomic_specified_enum_short; 219 220enum specified_enum_unsigned_short : unsigned short { 221 kSpecifiedValue_unsigned_short = 23, 222}; 223__UNUSED fbl::atomic<specified_enum_unsigned_short> atomic_specified_enum_unsigned_short; 224 225enum specified_enum_int : int { 226 kSpecifiedValue_int = 23, 227}; 228__UNUSED fbl::atomic<specified_enum_int> atomic_specified_enum_int; 229 230enum specified_enum_unsigned_int : unsigned int { 231 kSpecifiedValue_unsigned_int = 23, 232}; 233__UNUSED fbl::atomic<specified_enum_unsigned_int> atomic_specified_enum_unsigned_int; 234 235enum specified_enum_long : long { 236 kSpecifiedValue_long = 23, 237}; 238__UNUSED fbl::atomic<specified_enum_long> atomic_specified_enum_long; 239 240enum specified_enum_unsigned_long : unsigned long{ 241 kSpecifiedValue_unsigned_long = 23, 242}; 243__UNUSED fbl::atomic<specified_enum_unsigned_long> atomic_specified_enum_unsigned_long; 244 245enum specified_enum_long_long : long long { 246 kSpecifiedValue_long_long = 23, 247}; 248__UNUSED fbl::atomic<specified_enum_long_long> atomic_specified_enum_long_long; 249 250enum specified_enum_unsigned_long_long : unsigned long long { 251 kSpecifiedValue_unsigned_long_long = 23, 252}; 253__UNUSED fbl::atomic<specified_enum_unsigned_long_long> atomic_specified_enum_unsigned_long_long; 254 255enum specified_enum_bool : bool { 256 kSpecifiedValue_bool = true, 257}; 258__UNUSED fbl::atomic<specified_enum_bool> atomic_specified_enum_bool; 259 260enum struct unspecified_struct_enum { 261 kUnspecifiedValueStruct = 23, 262}; 263__UNUSED fbl::atomic<unspecified_struct_enum> atomic_unspecified_struct_enum; 264 265enum struct specified_struct_enum_char : char { 266 kSpecifiedStructValue_char = 23, 267}; 268__UNUSED fbl::atomic<specified_struct_enum_char> atomic_specified_struct_enum_char; 269 270enum struct specified_struct_enum_signed_char : signed char { 271 kSpecifiedStructValue_signed_char = 23, 272}; 273__UNUSED fbl::atomic<specified_struct_enum_signed_char> atomic_specified_struct_enum_signed_char; 274 275enum struct specified_struct_enum_unsigned_char : unsigned char { 276 kSpecifiedStructValue_unsigned_char = 23, 277}; 278__UNUSED fbl::atomic<specified_struct_enum_unsigned_char> atomic_specified_struct_enum_unsigned_char; 279 280enum struct specified_struct_enum_short : short { 281 kSpecifiedStructValue_short = 23, 282}; 283__UNUSED fbl::atomic<specified_struct_enum_short> atomic_specified_struct_enum_short; 284 285enum struct specified_struct_enum_unsigned_short : unsigned short { 286 kSpecifiedStructValue_unsigned_short = 23, 287}; 288__UNUSED fbl::atomic<specified_struct_enum_unsigned_short> atomic_specified_struct_enum_unsigned_short; 289 290enum struct specified_struct_enum_int : int { 291 kSpecifiedStructValue_int = 23, 292}; 293__UNUSED fbl::atomic<specified_struct_enum_int> atomic_specified_struct_enum_int; 294 295enum struct specified_struct_enum_unsigned_int : unsigned int { 296 kSpecifiedStructValue_unsigned_int = 23, 297}; 298__UNUSED fbl::atomic<specified_struct_enum_unsigned_int> atomic_specified_struct_enum_unsigned_int; 299 300enum struct specified_struct_enum_long : long { 301 kSpecifiedStructValue_long = 23, 302}; 303__UNUSED fbl::atomic<specified_struct_enum_long> atomic_specified_struct_enum_long; 304 305enum struct specified_struct_enum_unsigned_long : unsigned long{ 306 kSpecifiedStructValue_unsigned_long = 23, 307}; 308__UNUSED fbl::atomic<specified_struct_enum_unsigned_long> atomic_specified_struct_enum_unsigned_long; 309 310enum struct specified_struct_enum_long_long : long long { 311 kSpecifiedStructValue_long_long = 23, 312}; 313__UNUSED fbl::atomic<specified_struct_enum_long_long> atomic_specified_struct_enum_long_long; 314 315enum struct specified_struct_enum_unsigned_long_long : unsigned long long { 316 kSpecifiedStructValue_unsigned_long_long = 23, 317}; 318__UNUSED fbl::atomic<specified_struct_enum_unsigned_long_long> atomic_specified_struct_enum_unsigned_long_long; 319 320enum struct specified_struct_enum_bool : bool { 321 kSpecifiedStructValue_bool = true, 322}; 323__UNUSED fbl::atomic<specified_struct_enum_bool> atomic_specified_struct_enum_bool; 324 325bool atomic_wont_compile_test() { 326 BEGIN_TEST; 327 328 // fbl::atomic only supports integer, enum, and pointer types. 329 330#if TEST_WILL_NOT_COMPILE || 0 331 struct not_integral {}; 332 fbl::atomic<not_integral> not_integral; 333#endif 334 335#if TEST_WILL_NOT_COMPILE || 0 336 fbl::atomic<float> not_integral; 337#endif 338 339#if TEST_WILL_NOT_COMPILE || 0 340 fbl::atomic<double> not_integral; 341#endif 342 343 END_TEST; 344} 345 346fbl::memory_order orders[] = { 347 fbl::memory_order_relaxed, 348 fbl::memory_order_acquire, 349 fbl::memory_order_release, 350 fbl::memory_order_acq_rel, 351 fbl::memory_order_seq_cst, 352}; 353 354// Bunch of machinery for arithmetic tests. 355template <typename T> 356using ordinary_op = T (*)(T*, T); 357 358template <typename T> 359using atomic_op = T (*)(fbl::atomic<T>*, T, fbl::memory_order); 360 361template <typename T> 362using volatile_op = T (*)(volatile fbl::atomic<T>*, T, fbl::memory_order); 363 364template <typename T> 365struct TestCase { 366 ordinary_op<T> ordinary; 367 atomic_op<T> nonmember_atomic; 368 atomic_op<T> member_atomic; 369 volatile_op<T> nonmember_volatile; 370 volatile_op<T> member_volatile; 371}; 372 373template <typename T> 374T test_values[] = { 375 0, 376 1, 377 23, 378 fbl::numeric_limits<T>::min() / 4, 379 fbl::numeric_limits<T>::max() / 4, 380}; 381 382template <> 383bool test_values<bool>[] = { 384 false, 385 true, 386 true, 387 false, 388 true, 389}; 390 391template <> 392void* test_values<void*>[] = { 393 &test_values<int>[0], 394 &test_values<int>[1], 395 &test_values<int>[2], 396 &test_values<int>[3], 397 &test_values<int>[4], 398}; 399 400template <> 401const void* test_values<const void*>[] = { 402 &test_values<int>[0], 403 &test_values<int>[1], 404 &test_values<int>[2], 405 &test_values<int>[3], 406 &test_values<int>[4], 407}; 408 409template <> 410volatile void* test_values<volatile void*>[] = { 411 &test_values<int>[0], 412 &test_values<int>[1], 413 &test_values<int>[2], 414 &test_values<int>[3], 415 &test_values<int>[4], 416}; 417 418template <> 419const volatile void* test_values<const volatile void*>[] = { 420 &test_values<int>[0], 421 &test_values<int>[1], 422 &test_values<int>[2], 423 &test_values<int>[3], 424 &test_values<int>[4], 425}; 426 427template <> 428int* test_values<int*>[] = { 429 &test_values<int>[0], 430 &test_values<int>[1], 431 &test_values<int>[2], 432 &test_values<int>[3], 433 &test_values<int>[4], 434}; 435 436template <> 437const int* test_values<const int*>[] = { 438 &test_values<int>[0], 439 &test_values<int>[1], 440 &test_values<int>[2], 441 &test_values<int>[3], 442 &test_values<int>[4], 443}; 444 445template <> 446volatile int* test_values<volatile int*>[] = { 447 &test_values<int>[0], 448 &test_values<int>[1], 449 &test_values<int>[2], 450 &test_values<int>[3], 451 &test_values<int>[4], 452}; 453 454template <> 455const volatile int* test_values<const volatile int*>[] = { 456 &test_values<int>[0], 457 &test_values<int>[1], 458 &test_values<int>[2], 459 &test_values<int>[3], 460 &test_values<int>[4], 461}; 462 463S test_values_of_S[] = { {}, {}, {}, {} }; 464 465template <> 466S* test_values<S*>[] = { 467 &test_values_of_S[0], 468 &test_values_of_S[1], 469 &test_values_of_S[2], 470 &test_values_of_S[3], 471 nullptr, 472}; 473 474template <> 475const S* test_values<const S*>[] = { 476 &test_values_of_S[0], 477 &test_values_of_S[1], 478 &test_values_of_S[2], 479 &test_values_of_S[3], 480 nullptr, 481}; 482 483template <> 484volatile S* test_values<volatile S*>[] = { 485 &test_values_of_S[0], 486 &test_values_of_S[1], 487 &test_values_of_S[2], 488 &test_values_of_S[3], 489 nullptr, 490}; 491 492template <> 493const volatile S* test_values<const volatile S*>[] = { 494 &test_values_of_S[0], 495 &test_values_of_S[1], 496 &test_values_of_S[2], 497 &test_values_of_S[3], 498 nullptr, 499}; 500 501void nothing_0() {} 502void nothing_1() {} 503void nothing_2() {} 504void nothing_3() {} 505 506template <> 507function_pointer test_values<function_pointer>[] = { 508 ¬hing_0, 509 ¬hing_1, 510 ¬hing_2, 511 ¬hing_3, 512 nullptr, 513}; 514 515template <typename T> 516TestCase<T> test_cases[] = { 517 { 518 [](T* ptr_to_a, T b) -> T { 519 T a = *ptr_to_a; 520 *ptr_to_a = static_cast<T>(a + b); 521 return a; 522 }, 523 fbl::atomic_fetch_add<T>, 524 [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 525 return ptr_to_atomic_a->fetch_add(b, order); 526 }, 527 fbl::atomic_fetch_add<T>, 528 [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 529 return ptr_to_atomic_a->fetch_add(b, order); 530 }, 531 }, 532 { 533 [](T* ptr_to_a, T b) -> T { 534 T a = *ptr_to_a; 535 *ptr_to_a = static_cast<T>(a & b); 536 return a; 537 }, 538 fbl::atomic_fetch_and<T>, 539 [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 540 return ptr_to_atomic_a->fetch_and(b, order); 541 }, 542 fbl::atomic_fetch_and<T>, 543 [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 544 return ptr_to_atomic_a->fetch_and(b, order); 545 }, 546 }, 547 { 548 [](T* ptr_to_a, T b) -> T { 549 T a = *ptr_to_a; 550 *ptr_to_a = static_cast<T>(a | b); 551 return a; 552 }, 553 fbl::atomic_fetch_or<T>, 554 [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 555 return ptr_to_atomic_a->fetch_or(b, order); 556 }, 557 fbl::atomic_fetch_or<T>, 558 [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 559 return ptr_to_atomic_a->fetch_or(b, order); 560 }, 561 }, 562 { 563 [](T* ptr_to_a, T b) -> T { 564 T a = *ptr_to_a; 565 *ptr_to_a = static_cast<T>(a ^ b); 566 return a; 567 }, 568 fbl::atomic_fetch_xor<T>, 569 [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 570 return ptr_to_atomic_a->fetch_xor(b, order); 571 }, 572 fbl::atomic_fetch_xor<T>, 573 [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 574 return ptr_to_atomic_a->fetch_xor(b, order); 575 }, 576 }, 577}; 578 579template <typename T> 580TestCase<T> subtraction_test_case = { 581 [](T* ptr_to_a, T b) -> T { 582 T a = *ptr_to_a; 583 *ptr_to_a = static_cast<T>(a - b); 584 return a; 585 }, 586 fbl::atomic_fetch_sub, 587 [](fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 588 return ptr_to_atomic_a->fetch_sub(b, order); 589 }, 590 fbl::atomic_fetch_sub, 591 [](volatile fbl::atomic<T>* ptr_to_atomic_a, T b, fbl::memory_order order) -> T { 592 return ptr_to_atomic_a->fetch_sub(b, order); 593 }, 594}; 595 596template <typename T> 597bool math_test() { 598 for (const T original_left : test_values<T>) { 599 for (T right : test_values<T>) { 600 for (const auto& order : orders) { 601 for (auto test_case : test_cases<T>) { 602 { 603 fbl::atomic<T> atomic_left(original_left); 604 T left = original_left; 605 ASSERT_EQ(test_case.ordinary(&left, right), 606 test_case.member_atomic(&atomic_left, right, order), 607 "Atomic and ordinary math differ"); 608 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 609 } 610 { 611 fbl::atomic<T> atomic_left(original_left); 612 T left = original_left; 613 ASSERT_EQ(test_case.ordinary(&left, right), 614 test_case.nonmember_atomic(&atomic_left, right, order), 615 "Atomic and ordinary math differ"); 616 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 617 } 618 { 619 volatile fbl::atomic<T> atomic_left(original_left); 620 T left = original_left; 621 ASSERT_EQ(test_case.ordinary(&left, right), 622 test_case.member_volatile(&atomic_left, right, order), 623 "Atomic and ordinary math differ"); 624 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 625 } 626 { 627 volatile fbl::atomic<T> atomic_left(original_left); 628 T left = original_left; 629 ASSERT_EQ(test_case.ordinary(&left, right), 630 test_case.nonmember_volatile(&atomic_left, right, order), 631 "Atomic and ordinary math differ"); 632 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 633 } 634 } 635 // Let's not worry about signed subtraction UB. 636 if (fbl::is_unsigned<T>::value) { 637 { 638 fbl::atomic<T> atomic_left(original_left); 639 T left = original_left; 640 ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right), 641 subtraction_test_case<T>.member_atomic(&atomic_left, right, order), 642 "Atomic and ordinary math differ"); 643 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 644 } 645 { 646 fbl::atomic<T> atomic_left(original_left); 647 T left = original_left; 648 ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right), 649 subtraction_test_case<T>.nonmember_atomic(&atomic_left, right, order), 650 "Atomic and ordinary math differ"); 651 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 652 } 653 { 654 volatile fbl::atomic<T> atomic_left(original_left); 655 T left = original_left; 656 ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right), 657 subtraction_test_case<T>.member_volatile(&atomic_left, right, order), 658 "Atomic and ordinary math differ"); 659 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 660 } 661 { 662 volatile fbl::atomic<T> atomic_left(original_left); 663 T left = original_left; 664 ASSERT_EQ(subtraction_test_case<T>.ordinary(&left, right), 665 subtraction_test_case<T>.nonmember_volatile(&atomic_left, right, order), 666 "Atomic and ordinary math differ"); 667 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 668 } 669 } 670 } 671 } 672 } 673 674 return true; 675} 676 677template <typename T> 678using ordinary_pointer_op = T (*)(T*, ptrdiff_t); 679 680template <typename T> 681using atomic_pointer_op = T (*)(fbl::atomic<T>*, ptrdiff_t, fbl::memory_order); 682 683template <typename T> 684using volatile_pointer_op = T (*)(volatile fbl::atomic<T>*, ptrdiff_t, fbl::memory_order); 685 686template <typename T> 687struct PointerTestCase { 688 ordinary_pointer_op<T> ordinary; 689 atomic_pointer_op<T> nonmember_atomic; 690 atomic_pointer_op<T> member_atomic; 691 volatile_pointer_op<T> nonmember_volatile; 692 volatile_pointer_op<T> member_volatile; 693}; 694 695template <typename T> 696PointerTestCase<T> pointer_add_test_case = { 697 [](T* ptr_to_a, ptrdiff_t d) -> T { 698 T a = *ptr_to_a; 699 *ptr_to_a = a + d; 700 return a; 701 }, 702 [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 703 return fbl::atomic_fetch_add(ptr_to_atomic_a, d, order); 704 }, 705 [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 706 return ptr_to_atomic_a->fetch_add(d, order); 707 }, 708 [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 709 return fbl::atomic_fetch_add(ptr_to_atomic_a, d, order); 710 }, 711 [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 712 return ptr_to_atomic_a->fetch_add(d, order); 713 }, 714}; 715 716template <typename T> 717PointerTestCase<T> pointer_sub_test_case = { 718 [](T* ptr_to_a, ptrdiff_t d) -> T { 719 T a = *ptr_to_a; 720 *ptr_to_a = a - d; 721 return a; 722 }, 723 [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 724 return fbl::atomic_fetch_sub(ptr_to_atomic_a, d, order); 725 }, 726 [](fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 727 return ptr_to_atomic_a->fetch_sub(d, order); 728 }, 729 [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 730 return fbl::atomic_fetch_sub(ptr_to_atomic_a, d, order); 731 }, 732 [](volatile fbl::atomic<T>* ptr_to_atomic_a, ptrdiff_t d, fbl::memory_order order) -> T { 733 return ptr_to_atomic_a->fetch_sub(d, order); 734 }, 735}; 736 737template <typename T> 738bool pointer_add_test() { 739 static_assert(fbl::is_pointer<T>::value, ""); 740 ptrdiff_t right = 2; 741 const auto& test_case = pointer_add_test_case<T>; 742 for (const T original_left : test_values<T>) { 743 for (const auto& order : orders) { 744 { 745 fbl::atomic<T> atomic_left(original_left); 746 T left = original_left; 747 ASSERT_EQ(test_case.ordinary(&left, right), 748 test_case.member_atomic(&atomic_left, right, order), 749 "Atomic and ordinary math differ"); 750 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 751 } 752 { 753 fbl::atomic<T> atomic_left(original_left); 754 T left = original_left; 755 ASSERT_EQ(test_case.ordinary(&left, right), 756 test_case.nonmember_atomic(&atomic_left, right, order), 757 "Atomic and ordinary math differ"); 758 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 759 } 760 { 761 volatile fbl::atomic<T> atomic_left(original_left); 762 T left = original_left; 763 ASSERT_EQ(test_case.ordinary(&left, right), 764 test_case.member_volatile(&atomic_left, right, order), 765 "Atomic and ordinary math differ"); 766 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 767 } 768 { 769 volatile fbl::atomic<T> atomic_left(original_left); 770 T left = original_left; 771 ASSERT_EQ(test_case.ordinary(&left, right), 772 test_case.nonmember_volatile(&atomic_left, right, order), 773 "Atomic and ordinary math differ"); 774 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 775 } 776 } 777 778 right -= 1; 779 } 780 781 return true; 782} 783 784template <typename T> 785bool pointer_sub_test() { 786 static_assert(fbl::is_pointer<T>::value, ""); 787 ptrdiff_t right = -2; 788 const auto& test_case = pointer_sub_test_case<T>; 789 for (const T original_left : test_values<T>) { 790 for (const auto& order : orders) { 791 { 792 fbl::atomic<T> atomic_left(original_left); 793 T left = original_left; 794 ASSERT_EQ(test_case.ordinary(&left, right), 795 test_case.member_atomic(&atomic_left, right, order), 796 "Atomic and ordinary math differ"); 797 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 798 } 799 { 800 fbl::atomic<T> atomic_left(original_left); 801 T left = original_left; 802 ASSERT_EQ(test_case.ordinary(&left, right), 803 test_case.nonmember_atomic(&atomic_left, right, order), 804 "Atomic and ordinary math differ"); 805 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 806 } 807 { 808 volatile fbl::atomic<T> atomic_left(original_left); 809 T left = original_left; 810 ASSERT_EQ(test_case.ordinary(&left, right), 811 test_case.member_volatile(&atomic_left, right, order), 812 "Atomic and ordinary math differ"); 813 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 814 } 815 { 816 volatile fbl::atomic<T> atomic_left(original_left); 817 T left = original_left; 818 ASSERT_EQ(test_case.ordinary(&left, right), 819 test_case.nonmember_volatile(&atomic_left, right, order), 820 "Atomic and ordinary math differ"); 821 ASSERT_EQ(left, atomic_load(&atomic_left), "Atomic and ordinary math differ"); 822 } 823 } 824 825 right += 1; 826 } 827 828 return true; 829} 830 831template <typename T> 832bool load_store_test() { 833 fbl::atomic<T> atomic_value; 834 835 for (T value : test_values<T>) { 836 atomic_value.store(value); 837 ASSERT_EQ(atomic_value.load(), value, "Member load/store busted"); 838 } 839 840 for (T value : test_values<T>) { 841 fbl::atomic_store(&atomic_value, value); 842 ASSERT_EQ(atomic_load(&atomic_value), value, "Nonmember load/store busted"); 843 } 844 845 volatile fbl::atomic<T> volatile_value; 846 847 for (T value : test_values<T>) { 848 volatile_value.store(value); 849 ASSERT_EQ(volatile_value.load(), value, "Member load/store busted"); 850 } 851 852 for (T value : test_values<T>) { 853 fbl::atomic_store(&volatile_value, value); 854 ASSERT_EQ(atomic_load(&volatile_value), value, "Nonmember load/store busted"); 855 } 856 857 return true; 858} 859 860template <typename T> 861bool exchange_test() { 862 T last_value = test_values<T>[0]; 863 fbl::atomic<T> atomic_value(last_value); 864 865 for (T value : test_values<T>) { 866 ASSERT_EQ(atomic_value.load(), last_value, "Member exchange busted"); 867 ASSERT_EQ(atomic_value.exchange(value), last_value, "Member exchange busted"); 868 last_value = value; 869 } 870 871 last_value = test_values<T>[0]; 872 atomic_value.store(last_value); 873 874 for (T value : test_values<T>) { 875 ASSERT_EQ(fbl::atomic_load(&atomic_value), last_value, "Nonmember exchange busted"); 876 ASSERT_EQ(fbl::atomic_exchange(&atomic_value, value), last_value, "Nonmember exchange busted"); 877 last_value = value; 878 } 879 880 last_value = test_values<T>[0]; 881 volatile fbl::atomic<T> volatile_value(last_value); 882 883 for (T value : test_values<T>) { 884 ASSERT_EQ(volatile_value.load(), last_value, "Member exchange busted"); 885 ASSERT_EQ(volatile_value.exchange(value), last_value, "Member exchange busted"); 886 last_value = value; 887 } 888 889 last_value = test_values<T>[0]; 890 volatile_value.store(last_value); 891 892 for (T value : test_values<T>) { 893 ASSERT_EQ(fbl::atomic_load(&volatile_value), last_value, "Nonmember exchange busted"); 894 ASSERT_EQ(fbl::atomic_exchange(&volatile_value, value), last_value, "Nonmember exchange busted"); 895 last_value = value; 896 } 897 898 return true; 899} 900 901template <typename T> 902struct cas_function { 903 bool (*function)(fbl::atomic<T>* atomic_ptr, T* expected, T desired, 904 fbl::memory_order success_order, fbl::memory_order failure_order); 905 bool can_spuriously_fail; 906}; 907 908template <typename T> 909cas_function<T> cas_functions[] = { 910 {fbl::atomic_compare_exchange_weak, true}, 911 {fbl::atomic_compare_exchange_strong, false}, 912 {[](fbl::atomic<T>* atomic_ptr, T* expected, T desired, 913 fbl::memory_order success_order, fbl::memory_order failure_order) { 914 return atomic_ptr->compare_exchange_weak(expected, desired, success_order, failure_order); 915 }, 916 true}, 917 {[](fbl::atomic<T>* atomic_ptr, T* expected, T desired, 918 fbl::memory_order success_order, fbl::memory_order failure_order) { 919 return atomic_ptr->compare_exchange_strong(expected, desired, success_order, failure_order); 920 }, 921 false}, 922}; 923 924template <typename T> 925struct volatile_cas_function { 926 bool (*function)(volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired, 927 fbl::memory_order success_order, fbl::memory_order failure_order); 928 bool can_spuriously_fail; 929}; 930 931template <typename T> 932volatile_cas_function<T> volatile_cas_functions[] = { 933 {fbl::atomic_compare_exchange_weak, true}, 934 {fbl::atomic_compare_exchange_strong, false}, 935 {[](volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired, 936 fbl::memory_order success_order, fbl::memory_order failure_order) { 937 return atomic_ptr->compare_exchange_weak(expected, desired, success_order, failure_order); 938 }, 939 true}, 940 {[](volatile fbl::atomic<T>* atomic_ptr, T* expected, T desired, 941 fbl::memory_order success_order, fbl::memory_order failure_order) { 942 return atomic_ptr->compare_exchange_strong(expected, desired, success_order, failure_order); 943 }, 944 false}}; 945 946enum cas_slots { 947 kExpected = 0, 948 kActual = 1, 949 kDesired = 2, 950}; 951 952template <typename T> 953T cas_test_values[] = { 954 22, 955 23, 956 24, 957}; 958 959template <> 960bool cas_test_values<bool>[] = { 961 false, 962 true, 963 false, 964}; 965 966template <> 967void* cas_test_values<void*>[] = { 968 &cas_test_values<int>[0], 969 &cas_test_values<int>[1], 970 &cas_test_values<int>[2], 971}; 972 973template <> 974const void* cas_test_values<const void*>[] = { 975 &cas_test_values<int>[0], 976 &cas_test_values<int>[1], 977 &cas_test_values<int>[2], 978}; 979 980template <> 981volatile void* cas_test_values<volatile void*>[] = { 982 &cas_test_values<int>[0], 983 &cas_test_values<int>[1], 984 &cas_test_values<int>[2], 985}; 986 987template <> 988const volatile void* cas_test_values<const volatile void*>[] = { 989 &cas_test_values<int>[0], 990 &cas_test_values<int>[1], 991 &cas_test_values<int>[2], 992}; 993 994template <> 995int* cas_test_values<int*>[] = { 996 &cas_test_values<int>[0], 997 &cas_test_values<int>[1], 998 &cas_test_values<int>[2], 999}; 1000 1001template <> 1002const int* cas_test_values<const int*>[] = { 1003 &cas_test_values<int>[0], 1004 &cas_test_values<int>[1], 1005 &cas_test_values<int>[2], 1006}; 1007 1008template <> 1009volatile int* cas_test_values<volatile int*>[] = { 1010 &cas_test_values<int>[0], 1011 &cas_test_values<int>[1], 1012 &cas_test_values<int>[2], 1013}; 1014 1015template <> 1016const volatile int* cas_test_values<const volatile int*>[] = { 1017 &cas_test_values<int>[0], 1018 &cas_test_values<int>[1], 1019 &cas_test_values<int>[2], 1020}; 1021 1022S cas_test_values_of_S[] = { {}, {} }; 1023 1024template <> 1025S* cas_test_values<S*>[] = { 1026 &cas_test_values_of_S[0], 1027 &cas_test_values_of_S[1], 1028 nullptr, 1029}; 1030 1031template <> 1032const S* cas_test_values<const S*>[] = { 1033 &cas_test_values_of_S[0], 1034 &cas_test_values_of_S[1], 1035 nullptr, 1036}; 1037 1038template <> 1039volatile S* cas_test_values<volatile S*>[] = { 1040 &cas_test_values_of_S[0], 1041 &cas_test_values_of_S[1], 1042 nullptr, 1043}; 1044 1045template <> 1046const volatile S* cas_test_values<const volatile S*>[] = { 1047 &cas_test_values_of_S[0], 1048 &cas_test_values_of_S[1], 1049 nullptr, 1050}; 1051 1052template <> 1053function_pointer cas_test_values<function_pointer>[] = { 1054 ¬hing_0, 1055 ¬hing_1, 1056 nullptr, 1057}; 1058 1059template <typename T> 1060bool compare_exchange_test() { 1061 for (auto cas : cas_functions<T>) { 1062 for (const auto& success_order : orders) { 1063 for (const auto& failure_order : orders) { 1064 { 1065 // Failure case 1066 T actual = cas_test_values<T>[kActual]; 1067 fbl::atomic<T> atomic_value(actual); 1068 T expected = cas_test_values<T>[kExpected]; 1069 T desired = cas_test_values<T>[kDesired]; 1070 EXPECT_FALSE(cas.function(&atomic_value, &expected, desired, 1071 success_order, failure_order), 1072 "compare-exchange shouldn't have succeeded!"); 1073 EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!"); 1074 } 1075 { 1076 // Success case 1077 T actual = cas_test_values<T>[kActual]; 1078 fbl::atomic<T> atomic_value(actual); 1079 T expected = actual; 1080 T desired = cas_test_values<T>[kDesired]; 1081 // Some compare-and-swap functions can spuriously fail. 1082 bool succeeded = cas.function(&atomic_value, &expected, desired, 1083 success_order, failure_order); 1084 if (!cas.can_spuriously_fail) { 1085 EXPECT_TRUE(succeeded, "compare-exchange should've succeeded!"); 1086 } 1087 EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!"); 1088 } 1089 } 1090 } 1091 } 1092 1093 for (auto cas : volatile_cas_functions<T>) { 1094 for (const auto& success_order : orders) { 1095 for (const auto& failure_order : orders) { 1096 { 1097 // Failure case 1098 T actual = cas_test_values<T>[kActual]; 1099 fbl::atomic<T> atomic_value(actual); 1100 T expected = cas_test_values<T>[kExpected]; 1101 T desired = cas_test_values<T>[kDesired]; 1102 EXPECT_FALSE(cas.function(&atomic_value, &expected, desired, 1103 success_order, failure_order), 1104 "compare-exchange shouldn't have succeeded!"); 1105 EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!"); 1106 } 1107 { 1108 // Success case 1109 T actual = cas_test_values<T>[kActual]; 1110 fbl::atomic<T> atomic_value(actual); 1111 T expected = actual; 1112 T desired = cas_test_values<T>[kDesired]; 1113 // Compare-and-swap can spuriously fail. 1114 // Some compare-and-swap functions can spuriously fail. 1115 bool succeeded = cas.function(&atomic_value, &expected, desired, 1116 success_order, failure_order); 1117 if (!cas.can_spuriously_fail) { 1118 EXPECT_TRUE(succeeded, "compare-exchange should've succeeded!"); 1119 } 1120 EXPECT_EQ(expected, actual, "compare-exchange didn't report actual value!"); 1121 } 1122 } 1123 } 1124 } 1125 1126 return true; 1127} 1128 1129// Actual test cases on operations for each builtin type. 1130bool atomic_math_test() { 1131 BEGIN_TEST; 1132 1133 ASSERT_TRUE(math_test<char>()); 1134 ASSERT_TRUE(math_test<signed char>()); 1135 ASSERT_TRUE(math_test<unsigned char>()); 1136 ASSERT_TRUE(math_test<short>()); 1137 ASSERT_TRUE(math_test<unsigned short>()); 1138 ASSERT_TRUE(math_test<int>()); 1139 ASSERT_TRUE(math_test<unsigned int>()); 1140 ASSERT_TRUE(math_test<long>()); 1141 ASSERT_TRUE(math_test<unsigned long>()); 1142 ASSERT_TRUE(math_test<long long>()); 1143 ASSERT_TRUE(math_test<unsigned long long>()); 1144 1145 END_TEST; 1146} 1147 1148bool atomic_pointer_math_test() { 1149 BEGIN_TEST; 1150 1151 ASSERT_TRUE(pointer_add_test<int*>()); 1152 ASSERT_TRUE(pointer_add_test<const int*>()); 1153 ASSERT_TRUE(pointer_add_test<volatile int*>()); 1154 ASSERT_TRUE(pointer_add_test<const volatile int*>()); 1155 ASSERT_TRUE(pointer_add_test<S*>()); 1156 ASSERT_TRUE(pointer_add_test<const S*>()); 1157 ASSERT_TRUE(pointer_add_test<volatile S*>()); 1158 ASSERT_TRUE(pointer_add_test<const volatile S*>()); 1159 1160 ASSERT_TRUE(pointer_sub_test<int*>()); 1161 ASSERT_TRUE(pointer_sub_test<const int*>()); 1162 ASSERT_TRUE(pointer_sub_test<volatile int*>()); 1163 ASSERT_TRUE(pointer_sub_test<const volatile int*>()); 1164 ASSERT_TRUE(pointer_sub_test<S*>()); 1165 ASSERT_TRUE(pointer_sub_test<const S*>()); 1166 ASSERT_TRUE(pointer_sub_test<volatile S*>()); 1167 ASSERT_TRUE(pointer_sub_test<const volatile S*>()); 1168 1169 // Note that there is no void pointer or function pointer math, 1170 // and so no tests of them. 1171 1172 END_TEST; 1173} 1174 1175bool atomic_load_store_test() { 1176 BEGIN_TEST; 1177 1178 ASSERT_TRUE(load_store_test<char>()); 1179 ASSERT_TRUE(load_store_test<signed char>()); 1180 ASSERT_TRUE(load_store_test<unsigned char>()); 1181 ASSERT_TRUE(load_store_test<short>()); 1182 ASSERT_TRUE(load_store_test<unsigned short>()); 1183 ASSERT_TRUE(load_store_test<int>()); 1184 ASSERT_TRUE(load_store_test<unsigned int>()); 1185 ASSERT_TRUE(load_store_test<long>()); 1186 ASSERT_TRUE(load_store_test<unsigned long>()); 1187 ASSERT_TRUE(load_store_test<long long>()); 1188 ASSERT_TRUE(load_store_test<unsigned long long>()); 1189 ASSERT_TRUE(load_store_test<bool>()); 1190 1191 ASSERT_TRUE(load_store_test<void*>()); 1192 ASSERT_TRUE(load_store_test<const void*>()); 1193 ASSERT_TRUE(load_store_test<volatile void*>()); 1194 ASSERT_TRUE(load_store_test<const volatile void*>()); 1195 ASSERT_TRUE(load_store_test<int*>()); 1196 ASSERT_TRUE(load_store_test<const int*>()); 1197 ASSERT_TRUE(load_store_test<volatile int*>()); 1198 ASSERT_TRUE(load_store_test<const volatile int*>()); 1199 ASSERT_TRUE(load_store_test<function_pointer>()); 1200 1201 END_TEST; 1202} 1203 1204bool atomic_exchange_test() { 1205 BEGIN_TEST; 1206 1207 ASSERT_TRUE(exchange_test<char>()); 1208 ASSERT_TRUE(exchange_test<signed char>()); 1209 ASSERT_TRUE(exchange_test<unsigned char>()); 1210 ASSERT_TRUE(exchange_test<short>()); 1211 ASSERT_TRUE(exchange_test<unsigned short>()); 1212 ASSERT_TRUE(exchange_test<int>()); 1213 ASSERT_TRUE(exchange_test<unsigned int>()); 1214 ASSERT_TRUE(exchange_test<long>()); 1215 ASSERT_TRUE(exchange_test<unsigned long>()); 1216 ASSERT_TRUE(exchange_test<long long>()); 1217 ASSERT_TRUE(exchange_test<unsigned long long>()); 1218 ASSERT_TRUE(exchange_test<bool>()); 1219 1220 ASSERT_TRUE(exchange_test<void*>()); 1221 ASSERT_TRUE(exchange_test<const void*>()); 1222 ASSERT_TRUE(exchange_test<volatile void*>()); 1223 ASSERT_TRUE(exchange_test<const volatile void*>()); 1224 ASSERT_TRUE(exchange_test<int*>()); 1225 ASSERT_TRUE(exchange_test<const int*>()); 1226 ASSERT_TRUE(exchange_test<volatile int*>()); 1227 ASSERT_TRUE(exchange_test<const volatile int*>()); 1228 ASSERT_TRUE(exchange_test<S*>()); 1229 ASSERT_TRUE(exchange_test<const S*>()); 1230 ASSERT_TRUE(exchange_test<volatile S*>()); 1231 ASSERT_TRUE(exchange_test<const volatile S*>()); 1232 ASSERT_TRUE(exchange_test<function_pointer>()); 1233 1234 END_TEST; 1235} 1236 1237bool atomic_compare_exchange_test() { 1238 BEGIN_TEST; 1239 1240 ASSERT_TRUE(compare_exchange_test<char>()); 1241 ASSERT_TRUE(compare_exchange_test<signed char>()); 1242 ASSERT_TRUE(compare_exchange_test<unsigned char>()); 1243 ASSERT_TRUE(compare_exchange_test<short>()); 1244 ASSERT_TRUE(compare_exchange_test<unsigned short>()); 1245 ASSERT_TRUE(compare_exchange_test<int>()); 1246 ASSERT_TRUE(compare_exchange_test<unsigned int>()); 1247 ASSERT_TRUE(compare_exchange_test<long>()); 1248 ASSERT_TRUE(compare_exchange_test<unsigned long>()); 1249 ASSERT_TRUE(compare_exchange_test<long long>()); 1250 ASSERT_TRUE(compare_exchange_test<unsigned long long>()); 1251 ASSERT_TRUE(compare_exchange_test<bool>()); 1252 1253 ASSERT_TRUE(compare_exchange_test<void*>()); 1254 ASSERT_TRUE(compare_exchange_test<const void*>()); 1255 ASSERT_TRUE(compare_exchange_test<volatile void*>()); 1256 ASSERT_TRUE(compare_exchange_test<const volatile void*>()); 1257 ASSERT_TRUE(compare_exchange_test<int*>()); 1258 ASSERT_TRUE(compare_exchange_test<const int*>()); 1259 ASSERT_TRUE(compare_exchange_test<volatile int*>()); 1260 ASSERT_TRUE(compare_exchange_test<const volatile int*>()); 1261 ASSERT_TRUE(compare_exchange_test<S*>()); 1262 ASSERT_TRUE(compare_exchange_test<const S*>()); 1263 ASSERT_TRUE(compare_exchange_test<volatile S*>()); 1264 ASSERT_TRUE(compare_exchange_test<const volatile S*>()); 1265 ASSERT_TRUE(compare_exchange_test<function_pointer>()); 1266 1267 END_TEST; 1268} 1269 1270// Code wants to rely on the ABI of fbl::atomic types. This means 1271// matching the underlying types' size and alignment, and the class 1272// being standard layout. 1273 1274static_assert(sizeof(fbl::atomic<char>) == sizeof(char), ""); 1275static_assert(sizeof(fbl::atomic<signed char>) == sizeof(signed char), ""); 1276static_assert(sizeof(fbl::atomic<unsigned char>) == sizeof(unsigned char), ""); 1277static_assert(sizeof(fbl::atomic<short>) == sizeof(short), ""); 1278static_assert(sizeof(fbl::atomic<unsigned short>) == sizeof(unsigned short), ""); 1279static_assert(sizeof(fbl::atomic<int>) == sizeof(int), ""); 1280static_assert(sizeof(fbl::atomic<unsigned int>) == sizeof(unsigned int), ""); 1281static_assert(sizeof(fbl::atomic<long>) == sizeof(long), ""); 1282static_assert(sizeof(fbl::atomic<unsigned long>) == sizeof(unsigned long), ""); 1283static_assert(sizeof(fbl::atomic<long long>) == sizeof(long long), ""); 1284static_assert(sizeof(fbl::atomic<unsigned long long>) == sizeof(unsigned long long), ""); 1285static_assert(sizeof(fbl::atomic<bool>) == sizeof(bool), ""); 1286static_assert(sizeof(fbl::atomic<void*>) == sizeof(void*), ""); 1287static_assert(sizeof(fbl::atomic<const void*>) == sizeof(const void*), ""); 1288static_assert(sizeof(fbl::atomic<volatile void*>) == sizeof(volatile void*), ""); 1289static_assert(sizeof(fbl::atomic<const volatile void*>) == sizeof(const volatile void*), ""); 1290static_assert(sizeof(fbl::atomic<int*>) == sizeof(int*), ""); 1291static_assert(sizeof(fbl::atomic<const int*>) == sizeof(const int*), ""); 1292static_assert(sizeof(fbl::atomic<volatile int*>) == sizeof(volatile int*), ""); 1293static_assert(sizeof(fbl::atomic<const volatile int*>) == sizeof(const volatile int*), ""); 1294static_assert(sizeof(fbl::atomic<S*>) == sizeof(S*), ""); 1295static_assert(sizeof(fbl::atomic<const S*>) == sizeof(const S*), ""); 1296static_assert(sizeof(fbl::atomic<volatile S*>) == sizeof(volatile S*), ""); 1297static_assert(sizeof(fbl::atomic<const volatile S*>) == sizeof(const volatile S*), ""); 1298static_assert(sizeof(fbl::atomic<function_pointer>) == sizeof(function_pointer), ""); 1299 1300static_assert(alignof(fbl::atomic<char>) == alignof(char), ""); 1301static_assert(alignof(fbl::atomic<signed char>) == alignof(signed char), ""); 1302static_assert(alignof(fbl::atomic<unsigned char>) == alignof(unsigned char), ""); 1303static_assert(alignof(fbl::atomic<short>) == alignof(short), ""); 1304static_assert(alignof(fbl::atomic<unsigned short>) == alignof(unsigned short), ""); 1305static_assert(alignof(fbl::atomic<int>) == alignof(int), ""); 1306static_assert(alignof(fbl::atomic<unsigned int>) == alignof(unsigned int), ""); 1307static_assert(alignof(fbl::atomic<long>) == alignof(long), ""); 1308static_assert(alignof(fbl::atomic<unsigned long>) == alignof(unsigned long), ""); 1309static_assert(alignof(fbl::atomic<long long>) == alignof(long long), ""); 1310static_assert(alignof(fbl::atomic<unsigned long long>) == alignof(unsigned long long), ""); 1311static_assert(alignof(fbl::atomic<bool>) == alignof(bool), ""); 1312static_assert(alignof(fbl::atomic<void*>) == alignof(void*), ""); 1313static_assert(alignof(fbl::atomic<const void*>) == alignof(const void*), ""); 1314static_assert(alignof(fbl::atomic<volatile void*>) == alignof(volatile void*), ""); 1315static_assert(alignof(fbl::atomic<const volatile void*>) == alignof(const volatile void*), ""); 1316static_assert(alignof(fbl::atomic<int*>) == alignof(int*), ""); 1317static_assert(alignof(fbl::atomic<const int*>) == alignof(const int*), ""); 1318static_assert(alignof(fbl::atomic<volatile int*>) == alignof(volatile int*), ""); 1319static_assert(alignof(fbl::atomic<const volatile int*>) == alignof(const volatile int*), ""); 1320static_assert(alignof(fbl::atomic<S*>) == alignof(S*), ""); 1321static_assert(alignof(fbl::atomic<const S*>) == alignof(const S*), ""); 1322static_assert(alignof(fbl::atomic<volatile S*>) == alignof(volatile S*), ""); 1323static_assert(alignof(fbl::atomic<const volatile S*>) == alignof(const volatile S*), ""); 1324static_assert(alignof(fbl::atomic<function_pointer>) == alignof(function_pointer), ""); 1325 1326static_assert(fbl::is_standard_layout<fbl::atomic<char>>::value, ""); 1327static_assert(fbl::is_standard_layout<fbl::atomic<signed char>>::value, ""); 1328static_assert(fbl::is_standard_layout<fbl::atomic<unsigned char>>::value, ""); 1329static_assert(fbl::is_standard_layout<fbl::atomic<short>>::value, ""); 1330static_assert(fbl::is_standard_layout<fbl::atomic<unsigned short>>::value, ""); 1331static_assert(fbl::is_standard_layout<fbl::atomic<int>>::value, ""); 1332static_assert(fbl::is_standard_layout<fbl::atomic<unsigned int>>::value, ""); 1333static_assert(fbl::is_standard_layout<fbl::atomic<long>>::value, ""); 1334static_assert(fbl::is_standard_layout<fbl::atomic<unsigned long>>::value, ""); 1335static_assert(fbl::is_standard_layout<fbl::atomic<long long>>::value, ""); 1336static_assert(fbl::is_standard_layout<fbl::atomic<unsigned long long>>::value, ""); 1337static_assert(fbl::is_standard_layout<fbl::atomic<bool>>::value, ""); 1338static_assert(fbl::is_standard_layout<fbl::atomic<void*>>::value, ""); 1339static_assert(fbl::is_standard_layout<fbl::atomic<const void*>>::value, ""); 1340static_assert(fbl::is_standard_layout<fbl::atomic<volatile void*>>::value, ""); 1341static_assert(fbl::is_standard_layout<fbl::atomic<const volatile void*>>::value, ""); 1342static_assert(fbl::is_standard_layout<fbl::atomic<void*>>::value, ""); 1343static_assert(fbl::is_standard_layout<fbl::atomic<const int*>>::value, ""); 1344static_assert(fbl::is_standard_layout<fbl::atomic<volatile int*>>::value, ""); 1345static_assert(fbl::is_standard_layout<fbl::atomic<const volatile int*>>::value, ""); 1346static_assert(fbl::is_standard_layout<fbl::atomic<S*>>::value, ""); 1347static_assert(fbl::is_standard_layout<fbl::atomic<const S*>>::value, ""); 1348static_assert(fbl::is_standard_layout<fbl::atomic<volatile S*>>::value, ""); 1349static_assert(fbl::is_standard_layout<fbl::atomic<const volatile S*>>::value, ""); 1350static_assert(fbl::is_standard_layout<fbl::atomic<function_pointer>>::value, ""); 1351 1352bool atomic_fence_test() { 1353 BEGIN_TEST; 1354 1355 for (const auto& order : orders) { 1356 atomic_thread_fence(order); 1357 atomic_signal_fence(order); 1358 } 1359 1360 END_TEST; 1361} 1362 1363bool atomic_init_test() { 1364 BEGIN_TEST; 1365 1366 fbl::atomic_uint32_t atomic1; 1367 fbl::atomic_init(&atomic1, 1u); 1368 EXPECT_EQ(1u, atomic1.load()); 1369 1370 fbl::atomic_uint32_t atomic2; 1371 volatile fbl::atomic_uint32_t* vatomic2 = &atomic2; 1372 fbl::atomic_init(vatomic2, 2u); 1373 EXPECT_EQ(2u, atomic2.load()); 1374 1375 END_TEST; 1376} 1377 1378} // namespace 1379 1380BEGIN_TEST_CASE(atomic_tests) 1381RUN_NAMED_TEST("Atomic explicit declarations test", atomic_explicit_declarations_test) 1382RUN_NAMED_TEST("Atomic using declarations test", atomic_using_declarations_test) 1383RUN_NAMED_TEST("Atomic won't compile test", atomic_wont_compile_test) 1384RUN_NAMED_TEST("Atomic math test", atomic_math_test) 1385RUN_NAMED_TEST("Atomic pointer math test", atomic_pointer_math_test) 1386RUN_NAMED_TEST("Atomic load/store test", atomic_load_store_test) 1387RUN_NAMED_TEST("Atomic exchange test", atomic_exchange_test) 1388RUN_NAMED_TEST("Atomic compare-exchange test", atomic_compare_exchange_test) 1389RUN_NAMED_TEST("Atomic fence test", atomic_fence_test) 1390RUN_NAMED_TEST("Atomic init test", atomic_init_test) 1391END_TEST_CASE(atomic_tests); 1392