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

@advitrocks9advitrocks9 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.

CopilotAI lite review requested due to automatic review settings August 31, 2026 18:27
@github-actions

Copy link
Copy Markdown

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

CopilotAI 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.

FileDescription
cpp/src/arrow/util/thread_pool.hAdds FRIEND_TEST access for the new fork-safety regression test.
cpp/src/arrow/util/thread_pool.ccRestores ThreadPool internal invariants when worker thread creation throws; avoids counter leaks on launch failure.
cpp/src/arrow/util/thread_pool_test.ccAdds 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 threadcpp/src/arrow/util/thread_pool.cc Outdated
Comment threadcpp/src/arrow/util/thread_pool_test.cc Outdated
Comment threadcpp/src/arrow/util/thread_pool_test.cc Outdated
@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Sep 1, 2026
CopilotAI review requested due to automatic review settings September 2, 2026 20:48
@advitrocks9

Copy link
Copy Markdown
ContributorAuthor

All three done.

CopilotAI 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

Copy link
Copy Markdown

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

@pitrou

Copy link
Copy Markdown
Member

@github-actions crossbow submit -g cpp

@github-actions

Copy link
Copy Markdown

Revision: 0fa803a

Submitted crossbow builds: ursacomputing/crossbow @ actions-b40897411d

TaskStatus
example-cpp-minimal-build-staticGitHub Actions
example-cpp-minimal-build-static-system-dependencyGitHub Actions
example-cpp-tutorialGitHub Actions
test-build-cpp-fuzzGitHub Actions
test-conda-cppGitHub Actions
test-conda-cpp-valgrindGitHub Actions
test-debian-13-cpp-amd64GitHub Actions
test-debian-13-cpp-i386GitHub Actions
test-debian-experimental-cpp-gcc-15GitHub Actions
test-fedora-42-cppGitHub Actions
test-ubuntu-22.04-cppGitHub Actions
test-ubuntu-22.04-cpp-bundledGitHub Actions
test-ubuntu-22.04-cpp-emscriptenGitHub Actions
test-ubuntu-22.04-cpp-no-threadingGitHub Actions
test-ubuntu-24.04-cppGitHub Actions
test-ubuntu-24.04-cpp-bundled-offlineGitHub Actions
test-ubuntu-24.04-cpp-gcc-13-bundledGitHub Actions
test-ubuntu-24.04-cpp-gcc-14GitHub Actions
test-ubuntu-24.04-cpp-minimal-with-formatsGitHub Actions
test-ubuntu-24.04-cpp-thread-sanitizerGitHub Actions

@pitroupitrou 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

Copy link
Copy Markdown
Member

(note: CI failures are unrelated)

@pitrou
pitrou merged commit 157575a into apache:mainSep 3, 2026
61 of 62 checks passed
@pitroupitrou removed the awaiting committer review Awaiting committer review label Sep 3, 2026
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Sep 3, 2026
Sign up for freeto 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

@advitrocks9@pitrou