Skip to content

Commit 997bb05

Browse files
committed
Fix PyUnstable_ThreadState_ResetStack()
Add c_stack_init_start and c_stack_init_size to _PyThreadStateImpl to cache PyUnstable_ThreadState_ResetStack() values. Set these members at the first call, and then reuse these values.
1 parent 404f291 commit 997bb05

File tree

4 files changed

+46
-14
lines changed

4 files changed

+46
-14
lines changed

Include/internal/pycore_tstate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ typedef struct _PyThreadStateImpl {
3737
uintptr_t c_stack_soft_limit;
3838
uintptr_t c_stack_hard_limit;
3939

40+
// PyUnstable_ThreadState_ResetStack() values
41+
uintptr_t c_stack_init_start;
42+
size_t c_stack_init_size;
43+
4044
PyObject *asyncio_running_loop; // Strong reference
4145
PyObject *asyncio_running_task; // Strong reference
4246

Modules/_testinternalcapi.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2436,8 +2436,12 @@ static PyObject *
24362436
test_threadstate_set_stack(PyObject *self, PyObject *Py_UNUSED(args))
24372437
{
24382438
PyThreadState *tstate = PyThreadState_GET();
2439+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
24392440
assert(!PyErr_Occurred());
24402441

2442+
uintptr_t init_start = ts->c_stack_init_start;
2443+
size_t init_size = ts->c_stack_init_size;
2444+
24412445
// Test the minimum stack size
24422446
size_t size = _PyOS_STACK_MARGIN_BYTES * 3;
24432447
void *start = (void*)(_Py_get_machine_stack_pointer() - size);
@@ -2455,7 +2459,11 @@ test_threadstate_set_stack(PyObject *self, PyObject *Py_UNUSED(args))
24552459
assert(PyErr_ExceptionMatches(PyExc_ValueError));
24562460
PyErr_Clear();
24572461

2462+
// Test PyUnstable_ThreadState_ResetStack()
24582463
PyUnstable_ThreadState_ResetStack(tstate);
2464+
assert(ts->c_stack_init_start == init_start);
2465+
assert(ts->c_stack_init_size == init_size);
2466+
24592467
Py_RETURN_NONE;
24602468
}
24612469

Python/ceval.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,9 @@ PyUnstable_ThreadState_SetStack(PyThreadState *tstate,
489489
}
490490

491491

492-
void
493-
PyUnstable_ThreadState_ResetStack(PyThreadState *tstate)
492+
// Get the stack start address and stack size (in bytes)
493+
static void
494+
get_stack(uintptr_t *start, size_t *size)
494495
{
495496
#ifdef WIN32
496497
ULONG_PTR low, high;
@@ -499,15 +500,14 @@ PyUnstable_ThreadState_ResetStack(PyThreadState *tstate)
499500
ULONG guarantee = 0;
500501
SetThreadStackGuarantee(&guarantee);
501502

502-
uintptr_t start = (uintptr_t)low + guarantee;
503-
size_t size = (uintptr_t)high - start;
504-
tstate_set_stack(tstate, (void*)start, size);
503+
*start = (uintptr_t)low + guarantee;
504+
*size = (uintptr_t)high - start;
505505

506506
#elif defined(__APPLE__)
507507
pthread_t this_thread = pthread_self();
508508
void *top = pthread_get_stackaddr_np(this_thread); // top of the stack
509-
size_t size = pthread_get_stacksize_np(this_thread);
510-
tstate_set_stack(tstate, (char*)top - size, size);
509+
*size = pthread_get_stacksize_np(this_thread);
510+
*start = (uintptr_t)top - *size;
511511

512512
#else
513513
// XXX musl supports HAVE_PTHRED_GETATTR_NP, but the resulting stack size
@@ -525,23 +525,40 @@ PyUnstable_ThreadState_ResetStack(PyThreadState *tstate)
525525
err |= pthread_attr_destroy(&attr);
526526
}
527527
if (err == 0) {
528-
uintptr_t base = ((uintptr_t)stack_addr) + guard_size;
529-
uintptr_t start = base;
530-
size_t pystack_size = (base + stack_size) - start;
531-
tstate_set_stack(tstate, (void*)start, pystack_size);
528+
uintptr_t base = (uintptr_t)stack_addr + guard_size;
529+
*start = base;
530+
*size = (base + stack_size) - *start;
532531
}
533532
else
534533
# endif
535534
{
536535
uintptr_t here_addr = _Py_get_machine_stack_pointer();
537536
uintptr_t top = _Py_SIZE_ROUND_UP(here_addr, 4096);
538-
uintptr_t start = top - Py_C_STACK_SIZE;
539-
size_t pystack_size = top - start;
540-
tstate_set_stack(tstate, (void*)start, pystack_size);
537+
*size = Py_C_STACK_SIZE;
538+
*start = top - *size;
541539
}
542540
#endif
543541
}
544542

543+
void
544+
PyUnstable_ThreadState_ResetStack(PyThreadState *tstate)
545+
{
546+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)tstate;
547+
if (ts->c_stack_init_start != 0) {
548+
tstate_set_stack(tstate,
549+
(void*)ts->c_stack_init_start,
550+
ts->c_stack_init_size);
551+
return;
552+
}
553+
554+
uintptr_t start;
555+
size_t size;
556+
get_stack(&start, &size);
557+
tstate_set_stack(tstate, (void*)start, size);
558+
ts->c_stack_init_start = start;
559+
ts->c_stack_init_size = size;
560+
}
561+
545562

546563
/* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall()
547564
if the recursion_depth reaches recursion_limit. */

Python/pystate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,9 @@ init_threadstate(_PyThreadStateImpl *_tstate,
14901490
_tstate->c_stack_top = 0;
14911491
_tstate->c_stack_hard_limit = 0;
14921492

1493+
_tstate->c_stack_init_start = 0;
1494+
_tstate->c_stack_init_size = 0;
1495+
14931496
_tstate->asyncio_running_loop = NULL;
14941497
_tstate->asyncio_running_task = NULL;
14951498

0 commit comments

Comments
 (0)