Blender V4.3
bpy_interface_atexit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13#include <Python.h>
14
15#include "BLI_utildefines.h"
16
17#include "bpy.hh" /* own include */
18#include "bpy_capi_utils.hh"
19
20#include "WM_api.hh"
21
22static PyObject *bpy_atexit(PyObject * /*self*/, PyObject * /*args*/, PyObject * /*kw*/)
23{
24 /* NOTE(@ideasman42): This doesn't have to match Blender shutting down exactly,
25 * leaks reported by memory checking tools may be reported but are harmless
26 * and don't have to be *fixed* unless doing so is trivial.
27 *
28 * Just handle the basics:
29 * - Free resources avoiding crashes and errors on exit.
30 * - Remove Blender's temporary directory.
31 *
32 * Anything else that prevents `sys.exit(..)` from exiting gracefully should be handled here too.
33 */
34
36 /* As Python requested the exit, it handles shutting itself down. */
37 const bool do_python_exit = false;
38 /* User actions such as saving the session, preferences, recent-files for e.g.
39 * should be skipped because an explicit call to exit is more likely to be used as part of
40 * automated processes shouldn't impact the users session in the future. */
41 const bool do_user_exit_actions = false;
42
43 WM_exit_ex(C, do_python_exit, do_user_exit_actions);
44
45 Py_RETURN_NONE;
46}
47
48#if (defined(__GNUC__) && !defined(__clang__))
49# pragma GCC diagnostic push
50# pragma GCC diagnostic ignored "-Wcast-function-type"
51#endif
52
53static PyMethodDef meth_bpy_atexit = {"bpy_atexit", (PyCFunction)bpy_atexit, METH_NOARGS, nullptr};
54
55#if (defined(__GNUC__) && !defined(__clang__))
56# pragma GCC diagnostic pop
57#endif
58
59static PyObject *func_bpy_atregister = nullptr; /* borrowed reference, `atexit` holds. */
60
61static void atexit_func_call(const char *func_name, PyObject *atexit_func_arg)
62{
63 /* NOTE(@ideasman42): no error checking, if any of these fail we'll get a crash
64 * this is intended, but if its problematic it could be changed. */
65
66 PyObject *atexit_mod = PyImport_ImportModuleLevel("atexit", nullptr, nullptr, nullptr, 0);
67 PyObject *atexit_func = PyObject_GetAttrString(atexit_mod, func_name);
68 PyObject *args = PyTuple_New(1);
69 PyObject *ret;
70
71 PyTuple_SET_ITEM(args, 0, atexit_func_arg);
72 Py_INCREF(atexit_func_arg); /* only incref so we don't dec'ref along with 'args' */
73
74 ret = PyObject_CallObject(atexit_func, args);
75
76 Py_DECREF(atexit_mod);
77 Py_DECREF(atexit_func);
78 Py_DECREF(args);
79
80 if (ret) {
81 Py_DECREF(ret);
82 }
83 else { /* should never happen */
84 PyErr_Print();
85 }
86}
87
89{
90 /* atexit module owns this new function reference */
92
93 func_bpy_atregister = (PyObject *)PyCFunction_New(&meth_bpy_atexit, nullptr);
95}
96
98{
100
102 func_bpy_atregister = nullptr; /* don't really need to set but just in case */
103}
#define BLI_assert(a)
Definition BLI_assert.h:50
struct bContext * BPY_context_get(void)
static PyObject * func_bpy_atregister
static void atexit_func_call(const char *func_name, PyObject *atexit_func_arg)
void BPY_atexit_unregister()
void BPY_atexit_register()
static PyMethodDef meth_bpy_atexit
static PyObject * bpy_atexit(PyObject *, PyObject *, PyObject *)
return ret
void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_actions)