gh-140746: Fix Thread.start() that can hang indefinitely - v2#144750
gh-140746: Fix Thread.start() that can hang indefinitely - v2#144750YvesDup wants to merge 3 commits intopython:mainfrom
Conversation
bkap123
left a comment
There was a problem hiding this comment.
Left a couple of small comments on semantics.
|
|
||
| // Handles state transitions according to the following diagram: | ||
| // | ||
| // NOT_STARTED -> STARTING -> RUNNING -> DONE |
There was a problem hiding this comment.
This comment should be updated now that there can be a FAILED state. Possibly just replace error with FAILED.
| // NOT_STARTED -> STARTING -> RUNNING -> DONE | ||
| // | ^ | ||
| // | | | ||
| // +----- error --------+ |
There was a problem hiding this comment.
| // +----- FAILED --------+ |
|
|
||
| PyMutex mutex; | ||
|
|
||
| PyEvent thread_is_bootstraped; |
There was a problem hiding this comment.
"bootstraped" is misspelled everywhere (should be bootstrapped).
| PyErr_FormatUnraisable( | ||
| "Exception ignored in thread started by %R", boot->func); | ||
| } | ||
| // Notify that the bootstraped is done and failed (e.g. Memory error). |
There was a problem hiding this comment.
I think this makes more sense:
| // Notify that the bootstraped is done and failed (e.g. Memory error). | |
| // Notify that bootstrap is done and failed (e.g. Memory error). |
| @@ -0,0 +1,2 @@ | |||
| Fix :func:`threading.Thread.start` that can hang indefinitely in case of heap memory exhaustion | |||
| during initialization of the new thread. | |||
There was a problem hiding this comment.
Maybe add something about the new FAILED state that is managed by the C code?
| return NULL; | ||
| } | ||
|
|
||
| // gh-140746: catch error before thread really start |
There was a problem hiding this comment.
| // gh-140746: catch error before thread really start | |
| // gh-140746: catch error before thread really starts |
ryv-odoo
left a comment
There was a problem hiding this comment.
Hello @YvesDup ,
Now I understand what you meant in your comment 😄. Sorry I certainly misunderstood your comment at the time.
This version changes the behavior slightly from mine: The serving thread (aka the one who call start() on the new Thread) will crash (raise an exception) because of an error raised from the new Thread.
I am not a huge fan of this change because it means that the serving thread might not recover from it (and I feel that errors from sub thread shouldn't impact the parent Thread). But I don't have a strong opinion about it 🤔
I will apply the comments of @bkap123 in my branch since they mainly target my code.
Have a nice day.
| self.assertFalse(thread.is_alive()) | ||
| self.assertFalse(thread in threading._limbo) | ||
| self.assertFalse(thread in threading._active) |
There was a problem hiding this comment.
These assertions aren't not run here, the RuntimeError is raised before.
You should de-indent these lines.
This PR is based on the @ryv-odoo PR. I would have preferred to start from @ryv-odoo's PR branch rather than duplicating his code, but I don't know if that's possible.
Following the @colesbury comment,
I submit this PR that includes the waiting in C the module and raise a runtime exception when the thread handle state is set to failed. This exception is treated in the
Thread.start.