-
-
Notifications
You must be signed in to change notification settings - Fork 33k
gh-139653: Add PyUnstable_ThreadState_SetStack() #139668
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
base: main
Are you sure you want to change the base?
Conversation
Add PyUnstable_ThreadState_SetStack() and PyUnstable_ThreadState_ResetStack() functions to set the stack base address and stack size of a Python thread state.
This generally matches what I came up with :) The start argument might be confusing, as the place usage grows towards. |
Good!
APIs like
|
.. versionadded:: next | ||
.. c:function:: void PyUnstable_ThreadState_ResetStack(PyThreadState *tstate) |
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.
I'm not sure of this name. Maybe PyUnstable_ThreadState_InitStack()
would be more explicit?
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.
Reset is better, "init" implies you should only call it once.
assert(ts->c_stack_soft_limit < ts->c_stack_top); | ||
|
||
// Test the stack pointer | ||
#if !defined(NDEBUG) && !defined(__wasi__) |
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.
These assertions fail on WASI but I don't have time right now to investigate why.
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.
Should it be possible to call PyUnstable_ThreadState_SetStack
just before a stack switch, when the stack pointer is still in the old stack?
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 long as you don't make any C-API calls between the two operations, the order in which you stack switch and call PyUnstable_ThreadState_SetStack
shouldn't matter.
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.
So, unless we specifically say that PyUnstable_ThreadState_SetStack()
should only be called after the stack switch, we'll need to remove these asserts.
On systems like musl that just set
Would it be better to save the results of the initial |
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.
The API looks good, but it can fail in a couple of ways.
assert(stack_size > 0); | ||
|
||
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate; | ||
ts->c_stack_hard_limit = (uintptr_t)stack_start_addr; |
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 incorrect. You need to leave _PyOS_STACK_MARGIN_BYTES
space.
Don't worry, everyone seems to get this wrong. If #139294 ever gets reviewed and merged, it should prevent that happening.
|
||
void | ||
_Py_InitializeRecursionLimits(PyThreadState *tstate) | ||
PyUnstable_ThreadState_ResetStack(PyThreadState *tstate) |
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 also won't work. We need to record the top of the stack when initially getting the stack limits, and use that instead of _Py_get_machine_stack_pointer()
otherwise, we could continually lower the stack limits, so that they become invalid.
When you're done making the requested changes, leave the comment: |
void *stack_start_addr, size_t stack_size) | ||
{ | ||
if (stack_size == 0) { | ||
PyErr_SetString(PyExc_ValueError, "stack_size must be greater than 0"); |
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.
Is this necessary? A stack size of zero is no less valid than a stack size of one. Anything less than 2 * _PyOS_STACK_MARGIN_BYTES + enough_stack_to_do_something_with
is useless, and enough_stack_to_do_something_with
is hard to define.
Add PyUnstable_ThreadState_SetStack() and
PyUnstable_ThreadState_ResetStack() functions to set the stack base address and stack size of a Python thread state.
📚 Documentation preview 📚: https://cpython-previews--139668.org.readthedocs.build/