| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -91,6 +91,10 @@ Fault handler state | |||
| 91 | 91 | The dump now mentions if a garbage collector collection is running | |
| 92 | 92 | if *all_threads* is true. | |
| 93 | 93 | ||
| 94 | + .. versionchanged:: next | ||
| 95 | + Only the current thread is dumped if the :term:`GIL` is disabled to | ||
| 96 | + prevent the risk of data races. | ||
| 97 | + | ||
| 94 | 98 | .. function:: disable() | |
| 95 | 99 | ||
| 96 | 100 | Disable the fault handler: uninstall the signal handlers installed by | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -100,7 +100,12 @@ def check_error(self, code, lineno, fatal_error, *, | |||
| 100 | 100 | ||
| 101 | 101 | Raise an error if the output doesn't match the expected format. | |
| 102 | 102 | """ | |
| 103 | - if all_threads: | ||
| 103 | + all_threads_disabled = ( | ||
| 104 | + (not py_fatal_error) | ||
| 105 | + and all_threads | ||
| 106 | + and (not sys._is_gil_enabled()) | ||
| 107 | + ) | ||
| 108 | + if all_threads and not all_threads_disabled: | ||
| 104 | 109 | if know_current_thread: | |
| 105 | 110 | header = 'Current thread 0x[0-9a-f]+' | |
| 106 | 111 | else: | |
@@ -111,8 +116,10 @@ def check_error(self, code, lineno, fatal_error, *, | |||
| 111 | 116 | if py_fatal_error: | |
| 112 | 117 | regex.append("Python runtime state: initialized") | |
| 113 | 118 | regex.append('') | |
| 119 | + if all_threads_disabled: | ||
| 120 | + regex.append("<Cannot show all threads while the GIL is disabled>") | ||
| 114 | 121 | regex.append(fr'{header} \(most recent call first\):') | |
| 115 | - if garbage_collecting: | ||
| 122 | + if garbage_collecting and not all_threads_disabled: | ||
| 116 | 123 | regex.append(' Garbage-collecting') | |
| 117 | 124 | regex.append(fr' File "<string>", line {lineno} in {function}') | |
| 118 | 125 | regex = '\n'.join(regex) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + Only show the current thread in :mod:`faulthandler` on the :term:`free | ||
| 2 | + threaded <free threading>` build to prevent races. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,5 @@ | |||
| 1 | 1 | #include "Python.h" | |
| 2 | + #include "pycore_ceval.h" // _PyEval_IsGILEnabled | ||
| 2 | 3 | #include "pycore_initconfig.h" // _PyStatus_ERR | |
| 3 | 4 | #include "pycore_pyerrors.h" // _Py_DumpExtensionModules | |
| 4 | 5 | #include "pycore_pystate.h" // _PyThreadState_GET() | |
@@ -27,6 +28,8 @@ | |||
| 27 | 28 | # include <sys/auxv.h> // getauxval() | |
| 28 | 29 | #endif | |
| 29 | 30 | ||
| 31 | + /* Sentinel to ignore all_threads on free-threading */ | ||
| 32 | + #define FT_IGNORE_ALL_THREADS 2 | ||
| 30 | 33 | ||
| 31 | 34 | /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ | |
| 32 | 35 | #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024) | |
@@ -201,10 +204,13 @@ faulthandler_dump_traceback(int fd, int all_threads, | |||
| 201 | 204 | PyGILState_GetThisThreadState(). */ | |
| 202 | 205 | PyThreadState *tstate = PyGILState_GetThisThreadState(); | |
| 203 | 206 | ||
| 204 | - if (all_threads) { | ||
| 207 | + if (all_threads == 1) { | ||
| 205 | 208 | (void)_Py_DumpTracebackThreads(fd, NULL, tstate); | |
| 206 | 209 | } | |
| 207 | 210 | else { | |
| 211 | + if (all_threads == FT_IGNORE_ALL_THREADS) { | ||
| 212 | + PUTS(fd, "<Cannot show all threads while the GIL is disabled>\n"); | ||
| 213 | + } | ||
| 208 | 214 | if (tstate != NULL) | |
| 209 | 215 | _Py_DumpTraceback(fd, tstate); | |
| 210 | 216 | } | |
@@ -271,6 +277,27 @@ faulthandler_disable_fatal_handler(fault_handler_t *handler) | |||
| 271 | 277 | #endif | |
| 272 | 278 | } | |
| 273 | 279 | ||
| 280 | + static int | ||
| 281 | + deduce_all_threads(void) | ||
| 282 | + { | ||
| 283 | + #ifndef Py_GIL_DISABLED | ||
| 284 | + return fatal_error.all_threads; | ||
| 285 | + #else | ||
| 286 | + if (fatal_error.all_threads == 0) { | ||
| 287 | + return 0; | ||
| 288 | + } | ||
| 289 | + // We can't use _PyThreadState_GET, so use the stored GILstate one | ||
| 290 | + PyThreadState *tstate = PyGILState_GetThisThreadState(); | ||
| 291 | + if (tstate == NULL) { | ||
| 292 | + return 0; | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + /* In theory, it's safe to dump all threads if the GIL is enabled */ | ||
| 296 | + return _PyEval_IsGILEnabled(tstate) | ||
| 297 | + ? fatal_error.all_threads | ||
| 298 | + : FT_IGNORE_ALL_THREADS; | ||
| 299 | + #endif | ||
| 300 | + } | ||
| 274 | 301 | ||
| 275 | 302 | /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals. | |
| 276 | 303 | ||
@@ -325,7 +352,7 @@ faulthandler_fatal_error(int signum) | |||
| 325 | 352 | PUTS(fd, "\n\n"); | |
| 326 | 353 | } | |
| 327 | 354 | ||
| 328 | - faulthandler_dump_traceback(fd, fatal_error.all_threads, | ||
| 355 | + faulthandler_dump_traceback(fd, deduce_all_threads(), | ||
| 329 | 356 | fatal_error.interp); | |
| 330 | 357 | ||
| 331 | 358 | _Py_DumpExtensionModules(fd, fatal_error.interp); | |
@@ -401,7 +428,7 @@ faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info) | |||
| 401 | 428 | } | |
| 402 | 429 | } | |
| 403 | 430 | ||
| 404 | - faulthandler_dump_traceback(fd, fatal_error.all_threads, | ||
| 431 | + faulthandler_dump_traceback(fd, deduce_all_threads(), | ||
| 405 | 432 | fatal_error.interp); | |
| 406 | 433 | ||
| 407 | 434 | /* call the next exception handler */ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments