|
8 | 8 |
|
9 | 9 | #include "llvm/Support/ThreadPool.h" |
10 | 10 | #include "llvm/ADT/STLExtras.h" |
| 11 | +#include "llvm/ADT/ScopeExit.h" |
11 | 12 | #include "llvm/ADT/SetVector.h" |
12 | 13 | #include "llvm/ADT/SmallVector.h" |
13 | 14 | #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS |
@@ -197,6 +198,42 @@ TYPED_TEST(ThreadPoolTest, AsyncMoveOnly) { |
197 | 198 | ASSERT_EQ(42, f.get()); |
198 | 199 | } |
199 | 200 |
|
| 201 | +TYPED_TEST(ThreadPoolTest, AsyncRAIICaptures) { |
| 202 | + CHECK_UNSUPPORTED(); |
| 203 | + DefaultThreadPool Pool(hardware_concurrency(2)); |
| 204 | + |
| 205 | + // We use a task group and a non-atomic value to stress test that the chaining |
| 206 | + // of tasks via a captured RAII object in fact chains and synchronizes within |
| 207 | + // a group. |
| 208 | + ThreadPoolTaskGroup Group(Pool); |
| 209 | + int value = 0; |
| 210 | + |
| 211 | + // Create an RAII object that when destroyed schedules more work. This makes |
| 212 | + // it easy to check that the RAII is resolved at the same point as a task runs |
| 213 | + // on the thread pool. |
| 214 | + auto schedule_next = llvm::make_scope_exit([&Group, &value] { |
| 215 | + // We sleep before scheduling the final task to make it much more likely |
| 216 | + // that an incorrect implementation actually exbitits a bug. Without the |
| 217 | + // sleep, we may get "lucky" and have the second task finish before the |
| 218 | + // assertion below fails even with an incorrect implementaiton. The |
| 219 | + // sleep is making _failures_ more reliable, it is not needed for |
| 220 | + // correctness and this test should only flakily _pass_, never flakily |
| 221 | + // fail. |
| 222 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| 223 | + Group.async([&value] { value = 42; }); |
| 224 | + }); |
| 225 | + |
| 226 | + // Now schedule the initial task, moving the RAII object to schedule the final |
| 227 | + // task into its captures. |
| 228 | + Group.async([schedule_next = std::move(schedule_next)]() { |
| 229 | + // Nothing to do here, the captured RAII object does the work. |
| 230 | + }); |
| 231 | + |
| 232 | + // Both tasks should complete here, synchronizing with the read of value. |
| 233 | + Group.wait(); |
| 234 | + ASSERT_EQ(42, value); |
| 235 | +} |
| 236 | + |
200 | 237 | TYPED_TEST(ThreadPoolTest, GetFuture) { |
201 | 238 | CHECK_UNSUPPORTED(); |
202 | 239 | DefaultThreadPool Pool(hardware_concurrency(2)); |
|
0 commit comments