Skip to content
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

Thread state handling improvements aka bug and crash fixes when using Tohil/Python from multiple Tcl interpreters #70

Merged
merged 11 commits into from
Nov 17, 2021

Conversation

lehenbauer
Copy link
Collaborator

For every function of the tohil Tcl-side that does something with Python such as exec'ing, eval'ing, importing, call'ing, or invoking a Tcl/Python callback, don't just switch to the threadstate for that tcl interpreter's corresponding Python interpreter, but also keep track of what the threadstate is when those functions are first called, and switch it back right before they return.

To do this we

  • made tohil_setup_subinterp return the prior python thread state.
  • extended the calls to tohil_setup_subinterp in Tohil_Init to keep the prior thread state and, prior to returning, to restore it.
  • added a PyThreadState parameter to each ot tohil_tcl_return, Tohil_ReturnTclError, Tohil_ReturnStartupExceptionToTcl, and Tohil_ReturnExceptionToTcl and code for them to either pass along or restore the threadstate at the right moment after all manipulation of the relevant Python subinterpreter that was being used is complete.
  • fixed a bug where we were storing a pointer to the Tcl interpreter in our tclobj and tcldict datatypes. We changed it to use the same safe method to find the current Tcl interpreter that we use elsewhere, simplifying the code.

for every function of the tohil Tcl-side that does something with python
such as exec'ing, eval'ing, importing, call'ing, don't just switch to
the threadstate for the tcl interpreter's corresponding python
interpreter but also keep track of it and switch it back afterwards.
* make tohil_setup_subinterp return the prior python thread state
* extend calls to tohil_setup_subinterp in Tohil_Init to keep the prior
  thread state and prior to returning to restore it.
Thanks to @NasaGeek for identifying this problem, which is setting a
static value in two data types that are used by multiple python
subinterpreters.  We simplify by getting rid of that and finding the tcl
interpreter the same way we do elsehwere when we need it and have been
given no direct handle to it.
we were still restoring the thread state too early in a lot of cases.  rather than calling the return function but not returning it, grabbing the return, then restoring the thread state, then returning the return value of the return function, we add a PyThreadState parameter to each ot tohil_tcl_return, Tohil_ReturnTclError, Tohil_ReturnStartupExceptionToTcl, and Tohil_ReturnExceptionToTcl, and in all the functions that make use of those we grab the prior thread state when we swap the thread state to the python subinterpreter associated with the tcl interpreter and pass that value back to the aforementioned functions.
Copy link
Member

@resuna resuna left a comment

Choose a reason for hiding this comment

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

Looks good, except I may be confused by Tohil_ReturnExceptionToTcl but it does look like it may have a path that fails to restore state.

generic/tohil.c Outdated Show resolved Hide resolved
generic/tohil.c Show resolved Hide resolved
Copy link
Member

@NasaGeek NasaGeek left a comment

Choose a reason for hiding this comment

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

This is going to make my subinterpreter dreams come true!

generic/tohil.c Show resolved Hide resolved
generic/tohil.c Outdated Show resolved Hide resolved
generic/tohil.c Show resolved Hide resolved
@lehenbauer
Copy link
Collaborator Author

Looks good, except I may be confused by Tohil_ReturnExceptionToTcl but it does look like it may have a path that fails to restore state.

Good catch! The fall-through path did not restore the subinterpreter. It now does.

@lehenbauer lehenbauer closed this Nov 17, 2021
@lehenbauer lehenbauer reopened this Nov 17, 2021
@lehenbauer
Copy link
Collaborator Author

oops i didn't mean to close the PR

Added a note to the comment for this function about returning the thread state and the non-obvious implicit thread-state-swap that Py_NewInterpreter() performs.  Hat tip to @NasaGeek.
Copy link
Member

@resuna resuna left a comment

Choose a reason for hiding this comment

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

Looks good.

@lehenbauer lehenbauer merged commit 0bcf951 into main Nov 17, 2021
@lehenbauer lehenbauer deleted the last-moment-restore-threadstate branch November 17, 2021 21:37
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.

3 participants