-
Notifications
You must be signed in to change notification settings - Fork 233
Avoid race due to deleted imports when cleaning up objects at interpreter shutdown #973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a9165d6
28db9df
33f68da
7155fd1
e0bea0c
b68a5d1
013cf22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ from cuda.core.experimental._utils.cuda_utils import ( | |||||||
| CUDAError, | ||||||||
| driver, | ||||||||
| handle_return, | ||||||||
| is_shutting_down | ||||||||
| ) | ||||||||
|
|
||||||||
| if TYPE_CHECKING: | ||||||||
|
|
@@ -108,10 +109,11 @@ cdef class Event: | |||||||
| self._ctx_handle = ctx_handle | ||||||||
| return self | ||||||||
|
|
||||||||
| cpdef close(self): | ||||||||
| cpdef close(self, is_shutting_down=is_shutting_down): | ||||||||
| """Destroy the event.""" | ||||||||
| if self._handle is not None: | ||||||||
| err, = driver.cuEventDestroy(self._handle) | ||||||||
| if not is_shutting_down() | ||||||||
| err, = driver.cuEventDestroy(self._handle) | ||||||||
|
||||||||
| err, = driver.cuEventDestroy(self._handle) | |
| if (destroy := getattr(driver, "cuEventDestroy", None)) is not None: | |
| err, = destroy(self._handle) |
Then you don't need the global hack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to use a field-tested solution (see the internal thread) instead of coming up with a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about sys.is_finalizing()? There's probably not a more field tested solution than what's in the standard library.
In this case it also seems particularly suited to the problem being solved here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely better, but this is still a hack where if we run things under tools like cuda-memcheck that check for resource leaks it will still pop.
Additionally, we'd need to carry these checks everywhere that code could be called in __del__ functions, I believe even transitively. I.E. the raise_if_driver_error function.
What if we moved to a __dealloc__ function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed internally,sys.is_finalizing() - while official - only returns True at the very late stage of interpreter shutdown, later than all of the exit handlers (which this PR is based on). It is unclear to me if this solves the problem. I feel nervous about this. Do we have any known, big projects using this solution?
What if we moved to a
__dealloc__function?
No, we can't do this (yet), because we currently call Python bindings. Once #866 lands we can switch to this, but I need some time to work it out and I prefer this to be fixed independently (and asap).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the relevant steps, in order, during interpreter shutdown:
- wait for threads to shutdown
- wait for any pending calls
- call
atexithandlers (where the flag would be set) - set the interpreter to be officially in finalizing mode (this information is what
sys.is_finalizing()uses) - collect garbage (
__del__would be called here)
So, it doesn't really matter which approach we take, and it's overall less code and less hacky code to use a standard library builtin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes it sound like the previously proposed solution using atexit would work, but it wouldn't, because __del__ is still called at the same point in the program regardless of where the state of the interpreter is checked.
It would be more helpful to provide thorough reasoning (as I did above). Right now, it just looks like everything I said was incorrect without any description as to why that is.
Uh oh!
There was an error while loading. Please reload this page.