1 | //===-- tsan_clock_test.cpp -----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of ThreadSanitizer (TSan), a race detector. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "tsan_vector_clock.h" |
13 | |
14 | #include "gtest/gtest.h" |
15 | #include "tsan_rtl.h" |
16 | |
17 | namespace __tsan { |
18 | |
19 | TEST(VectorClock, GetSet) { |
20 | // Compiler won't ensure alignment on stack. |
21 | VectorClock *vc = New<VectorClock>(); |
22 | for (uptr i = 0; i < kThreadSlotCount; i++) |
23 | ASSERT_EQ(vc->Get(static_cast<Sid>(i)), kEpochZero); |
24 | for (uptr i = 0; i < kThreadSlotCount; i++) |
25 | vc->Set(static_cast<Sid>(i), static_cast<Epoch>(i)); |
26 | for (uptr i = 0; i < kThreadSlotCount; i++) |
27 | ASSERT_EQ(vc->Get(static_cast<Sid>(i)), static_cast<Epoch>(i)); |
28 | vc->Reset(); |
29 | for (uptr i = 0; i < kThreadSlotCount; i++) |
30 | ASSERT_EQ(vc->Get(static_cast<Sid>(i)), kEpochZero); |
31 | DestroyAndFree(vc); |
32 | } |
33 | |
34 | TEST(VectorClock, VectorOps) { |
35 | VectorClock *vc1 = New<VectorClock>(); |
36 | VectorClock *vc2 = nullptr; |
37 | VectorClock *vc3 = nullptr; |
38 | |
39 | vc1->Acquire(vc2); |
40 | for (uptr i = 0; i < kThreadSlotCount; i++) |
41 | ASSERT_EQ(vc1->Get(static_cast<Sid>(i)), kEpochZero); |
42 | vc1->Release(&vc2); |
43 | EXPECT_NE(vc2, nullptr); |
44 | vc1->Acquire(vc2); |
45 | for (uptr i = 0; i < kThreadSlotCount; i++) |
46 | ASSERT_EQ(vc1->Get(static_cast<Sid>(i)), kEpochZero); |
47 | |
48 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
49 | vc1->Set(static_cast<Sid>(i), static_cast<Epoch>(i)); |
50 | vc2->Set(static_cast<Sid>(i), static_cast<Epoch>(kThreadSlotCount - i)); |
51 | } |
52 | vc1->Acquire(vc2); |
53 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
54 | ASSERT_EQ(vc1->Get(static_cast<Sid>(i)), |
55 | static_cast<Epoch>(i < kThreadSlotCount / 2 ? kThreadSlotCount - i |
56 | : i)); |
57 | ASSERT_EQ(vc2->Get(static_cast<Sid>(i)), |
58 | static_cast<Epoch>(kThreadSlotCount - i)); |
59 | } |
60 | vc2->ReleaseStore(&vc3); |
61 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
62 | ASSERT_EQ(vc3->Get(static_cast<Sid>(i)), |
63 | static_cast<Epoch>(kThreadSlotCount - i)); |
64 | ASSERT_EQ(vc2->Get(static_cast<Sid>(i)), |
65 | static_cast<Epoch>(kThreadSlotCount - i)); |
66 | } |
67 | |
68 | vc1->Reset(); |
69 | vc2->Reset(); |
70 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
71 | vc1->Set(static_cast<Sid>(i), static_cast<Epoch>(i)); |
72 | vc2->Set(static_cast<Sid>(i), static_cast<Epoch>(kThreadSlotCount - i)); |
73 | } |
74 | vc1->ReleaseAcquire(&vc2); |
75 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
76 | Epoch expect = |
77 | static_cast<Epoch>(i < kThreadSlotCount / 2 ? kThreadSlotCount - i : i); |
78 | ASSERT_EQ(vc1->Get(static_cast<Sid>(i)), expect); |
79 | ASSERT_EQ(vc2->Get(static_cast<Sid>(i)), expect); |
80 | } |
81 | |
82 | vc1->Reset(); |
83 | vc2->Reset(); |
84 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
85 | vc1->Set(static_cast<Sid>(i), static_cast<Epoch>(i)); |
86 | vc2->Set(static_cast<Sid>(i), static_cast<Epoch>(kThreadSlotCount - i)); |
87 | } |
88 | vc1->ReleaseStoreAcquire(&vc2); |
89 | for (uptr i = 0; i < kThreadSlotCount; i++) { |
90 | ASSERT_EQ(vc1->Get(static_cast<Sid>(i)), |
91 | static_cast<Epoch>(i < kThreadSlotCount / 2 ? kThreadSlotCount - i |
92 | : i)); |
93 | ASSERT_EQ(vc2->Get(static_cast<Sid>(i)), static_cast<Epoch>(i)); |
94 | } |
95 | |
96 | DestroyAndFree(vc1); |
97 | DestroyAndFree(vc2); |
98 | DestroyAndFree(vc3); |
99 | } |
100 | |
101 | } // namespace __tsan |
102 | |