|
28 | 28 | namespace bthread { |
29 | 29 | void id_status(bthread_id_t, std::ostream &); |
30 | 30 | uint32_t id_value(bthread_id_t id); |
| 31 | +extern void (*g_bthread_id_join_before_wait_for_test)(void*); |
| 32 | +extern void* g_bthread_id_join_before_wait_arg_for_test; |
31 | 33 | } |
32 | 34 |
|
33 | 35 | namespace { |
@@ -116,33 +118,47 @@ TEST(BthreadIdTest, join_before_destroy) { |
116 | 118 |
|
117 | 119 | struct JoinRaceArgs { |
118 | 120 | bthread_id_t id; |
119 | | - std::atomic<bool> entered; |
| 121 | + std::atomic<bool> join_butex_read; |
| 122 | + std::atomic<bool> allow_wait; |
120 | 123 | }; |
121 | 124 |
|
| 125 | +void pause_join_before_wait(void* arg) { |
| 126 | + JoinRaceArgs* args = static_cast<JoinRaceArgs*>(arg); |
| 127 | + args->join_butex_read.store(true, std::memory_order_release); |
| 128 | + while (!args->allow_wait.load(std::memory_order_acquire)) { |
| 129 | + std::this_thread::yield(); |
| 130 | + } |
| 131 | +} |
| 132 | + |
122 | 133 | void* join_race_waiter(void* arg) { |
123 | 134 | JoinRaceArgs* args = static_cast<JoinRaceArgs*>(arg); |
124 | | - args->entered.store(true, std::memory_order_release); |
125 | 135 | EXPECT_EQ(0, bthread_id_join(args->id)); |
126 | 136 | return nullptr; |
127 | 137 | } |
128 | 138 |
|
129 | 139 | TEST(BthreadIdTest, join_races_with_destroy) { |
130 | | - for (int i = 0; i < 100; ++i) { |
131 | | - bthread_id_t id; |
132 | | - ASSERT_EQ(0, bthread_id_create(&id, nullptr, nullptr)); |
133 | | - JoinRaceArgs args; |
134 | | - args.id = id; |
135 | | - args.entered.store(false, std::memory_order_relaxed); |
136 | | - pthread_t waiter; |
137 | | - ASSERT_EQ(0, pthread_create(&waiter, nullptr, join_race_waiter, &args)); |
138 | | - while (!args.entered.load(std::memory_order_acquire)) { |
139 | | - std::this_thread::yield(); |
140 | | - } |
141 | | - void* data = nullptr; |
142 | | - ASSERT_EQ(0, bthread_id_trylock(id, &data)); |
143 | | - ASSERT_EQ(0, bthread_id_unlock_and_destroy(id)); |
144 | | - ASSERT_EQ(0, pthread_join(waiter, nullptr)); |
| 140 | + bthread_id_t id; |
| 141 | + ASSERT_EQ(0, bthread_id_create(&id, nullptr, nullptr)); |
| 142 | + JoinRaceArgs args; |
| 143 | + args.id = id; |
| 144 | + args.join_butex_read.store(false, std::memory_order_relaxed); |
| 145 | + args.allow_wait.store(false, std::memory_order_relaxed); |
| 146 | + bthread::g_bthread_id_join_before_wait_for_test = pause_join_before_wait; |
| 147 | + bthread::g_bthread_id_join_before_wait_arg_for_test = &args; |
| 148 | + |
| 149 | + pthread_t waiter; |
| 150 | + ASSERT_EQ(0, pthread_create(&waiter, nullptr, join_race_waiter, &args)); |
| 151 | + while (!args.join_butex_read.load(std::memory_order_acquire)) { |
| 152 | + std::this_thread::yield(); |
145 | 153 | } |
| 154 | + void* data = nullptr; |
| 155 | + ASSERT_EQ(0, bthread_id_trylock(id, &data)); |
| 156 | + ASSERT_EQ(0, bthread_id_unlock_and_destroy(id)); |
| 157 | + args.allow_wait.store(true, std::memory_order_release); |
| 158 | + ASSERT_EQ(0, pthread_join(waiter, nullptr)); |
| 159 | + |
| 160 | + bthread::g_bthread_id_join_before_wait_for_test = nullptr; |
| 161 | + bthread::g_bthread_id_join_before_wait_arg_for_test = nullptr; |
146 | 162 | } |
147 | 163 |
|
148 | 164 | struct OnResetArg { |
|
0 commit comments