Skip to content

GH-48137: [C++] Restore ThreadPool state when a worker fails to start - #51107

Merged
pitrou merged 2 commits into
apache:mainfrom
advitrocks9:fix-gh-48137
Sep 3, 2026
Merged

GH-48137: [C++] Restore ThreadPool state when a worker fails to start#51107
pitrou merged 2 commits into
apache:mainfrom
advitrocks9:fix-gh-48137

Conversation

@advitrocks9

@advitrocks9 advitrocks9 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Rationale for this change

LaunchWorkersUnlocked appends an entry to state_->workers_ before constructing the thread
that owns it, and only the worker itself erases that entry. If the std::thread constructor
fails, the entry stays behind with nothing left to remove it, so Shutdown waits forever on
workers_.empty(). The destructor takes the same path. The failure also escaped SpawnReal
after tasks_queued_or_running_ had been incremented, so WaitForIdle never returned either,
and once stale entries filled workers_ to capacity the pool stopped launching workers while
Spawn still returned OK for tasks nothing would run.

What changes are included in this PR?

LaunchWorkersUnlocked returns a Status. A failed thread construction erases the entry it had
reserved and returns an error, which SpawnReal and SetCapacity propagate. The task counter is
incremented after the launch rather than before, so a failed launch cannot leak a count.

Are these changes tested?

TestThreadPool.FailedWorkerLaunch lowers RLIMIT_NPROC to 1, spawns a task, restores the soft
limit, and then checks the pool reports no workers and no tasks and still shuts down. It skips on
macOS, where RLIMIT_NPROC counts processes rather than threads, and skips anywhere else the
lowered limit does not stop thread creation, such as under root.

Are there any user-facing changes?

Yes. Spawn, Submit and SetCapacity used to let a std::system_error escape when the OS
refused a new thread. They return an error Status now. ThreadPool::Make is unaffected, since
worker threads are only started on demand and a new pool starts none.

@advitrocks9
advitrocks9 requested a review from pitrou as a code owner August 31, 2026 18:27
Copilot AI lite review requested due to automatic review settings August 31, 2026 18:27
@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #48137 has been automatically assigned in GitHub to PR creator.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes exception-safety holes in Arrow’s C++ ThreadPool worker-launch path so that a failed std::thread construction cannot leave the pool in a wedged state (stale workers_ entries and inflated tasks_queued_or_running_) that would hang Shutdown() / WaitForIdle() and eventually prevent new workers from being started.

Changes:

  • Make LaunchWorkersUnlocked() erase the just-appended workers_ entry if std::thread construction throws, then rethrow.
  • Move tasks_queued_or_running_ increment in SpawnReal() to after a successful worker launch attempt (keeping the launch heuristic equivalent).
  • Add a fork-based regression test that forces thread creation failure and asserts the pool returns to a clean state and can still shut down.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
cpp/src/arrow/util/thread_pool.h Adds FRIEND_TEST access for the new fork-safety regression test.
cpp/src/arrow/util/thread_pool.cc Restores ThreadPool internal invariants when worker thread creation throws; avoids counter leaks on launch failure.
cpp/src/arrow/util/thread_pool_test.cc Adds FailedWorkerLaunch regression test that validates state restoration after forced thread creation failure.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cpp/src/arrow/util/thread_pool.cc Outdated
Comment thread cpp/src/arrow/util/thread_pool_test.cc Outdated
Comment thread cpp/src/arrow/util/thread_pool_test.cc Outdated
@github-actions github-actions Bot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Sep 1, 2026
Copilot AI review requested due to automatic review settings September 2, 2026 20:48
@advitrocks9

Copy link
Copy Markdown
Contributor Author

All three done.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The implementation and test expectations currently conflict with the PR description’s stated exception-propagation behavior, and the new test alters a process-wide rlimit in-process rather than isolating it in a forked child (risking flakiness).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment on lines +707 to +710
} catch (const std::exception& e) {
state_->workers_.erase(it);
return Status::UnknownError("Failed to launch worker thread: ", e.what());
}
Comment on lines +844 to +848
struct rlimit limit;
ASSERT_EQ(getrlimit(RLIMIT_NPROC, &limit), 0);
const rlim_t soft_limit = limit.rlim_cur;
limit.rlim_cur = 1;
if (setrlimit(RLIMIT_NPROC, &limit) != 0) {
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

⚠️ GitHub issue #48137 has been automatically assigned in GitHub to PR creator.

@pitrou

pitrou commented Sep 3, 2026

Copy link
Copy Markdown
Member

@github-actions crossbow submit -g cpp

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Revision: 0fa803a

Submitted crossbow builds: ursacomputing/crossbow @ actions-b40897411d

Task Status
example-cpp-minimal-build-static GitHub Actions
example-cpp-minimal-build-static-system-dependency GitHub Actions
example-cpp-tutorial GitHub Actions
test-build-cpp-fuzz GitHub Actions
test-conda-cpp GitHub Actions
test-conda-cpp-valgrind GitHub Actions
test-debian-13-cpp-amd64 GitHub Actions
test-debian-13-cpp-i386 GitHub Actions
test-debian-experimental-cpp-gcc-15 GitHub Actions
test-fedora-42-cpp GitHub Actions
test-ubuntu-22.04-cpp GitHub Actions
test-ubuntu-22.04-cpp-bundled GitHub Actions
test-ubuntu-22.04-cpp-emscripten GitHub Actions
test-ubuntu-22.04-cpp-no-threading GitHub Actions
test-ubuntu-24.04-cpp GitHub Actions
test-ubuntu-24.04-cpp-bundled-offline GitHub Actions
test-ubuntu-24.04-cpp-gcc-13-bundled GitHub Actions
test-ubuntu-24.04-cpp-gcc-14 GitHub Actions
test-ubuntu-24.04-cpp-minimal-with-formats GitHub Actions
test-ubuntu-24.04-cpp-thread-sanitizer GitHub Actions

@pitrou pitrou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update @advitrocks9 ! LGTM now.

@pitrou

pitrou commented Sep 3, 2026

Copy link
Copy Markdown
Member

(note: CI failures are unrelated)

@pitrou
pitrou merged commit 157575a into apache:main Sep 3, 2026
61 of 62 checks passed
@pitrou pitrou removed the awaiting committer review Awaiting committer review label Sep 3, 2026
@github-actions github-actions Bot added the awaiting committer review Awaiting committer review label Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants