| 344 | } |
| 345 | |
| 346 | Result<T> Next() { |
| 347 | executor->Unpause(); |
| 348 | // This call may lead to tasks being scheduled in the serial executor |
| 349 | Future<T> next_fut = generator(); |
| 350 | next_fut.AddCallback([this](const Result<T>& res) { |
| 351 | // If we're done iterating we should drain the rest of the tasks in the executor |
| 352 | if (!res.ok() || IsIterationEnd(*res)) { |
| 353 | executor->Finish(); |
| 354 | return; |
| 355 | } |
| 356 | // Otherwise we will break out immediately, leaving the remaining tasks for |
| 357 | // the next call. |
| 358 | executor->Pause(); |
| 359 | }); |
| 360 | #ifdef ARROW_ENABLE_THREADING |
| 361 | // future must run on this thread |
| 362 | // Borrow this thread and run tasks until the future is finished |
| 363 | executor->RunLoop(); |
| 364 | #else |
| 365 | next_fut.Wait(); |
| 366 | #endif |
| 367 | if (!next_fut.is_finished()) { |
| 368 | // Not clear this is possible since RunLoop wouldn't generally exit |
| 369 | // unless we paused/finished which would imply next_fut has been |
| 370 | // finished. |
| 371 | return Status::Invalid( |
| 372 | "Serial executor terminated before next result computed"); |
| 373 | } |
| 374 | // At this point we may still have tasks in the executor, that is ok. |
| 375 | // We will run those tasks the next time through. |
| 376 | return next_fut.result(); |
| 377 | } |
| 378 | |
| 379 | std::unique_ptr<SerialExecutor> executor; |
| 380 | std::function<Future<T>()> generator; |
nothing calls this directly
no test coverage detected