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