| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
…ck() Add a keyword-only `max_threads` argument to `dump_traceback()` and `dump_traceback_later()`, defaulting to 100 to preserve existing behavior. Allows server processes with many worker threads to dump beyond the historical 100-thread cap (previously a hardcoded `MAX_NTHREADS = 100` in `Python/traceback.c`). The cap matters in practice: tstates are prepended to the PyInterpreterState linked list, so the dump walks newest-first. With more than 100 threads alive, the main thread (oldest, at the tail) is silently elided from watchdog dumps -- exactly the thread that's usually wanted. The hardcoded value is moved to a new internal macro `_Py_TRACEBACK_MAX_NTHREADS` in `pycore_traceback.h` so the in-tree fatal-signal callers all reference one source of truth.
Documentation build overview6 files changed · ± 6 modified ± Modified |
Sorry, something went wrong.
There was a problem hiding this comment.
I would prefer to also add max_threads parameter to enable().
Sorry, something went wrong.
- Drop _Py_TRACEBACK_MAX_NTHREADS macro; use 0 as sentinel for default 100 inside _Py_DumpTracebackThreads so internal callers don't have to pass the default explicitly. - Rename max_nthreads -> max_threads everywhere for naming consistency with the public Python kwarg. - Add max_threads kwarg to faulthandler.enable(); store in fatal_error.max_threads and pass through faulthandler_dump_traceback to the fatal-signal dump path on both POSIX and Windows. - Drop the three redundant explanatory comments vstinner flagged. - Doc: tighten the limitations bullet, drop implementation-detail mentions of the "..." truncation marker, switch versionchanged directives to "next", document the new enable() kwarg. - Tests: assertEqual exact count, check whole-line "\n...\n" marker, use script_helper.assert_python_ok, drop the default-value test, add test_enable_max_threads exercising the fatal-signal path. - NEWS: trim to two lines, mention all three functions.
|
Thanks for the feedback. |
Sorry, something went wrong.
The fatal-signal handler only dumps the current thread when the GIL is disabled (pythongh-104812 / 3.14 versionchanged), so the truncation marker assertion in test_enable_max_threads fails on free-threading CI runs. Skip it there.
There was a problem hiding this comment.
Can you replace unsigned int max_threads with Py_ssize_t max_threads? Replace also unsigned int nthreads with Py_ssize_t nthreads in _Py_DumpTracebackThreads().
Sorry, something went wrong.
| return; | ||
|
|
||
| faulthandler_dump_traceback(user->fd, user->all_threads, user->interp); | ||
| faulthandler_dump_traceback(user->fd, user->all_threads, user->interp, 0); |
There was a problem hiding this comment.
Please modify faulthandler.register() to add a max_threads parameter.
Sorry, something went wrong.
Thanks for this big update! |
Sorry, something went wrong.
There was a problem hiding this comment.
Please also add an entry to "What's New in Python 3.15".
Sorry, something went wrong.
- Add a 'faulthandler' entry to Doc/whatsnew/3.15.rst (per @ZeroIntensity). - Switch the max_threads parameters/fields and the nthreads loop counter in _Py_DumpTracebackThreads to Py_ssize_t (per @vstinner).
|
Ok I added the whats-new entry and switched the max_size args to Py_ssize_t. 👍 |
Sorry, something went wrong.
|
Can you also modify faulthandler.register() to add a max_threads parameter? |
Sorry, something went wrong.
Per @vstinner's follow-up: also wire the kwarg through register() / faulthandler_user. Stored in the per-signal user_signal_t struct; the user-signal handler now passes user->max_threads to faulthandler_dump_traceback instead of 0. Doc, whatsnew, and NEWS entries updated to list all four functions.
Mirrors test_enable_max_threads but uses register(SIGUSR1, ...) + os.kill round-trip, matching the existing test_register_* pattern.
|
Ok faulthandler.register() now has max_threads too. (and added an associated test). Holler if anything looks off there. |
Sorry, something went wrong.
| ready.wait() | ||
| faulthandler.register(signal.SIGUSR1, all_threads=True, | ||
| max_threads=CAP) | ||
| os.kill(os.getpid(), signal.SIGUSR1) |
There was a problem hiding this comment.
To raise the signal, you can use:
| os.kill(os.getpid(), signal.SIGUSR1) | |
| signal.raise_signal(signal.SIGUSR1) |
Can you use test_dump_traceback_max_threads() code to cleanup threads?
Sorry, something went wrong.
- Use signal.raise_signal() instead of os.kill(os.getpid(), ...). - Match test_dump_traceback_max_threads thread-cleanup pattern: keep refs, no daemon=True, set the stop event in a finally block, and join() the workers.
|
Ok; switched to raise_signal() and now doing test_dump_traceback_max_threads() style cleanup |
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM.
Sorry, something went wrong.
|
@ZeroIntensity: Do you want to double check the change? It would be good to merge this change before next Tuesday to have it in Python 3.15 beta1. |
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM as well.
Sorry, something went wrong.
|
Thanks for contributing :) |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Closes #149085.
Adds a keyword-only max_threads argument to faulthandler.dump_traceback() and faulthandler.dump_traceback_later(), raising the per-call cap on the number of threads dumped (previously a hardcoded MAX_NTHREADS = 100 in Python/traceback.c). Default of 100 preserves existing behavior.
Motivation (covered in the issue): on server processes with many worker or gRPC threads, watchdog dumps silently lose the main thread because tstates are prepended to the interpreter's thread list and the cap chops the tail. This was the failure mode that prompted the issue.
Scope per @vstinner's confirmation in the issue: max_threads only; the frame/stack limits raised by @ZeroIntensity are left as-is for now.
The hardcoded 100 is moved to a new internal macro _Py_TRACEBACK_MAX_NTHREADS in pycore_traceback.h so the in-tree fatal-signal callers (faulthandler.c, pylifecycle.c) all share one source of truth.
📚 Documentation preview 📚: https://cpython-previews--149106.org.readthedocs.build/