Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix deadlock related to _stash_obj_in_tls#180700

Closed
rtimpe wants to merge 1 commit into
gh/rtimpe/59/basefrom
gh/rtimpe/59/head
Closed

Fix deadlock related to _stash_obj_in_tls#180700
rtimpe wants to merge 1 commit into
gh/rtimpe/59/basefrom
gh/rtimpe/59/head

Conversation

@rtimpe

@rtimpe rtimpe commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

Stack from ghstack (oldest at bottom):

There's potential deadlock related to _stash_obj_in_tls. As of #173568 the
context object is stored in the calling thread TLS during _engine_run_backward. Normally this object deallocated after
the backward pass completes, but there's a race where the autograd device thread can end up holding the last reference.
If this happens the context object gets deallocated by the device thread, which needs to acquire the GIL. If another
thread happens to be holding the GIL while blocked on the device thread the result is a deadlock. See
#173568 for more detail

The fix here avoids aquiring the GIL in the device thread by clearing the GraphTask's shared_ptr to the context object
during cleanup. Since the TLS in the calling thread also has a shared_ptr, this avoids calling the SafePyObject
destructor (and therefore acquiring the GIL). I'm not a huge fan of this approach since it introduces a manual cleanup
step, but I wasn't able to come up with something better. Another option would be to use SafePyHandle instead of
SafePyObject and introduce a _remove_obj_from_tls python API. But that makes the python side responsible for
refcounting, which feels wrong.

I'm also not sure exactly how we end up with a thread holding the GIL and also blocked on an autograd device thread.
That feels like a bug, but it seems to be triggered by Meta-internal code, so I'm not able to debug it. All of which is
to say that this is the best approach I can come up with, but I'm very open to other suggestions.

Authored with Claude.

[ghstack-poisoned]
rtimpe added a commit that referenced this pull request Apr 17, 2026
There's potential deadlock related to _stash_obj_in_tls.  As of #173568 the
context object is stored in the calling thread TLS during _engine_run_backward.  Normally this object deallocated after
the backward pass completes, but there's a race where the autograd device thread can end up holding the last reference.
If this happens the context object gets deallocated by the device thread, which needs to acquire the GIL.  If another
thread happens to be holding the GIL while blocked on the device thread the result is a deadlock.  See
#173568 for more detail

The fix here avoids aquiring the GIL in the device thread by clearing the GraphTask's shared_ptr to the context object
during cleanup.  Since the TLS in the calling thread also has a shared_ptr, this avoids calling the SafePyObject
destructor (and therefore acquiring the GIL).  I'm not a huge fan of this approach since it introduces a manual cleanup
step, but I wasn't able to come up with something better.  Another option would be to use SafePyHandle instead of
SafePyObject and introduce a `_remove_obj_from_tls` python API.  But that makes the python side responsible for
refcounting, which feels wrong.

I'm also not sure exactly how we end up with a thread holding the GIL and also blocked on an autograd device thread.
That feels like a bug, but it seems to be triggered by Meta-internal code, so I'm not able to debug it.  All of which is
to say that this is the best approach I can come up with, but I'm very open to other suggestions.


ghstack-source-id: 81c9703
Pull-Request: #180700
@pytorch-bot

pytorch-bot Bot commented Apr 17, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/180700

Note: Links to docs will display an error until the docs builds have been completed.

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@pytorch-bot

pytorch-bot Bot commented Apr 17, 2026

Copy link
Copy Markdown

This PR needs a release notes: label

If your changes are user facing and intended to be a part of release notes, please use a label starting with release notes:.

If not, please add the topic: not user facing label.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "topic: not user facing"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

@rtimpe

rtimpe commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator Author

Duplicate of #180701

@rtimpe rtimpe marked this as a duplicate of #180701 Apr 17, 2026
@rtimpe rtimpe closed this Apr 17, 2026
@github-actions github-actions Bot deleted the gh/rtimpe/59/head branch May 18, 2026 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant