]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-137725: Convert faulthandler to Argument Clinic (#137726)
authorVictor Stinner <vstinner@python.org>
Sat, 16 Aug 2025 13:16:04 +0000 (15:16 +0200)
committerGitHub <noreply@github.com>
Sat, 16 Aug 2025 13:16:04 +0000 (15:16 +0200)
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Lib/test/test_faulthandler.py
Modules/clinic/faulthandler.c.h [new file with mode: 0644]
Modules/faulthandler.c

index 6c8ce475c698428bd136905b5f986c8c8eda1419..27102588076cc2838e0acc24af7f8f114ec5e740 100644 (file)
@@ -836,6 +836,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_exception));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_parameter_type));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_stack));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_datetime_module));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata));
@@ -850,6 +851,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(category));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cb_type));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(certfile));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(chain));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(check_same_thread));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clear));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(close));
@@ -944,6 +946,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(excepthook));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exception));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(existing_file_name));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exit));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exp));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(expression));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extend));
@@ -1204,6 +1207,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(release));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repeat));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reqrefs));
@@ -1242,6 +1246,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shared));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(show_cmd));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signed));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signum));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(size));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sizehint));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(skip_file_prefixes));
index 55e48214728153931889e599e410d866b4faf4d8..2d6130c216993f49dbc9a666f95ae447898d1a01 100644 (file)
@@ -327,6 +327,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(c_exception)
         STRUCT_FOR_ID(c_parameter_type)
         STRUCT_FOR_ID(c_return)
+        STRUCT_FOR_ID(c_stack)
         STRUCT_FOR_ID(cached_datetime_module)
         STRUCT_FOR_ID(cached_statements)
         STRUCT_FOR_ID(cadata)
@@ -341,6 +342,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(category)
         STRUCT_FOR_ID(cb_type)
         STRUCT_FOR_ID(certfile)
+        STRUCT_FOR_ID(chain)
         STRUCT_FOR_ID(check_same_thread)
         STRUCT_FOR_ID(clear)
         STRUCT_FOR_ID(close)
@@ -435,6 +437,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(excepthook)
         STRUCT_FOR_ID(exception)
         STRUCT_FOR_ID(existing_file_name)
+        STRUCT_FOR_ID(exit)
         STRUCT_FOR_ID(exp)
         STRUCT_FOR_ID(expression)
         STRUCT_FOR_ID(extend)
@@ -695,6 +698,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(rel_tol)
         STRUCT_FOR_ID(release)
         STRUCT_FOR_ID(reload)
+        STRUCT_FOR_ID(repeat)
         STRUCT_FOR_ID(repl)
         STRUCT_FOR_ID(replace)
         STRUCT_FOR_ID(reqrefs)
@@ -733,6 +737,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(shared)
         STRUCT_FOR_ID(show_cmd)
         STRUCT_FOR_ID(signed)
+        STRUCT_FOR_ID(signum)
         STRUCT_FOR_ID(size)
         STRUCT_FOR_ID(sizehint)
         STRUCT_FOR_ID(skip_file_prefixes)
index ea188d4f2bf8edfb5a6920901cdc5f730c182a51..9e72c7df77b945f97b632a4258fe70c29e1124dd 100644 (file)
@@ -834,6 +834,7 @@ extern "C" {
     INIT_ID(c_exception), \
     INIT_ID(c_parameter_type), \
     INIT_ID(c_return), \
+    INIT_ID(c_stack), \
     INIT_ID(cached_datetime_module), \
     INIT_ID(cached_statements), \
     INIT_ID(cadata), \
@@ -848,6 +849,7 @@ extern "C" {
     INIT_ID(category), \
     INIT_ID(cb_type), \
     INIT_ID(certfile), \
+    INIT_ID(chain), \
     INIT_ID(check_same_thread), \
     INIT_ID(clear), \
     INIT_ID(close), \
@@ -942,6 +944,7 @@ extern "C" {
     INIT_ID(excepthook), \
     INIT_ID(exception), \
     INIT_ID(existing_file_name), \
+    INIT_ID(exit), \
     INIT_ID(exp), \
     INIT_ID(expression), \
     INIT_ID(extend), \
@@ -1202,6 +1205,7 @@ extern "C" {
     INIT_ID(rel_tol), \
     INIT_ID(release), \
     INIT_ID(reload), \
+    INIT_ID(repeat), \
     INIT_ID(repl), \
     INIT_ID(replace), \
     INIT_ID(reqrefs), \
@@ -1240,6 +1244,7 @@ extern "C" {
     INIT_ID(shared), \
     INIT_ID(show_cmd), \
     INIT_ID(signed), \
+    INIT_ID(signum), \
     INIT_ID(size), \
     INIT_ID(sizehint), \
     INIT_ID(skip_file_prefixes), \
index 044fdafef246edc1a13e8798f7cf316b74bcc0c4..02c62f68ff08017178cf7d876e29416b5a3df076 100644 (file)
@@ -1096,6 +1096,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(c_stack);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(cached_datetime_module);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -1152,6 +1156,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(chain);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(check_same_thread);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -1528,6 +1536,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(exit);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(exp);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -2568,6 +2580,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(repeat);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(repl);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
@@ -2720,6 +2736,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(signum);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(size);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
index 2fb963f52e513887b7c0d44a2ccd294760cb9b94..874f52af857b94761ca43c0904ff22f44d5ea4cd 100644 (file)
@@ -360,6 +360,17 @@ class FaultHandlerTests(unittest.TestCase):
             'Segmentation fault',
             all_threads=False)
 
+    @skip_segfault_on_android
+    def test_enable_without_c_stack(self):
+        self.check_fatal_error("""
+            import faulthandler
+            faulthandler.enable(c_stack=False)
+            faulthandler._sigsegv()
+            """,
+            3,
+            'Segmentation fault',
+            c_stack=False)
+
     @skip_segfault_on_android
     def test_disable(self):
         code = """
diff --git a/Modules/clinic/faulthandler.c.h b/Modules/clinic/faulthandler.c.h
new file mode 100644 (file)
index 0000000..de8280c
--- /dev/null
@@ -0,0 +1,688 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+#  include "pycore_gc.h"          // PyGC_Head
+#  include "pycore_runtime.h"     // _Py_ID()
+#endif
+#include "pycore_long.h"          // _PyLong_UnsignedInt_Converter()
+#include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
+
+PyDoc_STRVAR(faulthandler_dump_traceback_py__doc__,
+"dump_traceback($module, /, file=sys.stderr, all_threads=True)\n"
+"--\n"
+"\n"
+"Dump the traceback of the current thread into file.\n"
+"\n"
+"Dump the traceback of all threads if all_threads is true.");
+
+#define FAULTHANDLER_DUMP_TRACEBACK_PY_METHODDEF    \
+    {"dump_traceback", _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_traceback_py__doc__},
+
+static PyObject *
+faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file,
+                                    int all_threads);
+
+static PyObject *
+faulthandler_dump_traceback_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 2
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(file), &_Py_ID(all_threads), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"file", "all_threads", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "dump_traceback",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[2];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
+    PyObject *file = NULL;
+    int all_threads = 1;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[0]) {
+        file = args[0];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    all_threads = PyObject_IsTrue(args[1]);
+    if (all_threads < 0) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = faulthandler_dump_traceback_py_impl(module, file, all_threads);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler_dump_c_stack_py__doc__,
+"dump_c_stack($module, /, file=sys.stderr)\n"
+"--\n"
+"\n"
+"Dump the C stack of the current thread.");
+
+#define FAULTHANDLER_DUMP_C_STACK_PY_METHODDEF    \
+    {"dump_c_stack", _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_c_stack_py__doc__},
+
+static PyObject *
+faulthandler_dump_c_stack_py_impl(PyObject *module, PyObject *file);
+
+static PyObject *
+faulthandler_dump_c_stack_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 1
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(file), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"file", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "dump_c_stack",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[1];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
+    PyObject *file = NULL;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    file = args[0];
+skip_optional_pos:
+    return_value = faulthandler_dump_c_stack_py_impl(module, file);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler_py_enable__doc__,
+"enable($module, /, file=sys.stderr, all_threads=True, c_stack=True)\n"
+"--\n"
+"\n"
+"Enable the fault handler.");
+
+#define FAULTHANDLER_PY_ENABLE_METHODDEF    \
+    {"enable", _PyCFunction_CAST(faulthandler_py_enable), METH_FASTCALL|METH_KEYWORDS, faulthandler_py_enable__doc__},
+
+static PyObject *
+faulthandler_py_enable_impl(PyObject *module, PyObject *file,
+                            int all_threads, int c_stack);
+
+static PyObject *
+faulthandler_py_enable(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 3
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(file), &_Py_ID(all_threads), &_Py_ID(c_stack), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"file", "all_threads", "c_stack", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "enable",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[3];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
+    PyObject *file = NULL;
+    int all_threads = 1;
+    int c_stack = 1;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 0, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[0]) {
+        file = args[0];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    if (args[1]) {
+        all_threads = PyObject_IsTrue(args[1]);
+        if (all_threads < 0) {
+            goto exit;
+        }
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    c_stack = PyObject_IsTrue(args[2]);
+    if (c_stack < 0) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = faulthandler_py_enable_impl(module, file, all_threads, c_stack);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler_disable_py__doc__,
+"disable($module, /)\n"
+"--\n"
+"\n"
+"Disable the fault handler.");
+
+#define FAULTHANDLER_DISABLE_PY_METHODDEF    \
+    {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS, faulthandler_disable_py__doc__},
+
+static PyObject *
+faulthandler_disable_py_impl(PyObject *module);
+
+static PyObject *
+faulthandler_disable_py(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler_disable_py_impl(module);
+}
+
+PyDoc_STRVAR(faulthandler_is_enabled__doc__,
+"is_enabled($module, /)\n"
+"--\n"
+"\n"
+"Check if the handler is enabled.");
+
+#define FAULTHANDLER_IS_ENABLED_METHODDEF    \
+    {"is_enabled", (PyCFunction)faulthandler_is_enabled, METH_NOARGS, faulthandler_is_enabled__doc__},
+
+static int
+faulthandler_is_enabled_impl(PyObject *module);
+
+static PyObject *
+faulthandler_is_enabled(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *return_value = NULL;
+    int _return_value;
+
+    _return_value = faulthandler_is_enabled_impl(module);
+    if ((_return_value == -1) && PyErr_Occurred()) {
+        goto exit;
+    }
+    return_value = PyBool_FromLong((long)_return_value);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler_dump_traceback_later__doc__,
+"dump_traceback_later($module, /, timeout, repeat=False,\n"
+"                     file=sys.stderr, exit=False)\n"
+"--\n"
+"\n"
+"Dump the traceback of all threads in timeout seconds.\n"
+"\n"
+"If repeat is true, the tracebacks of all threads are dumped every timeout\n"
+"seconds. If exit is true, call _exit(1) which is not safe.");
+
+#define FAULTHANDLER_DUMP_TRACEBACK_LATER_METHODDEF    \
+    {"dump_traceback_later", _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_traceback_later__doc__},
+
+static PyObject *
+faulthandler_dump_traceback_later_impl(PyObject *module,
+                                       PyObject *timeout_obj, int repeat,
+                                       PyObject *file, int exit);
+
+static PyObject *
+faulthandler_dump_traceback_later(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 4
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(timeout), &_Py_ID(repeat), &_Py_ID(file), &_Py_ID(exit), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"timeout", "repeat", "file", "exit", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "dump_traceback_later",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[4];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+    PyObject *timeout_obj;
+    int repeat = 0;
+    PyObject *file = NULL;
+    int exit = 0;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 1, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    timeout_obj = args[0];
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[1]) {
+        repeat = PyObject_IsTrue(args[1]);
+        if (repeat < 0) {
+            goto exit;
+        }
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    if (args[2]) {
+        file = args[2];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    exit = PyObject_IsTrue(args[3]);
+    if (exit < 0) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = faulthandler_dump_traceback_later_impl(module, timeout_obj, repeat, file, exit);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler_cancel_dump_traceback_later_py__doc__,
+"cancel_dump_traceback_later($module, /)\n"
+"--\n"
+"\n"
+"Cancel the previous call to dump_traceback_later().");
+
+#define FAULTHANDLER_CANCEL_DUMP_TRACEBACK_LATER_PY_METHODDEF    \
+    {"cancel_dump_traceback_later", (PyCFunction)faulthandler_cancel_dump_traceback_later_py, METH_NOARGS, faulthandler_cancel_dump_traceback_later_py__doc__},
+
+static PyObject *
+faulthandler_cancel_dump_traceback_later_py_impl(PyObject *module);
+
+static PyObject *
+faulthandler_cancel_dump_traceback_later_py(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler_cancel_dump_traceback_later_py_impl(module);
+}
+
+#if defined(FAULTHANDLER_USER)
+
+PyDoc_STRVAR(faulthandler_register_py__doc__,
+"register($module, /, signum, file=sys.stderr, all_threads=True,\n"
+"         chain=False)\n"
+"--\n"
+"\n"
+"Register a handler for the signal \'signum\'.\n"
+"\n"
+"Dump the traceback of the current thread, or of all threads if\n"
+"all_threads is True, into file.");
+
+#define FAULTHANDLER_REGISTER_PY_METHODDEF    \
+    {"register", _PyCFunction_CAST(faulthandler_register_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_register_py__doc__},
+
+static PyObject *
+faulthandler_register_py_impl(PyObject *module, int signum, PyObject *file,
+                              int all_threads, int chain);
+
+static PyObject *
+faulthandler_register_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 4
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(signum), &_Py_ID(file), &_Py_ID(all_threads), &_Py_ID(chain), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"signum", "file", "all_threads", "chain", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "register",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[4];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
+    int signum;
+    PyObject *file = NULL;
+    int all_threads = 1;
+    int chain = 0;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 1, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    signum = PyLong_AsInt(args[0]);
+    if (signum == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    if (args[1]) {
+        file = args[1];
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    if (args[2]) {
+        all_threads = PyObject_IsTrue(args[2]);
+        if (all_threads < 0) {
+            goto exit;
+        }
+        if (!--noptargs) {
+            goto skip_optional_pos;
+        }
+    }
+    chain = PyObject_IsTrue(args[3]);
+    if (chain < 0) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = faulthandler_register_py_impl(module, signum, file, all_threads, chain);
+
+exit:
+    return return_value;
+}
+
+#endif /* defined(FAULTHANDLER_USER) */
+
+#if defined(FAULTHANDLER_USER)
+
+PyDoc_STRVAR(faulthandler_unregister_py__doc__,
+"unregister($module, signum, /)\n"
+"--\n"
+"\n"
+"Unregister the handler of the signal \'signum\' registered by register().");
+
+#define FAULTHANDLER_UNREGISTER_PY_METHODDEF    \
+    {"unregister", (PyCFunction)faulthandler_unregister_py, METH_O, faulthandler_unregister_py__doc__},
+
+static PyObject *
+faulthandler_unregister_py_impl(PyObject *module, int signum);
+
+static PyObject *
+faulthandler_unregister_py(PyObject *module, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    int signum;
+
+    signum = PyLong_AsInt(arg);
+    if (signum == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+    return_value = faulthandler_unregister_py_impl(module, signum);
+
+exit:
+    return return_value;
+}
+
+#endif /* defined(FAULTHANDLER_USER) */
+
+PyDoc_STRVAR(faulthandler__sigsegv__doc__,
+"_sigsegv($module, release_gil=False, /)\n"
+"--\n"
+"\n"
+"Raise a SIGSEGV signal.");
+
+#define FAULTHANDLER__SIGSEGV_METHODDEF    \
+    {"_sigsegv", _PyCFunction_CAST(faulthandler__sigsegv), METH_FASTCALL, faulthandler__sigsegv__doc__},
+
+static PyObject *
+faulthandler__sigsegv_impl(PyObject *module, int release_gil);
+
+static PyObject *
+faulthandler__sigsegv(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    int release_gil = 0;
+
+    if (!_PyArg_CheckPositional("_sigsegv", nargs, 0, 1)) {
+        goto exit;
+    }
+    if (nargs < 1) {
+        goto skip_optional;
+    }
+    release_gil = PyObject_IsTrue(args[0]);
+    if (release_gil < 0) {
+        goto exit;
+    }
+skip_optional:
+    return_value = faulthandler__sigsegv_impl(module, release_gil);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(faulthandler__fatal_error_c_thread__doc__,
+"_fatal_error_c_thread($module, /)\n"
+"--\n"
+"\n"
+"Call Py_FatalError() in a new C thread.");
+
+#define FAULTHANDLER__FATAL_ERROR_C_THREAD_METHODDEF    \
+    {"_fatal_error_c_thread", (PyCFunction)faulthandler__fatal_error_c_thread, METH_NOARGS, faulthandler__fatal_error_c_thread__doc__},
+
+static PyObject *
+faulthandler__fatal_error_c_thread_impl(PyObject *module);
+
+static PyObject *
+faulthandler__fatal_error_c_thread(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler__fatal_error_c_thread_impl(module);
+}
+
+PyDoc_STRVAR(faulthandler__sigfpe__doc__,
+"_sigfpe($module, /)\n"
+"--\n"
+"\n"
+"Raise a SIGFPE signal.");
+
+#define FAULTHANDLER__SIGFPE_METHODDEF    \
+    {"_sigfpe", (PyCFunction)faulthandler__sigfpe, METH_NOARGS, faulthandler__sigfpe__doc__},
+
+static PyObject *
+faulthandler__sigfpe_impl(PyObject *module);
+
+static PyObject *
+faulthandler__sigfpe(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler__sigfpe_impl(module);
+}
+
+PyDoc_STRVAR(faulthandler__sigabrt__doc__,
+"_sigabrt($module, /)\n"
+"--\n"
+"\n"
+"Raise a SIGABRT signal.");
+
+#define FAULTHANDLER__SIGABRT_METHODDEF    \
+    {"_sigabrt", (PyCFunction)faulthandler__sigabrt, METH_NOARGS, faulthandler__sigabrt__doc__},
+
+static PyObject *
+faulthandler__sigabrt_impl(PyObject *module);
+
+static PyObject *
+faulthandler__sigabrt(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler__sigabrt_impl(module);
+}
+
+#if defined(FAULTHANDLER_USE_ALT_STACK)
+
+PyDoc_STRVAR(faulthandler__stack_overflow__doc__,
+"_stack_overflow($module, /)\n"
+"--\n"
+"\n"
+"Recursive call to raise a stack overflow.");
+
+#define FAULTHANDLER__STACK_OVERFLOW_METHODDEF    \
+    {"_stack_overflow", (PyCFunction)faulthandler__stack_overflow, METH_NOARGS, faulthandler__stack_overflow__doc__},
+
+static PyObject *
+faulthandler__stack_overflow_impl(PyObject *module);
+
+static PyObject *
+faulthandler__stack_overflow(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return faulthandler__stack_overflow_impl(module);
+}
+
+#endif /* defined(FAULTHANDLER_USE_ALT_STACK) */
+
+#if defined(MS_WINDOWS)
+
+PyDoc_STRVAR(faulthandler__raise_exception__doc__,
+"_raise_exception($module, code, flags=0, /)\n"
+"--\n"
+"\n"
+"Call RaiseException(code, flags).");
+
+#define FAULTHANDLER__RAISE_EXCEPTION_METHODDEF    \
+    {"_raise_exception", _PyCFunction_CAST(faulthandler__raise_exception), METH_FASTCALL, faulthandler__raise_exception__doc__},
+
+static PyObject *
+faulthandler__raise_exception_impl(PyObject *module, unsigned int code,
+                                   unsigned int flags);
+
+static PyObject *
+faulthandler__raise_exception(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+    PyObject *return_value = NULL;
+    unsigned int code;
+    unsigned int flags = 0;
+
+    if (!_PyArg_CheckPositional("_raise_exception", nargs, 1, 2)) {
+        goto exit;
+    }
+    if (!_PyLong_UnsignedInt_Converter(args[0], &code)) {
+        goto exit;
+    }
+    if (nargs < 2) {
+        goto skip_optional;
+    }
+    if (!_PyLong_UnsignedInt_Converter(args[1], &flags)) {
+        goto exit;
+    }
+skip_optional:
+    return_value = faulthandler__raise_exception_impl(module, code, flags);
+
+exit:
+    return return_value;
+}
+
+#endif /* defined(MS_WINDOWS) */
+
+#ifndef FAULTHANDLER_REGISTER_PY_METHODDEF
+    #define FAULTHANDLER_REGISTER_PY_METHODDEF
+#endif /* !defined(FAULTHANDLER_REGISTER_PY_METHODDEF) */
+
+#ifndef FAULTHANDLER_UNREGISTER_PY_METHODDEF
+    #define FAULTHANDLER_UNREGISTER_PY_METHODDEF
+#endif /* !defined(FAULTHANDLER_UNREGISTER_PY_METHODDEF) */
+
+#ifndef FAULTHANDLER__STACK_OVERFLOW_METHODDEF
+    #define FAULTHANDLER__STACK_OVERFLOW_METHODDEF
+#endif /* !defined(FAULTHANDLER__STACK_OVERFLOW_METHODDEF) */
+
+#ifndef FAULTHANDLER__RAISE_EXCEPTION_METHODDEF
+    #define FAULTHANDLER__RAISE_EXCEPTION_METHODDEF
+#endif /* !defined(FAULTHANDLER__RAISE_EXCEPTION_METHODDEF) */
+/*[clinic end generated code: output=31bf0149d0d02ccf input=a9049054013a1b77]*/
index 84cfc6bd8ef6e491dda381cfd58d6bc74f25ee5d..9b8c77e2b0401f8d54f8d83b6dd56b2bbc674bb4 100644 (file)
@@ -30,6 +30,9 @@
 #endif
 
 
+#include "clinic/faulthandler.c.h"
+
+
 /* Sentinel to ignore all_threads on free-threading */
 #define FT_IGNORE_ALL_THREADS 2
 
 #define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str))
 
 
+/*[clinic input]
+module faulthandler
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c3d4f47c4f3d440f]*/
+
+
 typedef struct {
     int signum;
     int enabled;
@@ -228,22 +237,27 @@ faulthandler_dump_c_stack(int fd)
     reentrant = 0;
 }
 
-static PyObject*
-faulthandler_dump_traceback_py(PyObject *self,
-                               PyObject *args, PyObject *kwargs)
+
+/*[clinic input]
+faulthandler.dump_traceback as faulthandler_dump_traceback_py
+
+    file: object(py_default="sys.stderr") = NULL
+    all_threads: bool = True
+
+Dump the traceback of the current thread into file.
+
+Dump the traceback of all threads if all_threads is true.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file,
+                                    int all_threads)
+/*[clinic end generated code: output=34efece0ca18314f input=b832ec55e27a7898]*/
 {
-    static char *kwlist[] = {"file", "all_threads", NULL};
-    PyObject *file = NULL;
-    int all_threads = 1;
     PyThreadState *tstate;
     const char *errmsg;
     int fd;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-        "|Op:dump_traceback", kwlist,
-        &file, &all_threads))
-        return NULL;
-
     fd = faulthandler_get_fileno(&file);
     if (fd < 0)
         return NULL;
@@ -278,19 +292,19 @@ faulthandler_dump_traceback_py(PyObject *self,
     Py_RETURN_NONE;
 }
 
-static PyObject *
-faulthandler_dump_c_stack_py(PyObject *self,
-                             PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = {"file", NULL};
-    PyObject *file = NULL;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-        "|O:dump_c_stack", kwlist,
-        &file)) {
-        return NULL;
-    }
+/*[clinic input]
+faulthandler.dump_c_stack as faulthandler_dump_c_stack_py
+
+    file: object(py_default="sys.stderr") = NULL
 
+Dump the C stack of the current thread.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_dump_c_stack_py_impl(PyObject *module, PyObject *file)
+/*[clinic end generated code: output=151d6c95e9f8c0f6 input=10f6b6f29b635109]*/
+{
     int fd = faulthandler_get_fileno(&file);
     if (fd < 0) {
         return NULL;
@@ -569,20 +583,25 @@ faulthandler_enable(void)
     return 0;
 }
 
-static PyObject*
-faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
+
+/*[clinic input]
+faulthandler.enable as faulthandler_py_enable
+
+    file: object(py_default="sys.stderr") = NULL
+    all_threads: bool = True
+    c_stack: bool = True
+
+Enable the fault handler.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_py_enable_impl(PyObject *module, PyObject *file,
+                            int all_threads, int c_stack)
+/*[clinic end generated code: output=580d89b5eb62f1cb input=77277746a88b25ca]*/
 {
-    static char *kwlist[] = {"file", "all_threads", "c_stack", NULL};
-    PyObject *file = NULL;
-    int all_threads = 1;
     int fd;
-    int c_stack = 1;
     PyThreadState *tstate;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-        "|Opp:enable", kwlist, &file, &all_threads, &c_stack))
-        return NULL;
-
     fd = faulthandler_get_fileno(&file);
     if (fd < 0)
         return NULL;
@@ -626,8 +645,16 @@ faulthandler_disable(void)
     Py_CLEAR(fatal_error.file);
 }
 
-static PyObject*
-faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
+
+/*[clinic input]
+faulthandler.disable as faulthandler_disable_py
+
+Disable the fault handler.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_disable_py_impl(PyObject *module)
+/*[clinic end generated code: output=e9087a04535af3cb input=6223eac6804550af]*/
 {
     if (!fatal_error.enabled) {
         Py_RETURN_FALSE;
@@ -636,10 +663,18 @@ faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
     Py_RETURN_TRUE;
 }
 
-static PyObject*
-faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored))
+
+/*[clinic input]
+faulthandler.is_enabled -> bool
+
+Check if the handler is enabled.
+[clinic start generated code]*/
+
+static int
+faulthandler_is_enabled_impl(PyObject *module)
+/*[clinic end generated code: output=b9f33a3e0f881a23 input=3d5532547eb14bf9]*/
 {
-    return PyBool_FromLong(fatal_error.enabled);
+    return fatal_error.enabled;
 }
 
 static void
@@ -734,26 +769,33 @@ format_timeout(PyTime_t us)
     return _PyMem_Strdup(buffer);
 }
 
-static PyObject*
-faulthandler_dump_traceback_later(PyObject *self,
-                                   PyObject *args, PyObject *kwargs)
+
+/*[clinic input]
+faulthandler.dump_traceback_later
+
+    timeout as timeout_obj: object
+    repeat: bool = False
+    file: object(py_default="sys.stderr") = NULL
+    exit: bool = False
+
+Dump the traceback of all threads in timeout seconds.
+
+If repeat is true, the tracebacks of all threads are dumped every timeout
+seconds. If exit is true, call _exit(1) which is not safe.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_dump_traceback_later_impl(PyObject *module,
+                                       PyObject *timeout_obj, int repeat,
+                                       PyObject *file, int exit)
+/*[clinic end generated code: output=a24d80d694d25ba2 input=fd005625ecc2ba9a]*/
 {
-    static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
-    PyObject *timeout_obj;
     PyTime_t timeout, timeout_us;
-    int repeat = 0;
-    PyObject *file = NULL;
     int fd;
-    int exit = 0;
     PyThreadState *tstate;
     char *header;
     size_t header_len;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-        "O|iOi:dump_traceback_later", kwlist,
-        &timeout_obj, &repeat, &file, &exit))
-        return NULL;
-
     if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
                                   _PyTime_ROUND_TIMEOUT) < 0) {
         return NULL;
@@ -836,9 +878,16 @@ faulthandler_dump_traceback_later(PyObject *self,
     Py_RETURN_NONE;
 }
 
-static PyObject*
-faulthandler_cancel_dump_traceback_later_py(PyObject *self,
-                                            PyObject *Py_UNUSED(ignored))
+
+/*[clinic input]
+faulthandler.cancel_dump_traceback_later as faulthandler_cancel_dump_traceback_later_py
+
+Cancel the previous call to dump_traceback_later().
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_cancel_dump_traceback_later_py_impl(PyObject *module)
+/*[clinic end generated code: output=2cf303015d39c926 input=51ad64b6ca8412a4]*/
 {
     cancel_dump_traceback_later();
     Py_RETURN_NONE;
@@ -938,26 +987,32 @@ check_signum(int signum)
     return 1;
 }
 
-static PyObject*
-faulthandler_register_py(PyObject *self,
-                         PyObject *args, PyObject *kwargs)
+
+/*[clinic input]
+faulthandler.register as faulthandler_register_py
+
+    signum: int
+    file: object(py_default="sys.stderr") = NULL
+    all_threads: bool = True
+    chain: bool = False
+
+Register a handler for the signal 'signum'.
+
+Dump the traceback of the current thread, or of all threads if
+all_threads is True, into file.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_register_py_impl(PyObject *module, int signum, PyObject *file,
+                              int all_threads, int chain)
+/*[clinic end generated code: output=1f770cee150a56cd input=ae9de829e850907b]*/
 {
-    static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL};
-    int signum;
-    PyObject *file = NULL;
-    int all_threads = 1;
-    int chain = 0;
     int fd;
     user_signal_t *user;
     _Py_sighandler_t previous;
     PyThreadState *tstate;
     int err;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-        "i|Opp:register", kwlist,
-        &signum, &file, &all_threads, &chain))
-        return NULL;
-
     if (!check_signum(signum))
         return NULL;
 
@@ -1022,16 +1077,23 @@ faulthandler_unregister(user_signal_t *user, int signum)
     return 1;
 }
 
-static PyObject*
-faulthandler_unregister_py(PyObject *self, PyObject *args)
+
+/*[clinic input]
+faulthandler.unregister as faulthandler_unregister_py
+
+     signum: int
+     /
+
+Unregister the handler of the signal 'signum' registered by register().
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler_unregister_py_impl(PyObject *module, int signum)
+/*[clinic end generated code: output=01734423da1155ed input=c016de014495d384]*/
 {
-    int signum;
     user_signal_t *user;
     int change;
 
-    if (!PyArg_ParseTuple(args, "i:unregister", &signum))
-        return NULL;
-
     if (!check_signum(signum))
         return NULL;
 
@@ -1097,13 +1159,20 @@ faulthandler_raise_sigsegv(void)
 #endif
 }
 
+
+/*[clinic input]
+faulthandler._sigsegv
+
+     release_gil: bool = False
+     /
+
+Raise a SIGSEGV signal.
+[clinic start generated code]*/
+
 static PyObject *
-faulthandler_sigsegv(PyObject *self, PyObject *args)
+faulthandler__sigsegv_impl(PyObject *module, int release_gil)
+/*[clinic end generated code: output=96e5a2f215b01b76 input=c6ad893cf2ea2b41]*/
 {
-    int release_gil = 0;
-    if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil))
-        return NULL;
-
     if (release_gil) {
         Py_BEGIN_ALLOW_THREADS
         faulthandler_raise_sigsegv();
@@ -1120,8 +1189,16 @@ faulthandler_fatal_error_thread(void *plock)
     Py_FatalError("in new thread");
 }
 
+
+/*[clinic input]
+faulthandler._fatal_error_c_thread
+
+Call Py_FatalError() in a new C thread.
+[clinic start generated code]*/
+
 static PyObject *
-faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
+faulthandler__fatal_error_c_thread_impl(PyObject *module)
+/*[clinic end generated code: output=101bc8aaf4a5eec1 input=fbdca6fffd639a39]*/
 {
     long tid;
     PyThread_type_lock lock;
@@ -1150,16 +1227,32 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
-static PyObject*
-faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy))
+
+/*[clinic input]
+faulthandler._sigfpe
+
+Raise a SIGFPE signal.
+[clinic start generated code]*/
+
+static PyObject *
+faulthandler__sigfpe_impl(PyObject *module)
+/*[clinic end generated code: output=dec9c98100e986db input=fd608a92d4421d28]*/
 {
     faulthandler_suppress_crash_report();
     raise(SIGFPE);
     Py_UNREACHABLE();
 }
 
+
+/*[clinic input]
+faulthandler._sigabrt
+
+Raise a SIGABRT signal.
+[clinic start generated code]*/
+
 static PyObject *
-faulthandler_sigabrt(PyObject *self, PyObject *args)
+faulthandler__sigabrt_impl(PyObject *module)
+/*[clinic end generated code: output=58c1378a0c166682 input=be3e0ecefb8676b8]*/
 {
     faulthandler_suppress_crash_report();
     abort();
@@ -1186,8 +1279,16 @@ stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth)
     return stack_overflow(min_sp, max_sp, depth);
 }
 
+
+/*[clinic input]
+faulthandler._stack_overflow
+
+Recursive call to raise a stack overflow.
+[clinic start generated code]*/
+
 static PyObject *
-faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
+faulthandler__stack_overflow_impl(PyObject *module)
+/*[clinic end generated code: output=efffba4be522d8fb input=4291594a790b6c35]*/
 {
     size_t depth, size;
     uintptr_t sp = (uintptr_t)&depth;
@@ -1238,13 +1339,23 @@ faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
     return 0;
 }
 
+
 #ifdef MS_WINDOWS
+/*[clinic input]
+faulthandler._raise_exception
+
+    code: unsigned_int
+    flags: unsigned_int = 0
+    /
+
+Call RaiseException(code, flags).
+[clinic start generated code]*/
+
 static PyObject *
-faulthandler_raise_exception(PyObject *self, PyObject *args)
+faulthandler__raise_exception_impl(PyObject *module, unsigned int code,
+                                   unsigned int flags)
+/*[clinic end generated code: output=2346cf318eab10dc input=43a5ba0eb7794504]*/
 {
-    unsigned int code, flags = 0;
-    if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags))
-        return NULL;
     faulthandler_suppress_crash_report();
     RaiseException(code, flags, 0, NULL);
     Py_RETURN_NONE;
@@ -1255,69 +1366,26 @@ PyDoc_STRVAR(module_doc,
 "faulthandler module.");
 
 static PyMethodDef module_methods[] = {
-    {"enable",
-     _PyCFunction_CAST(faulthandler_py_enable), METH_VARARGS|METH_KEYWORDS,
-     PyDoc_STR("enable($module, /, file=sys.stderr, all_threads=True)\n--\n\n"
-               "Enable the fault handler.")},
-    {"disable", faulthandler_disable_py, METH_NOARGS,
-     PyDoc_STR("disable($module, /)\n--\n\n"
-               "Disable the fault handler.")},
-    {"is_enabled", faulthandler_is_enabled, METH_NOARGS,
-     PyDoc_STR("is_enabled($module, /)\n--\n\n"
-               "Check if the handler is enabled.")},
-    {"dump_traceback",
-     _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_VARARGS|METH_KEYWORDS,
-     PyDoc_STR("dump_traceback($module, /, file=sys.stderr, all_threads=True)\n--\n\n"
-               "Dump the traceback of the current thread, or of all threads "
-               "if all_threads is True, into file.")},
-     {"dump_c_stack",
-      _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_VARARGS|METH_KEYWORDS,
-      PyDoc_STR("dump_c_stack($module, /, file=sys.stderr)\n--\n\n"
-              "Dump the C stack of the current thread.")},
-    {"dump_traceback_later",
-     _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_VARARGS|METH_KEYWORDS,
-     PyDoc_STR("dump_traceback_later($module, /, timeout, repeat=False, file=sys.stderr, exit=False)\n--\n\n"
-               "Dump the traceback of all threads in timeout seconds,\n"
-               "or each timeout seconds if repeat is True. If exit is True, "
-               "call _exit(1) which is not safe.")},
-    {"cancel_dump_traceback_later",
-     faulthandler_cancel_dump_traceback_later_py, METH_NOARGS,
-     PyDoc_STR("cancel_dump_traceback_later($module, /)\n--\n\n"
-               "Cancel the previous call to dump_traceback_later().")},
+    FAULTHANDLER_PY_ENABLE_METHODDEF
+    FAULTHANDLER_DISABLE_PY_METHODDEF
+    FAULTHANDLER_IS_ENABLED_METHODDEF
+    FAULTHANDLER_DUMP_TRACEBACK_PY_METHODDEF
+    FAULTHANDLER_DUMP_C_STACK_PY_METHODDEF
+    FAULTHANDLER_DUMP_TRACEBACK_LATER_METHODDEF
+    FAULTHANDLER_CANCEL_DUMP_TRACEBACK_LATER_PY_METHODDEF
 #ifdef FAULTHANDLER_USER
-    {"register",
-     _PyCFunction_CAST(faulthandler_register_py), METH_VARARGS|METH_KEYWORDS,
-     PyDoc_STR("register($module, /, signum, file=sys.stderr, all_threads=True, chain=False)\n--\n\n"
-               "Register a handler for the signal 'signum': dump the "
-               "traceback of the current thread, or of all threads if "
-               "all_threads is True, into file.")},
-    {"unregister",
-     _PyCFunction_CAST(faulthandler_unregister_py), METH_VARARGS,
-     PyDoc_STR("unregister($module, signum, /)\n--\n\n"
-               "Unregister the handler of the signal "
-               "'signum' registered by register().")},
+    FAULTHANDLER_REGISTER_PY_METHODDEF
+    FAULTHANDLER_UNREGISTER_PY_METHODDEF
 #endif
-    {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
-     PyDoc_STR("_sigsegv($module, release_gil=False, /)\n--\n\n"
-               "Raise a SIGSEGV signal.")},
-    {"_fatal_error_c_thread", faulthandler_fatal_error_c_thread, METH_NOARGS,
-     PyDoc_STR("_fatal_error_c_thread($module, /)\n--\n\n"
-               "Call Py_FatalError() in a new C thread.")},
-    {"_sigabrt", faulthandler_sigabrt, METH_NOARGS,
-     PyDoc_STR("_sigabrt($module, /)\n--\n\n"
-               "Raise a SIGABRT signal.")},
-    {"_sigfpe", faulthandler_sigfpe, METH_NOARGS,
-     PyDoc_STR("_sigfpe($module, /)\n--\n\n"
-               "Raise a SIGFPE signal.")},
+    FAULTHANDLER__SIGSEGV_METHODDEF
+    FAULTHANDLER__FATAL_ERROR_C_THREAD_METHODDEF
+    FAULTHANDLER__SIGABRT_METHODDEF
+    FAULTHANDLER__SIGFPE_METHODDEF
 #ifdef FAULTHANDLER_STACK_OVERFLOW
-    {"_stack_overflow", faulthandler_stack_overflow, METH_NOARGS,
-     PyDoc_STR("_stack_overflow($module, /)\n--\n\n"
-               "Recursive call to raise a stack overflow.")},
+    FAULTHANDLER__STACK_OVERFLOW_METHODDEF
 #endif
 #ifdef MS_WINDOWS
-    {"_raise_exception", faulthandler_raise_exception, METH_VARARGS,
-     PyDoc_STR("_raise_exception($module, code, flags=0, /)\n--\n\n"
-               "Call RaiseException(code, flags).")},
+    FAULTHANDLER__RAISE_EXCEPTION_METHODDEF
 #endif
     {NULL, NULL}  /* sentinel */
 };
@@ -1327,26 +1395,26 @@ PyExec_faulthandler(PyObject *module) {
     /* Add constants for unit tests */
 #ifdef MS_WINDOWS
     /* RaiseException() codes (prefixed by an underscore) */
-    if (PyModule_AddIntConstant(module, "_EXCEPTION_ACCESS_VIOLATION",
-                                EXCEPTION_ACCESS_VIOLATION)) {
+    if (PyModule_Add(module, "_EXCEPTION_ACCESS_VIOLATION",
+                     PyLong_FromUnsignedLong(EXCEPTION_ACCESS_VIOLATION))) {
         return -1;
     }
-    if (PyModule_AddIntConstant(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO",
-                                EXCEPTION_INT_DIVIDE_BY_ZERO)) {
+    if (PyModule_Add(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO",
+                     PyLong_FromUnsignedLong(EXCEPTION_INT_DIVIDE_BY_ZERO))) {
         return -1;
     }
-    if (PyModule_AddIntConstant(module, "_EXCEPTION_STACK_OVERFLOW",
-                                EXCEPTION_STACK_OVERFLOW)) {
+    if (PyModule_Add(module, "_EXCEPTION_STACK_OVERFLOW",
+                     PyLong_FromUnsignedLong(EXCEPTION_STACK_OVERFLOW))) {
         return -1;
     }
 
     /* RaiseException() flags (prefixed by an underscore) */
-    if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE",
-                                EXCEPTION_NONCONTINUABLE)) {
+    if (PyModule_Add(module, "_EXCEPTION_NONCONTINUABLE",
+                     PyLong_FromUnsignedLong(EXCEPTION_NONCONTINUABLE))) {
         return -1;
     }
-    if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION",
-                                EXCEPTION_NONCONTINUABLE_EXCEPTION)) {
+    if (PyModule_Add(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION",
+                     PyLong_FromUnsignedLong(EXCEPTION_NONCONTINUABLE_EXCEPTION))) {
         return -1;
     }
 #endif