| 695 | params[i].maxDrivers = kThreadsPerTask; |
| 696 | } |
| 697 | std::vector<int32_t> counters(kNumTasks, 0); |
| 698 | std::vector<std::thread> threads; |
| 699 | threads.reserve(kNumTasks); |
| 700 | for (int32_t i = 0; i < kNumTasks; ++i) { |
| 701 | threads.push_back(std::thread([this, ¶ms, &counters, i]() { |
| 702 | readResults(params[i], ResultOperation::kYield, 10'000, &counters[i], i); |
| 703 | })); |
| 704 | } |
| 705 | for (int32_t i = 0; i < kNumTasks; ++i) { |
| 706 | threads[i].join(); |
| 707 | EXPECT_WITH_DELAY(stateFutures_.at(i).isReady()); |
| 708 | EXPECT_EQ(counters[i], kThreadsPerTask * hits); |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | // A testing Operator that periodically does one of the following: |
| 713 | // |
| 714 | // 1. Blocks and registers a resume that continues the Driver after a timed |
| 715 | // pause. This simulates blocking to wait for exchange or consumer. |
| 716 | // |
| 717 | // 2. Enters a suspended section where the Driver is on thread but is not |
| 718 | // counted as running and is therefore instantaneously cancellable and pausable. |
| 719 | // Comes back on thread after a timed pause. This simulates an RPC to an out of |
| 720 | // process service. |
| 721 | // |
| 722 | // 3. Enters a suspended section where this pauses and resumes random Tasks, |
| 723 | // including its own Task. This simulates making Tasks release memory under |
| 724 | // memory contention, checkpointing Tasks for migration or fault tolerance and |
| 725 | // other process-wide coordination activities. |
| 726 | // |
| 727 | // These situations will occur with arbitrary concurrency and sequence and must |
| 728 | // therefore be in one test to check against deadlocks. |
| 729 | class TestingPauser : public Operator { |
| 730 | public: |
| 731 | TestingPauser( |
| 732 | DriverCtx* ctx, |
| 733 | int32_t id, |
| 734 | std::shared_ptr<const TestingPauserNode> node, |
no test coverage detected