aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/pybind/module.cpp
blob: b7b003d3b087395512ff2065a52011838ee05c00 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "module.h"
#include "ptr.h"

#include <util/generic/adaptor.h>

namespace NPyBind {

#if PY_MAJOR_VERSION >= 3
    namespace NPrivate {
        struct TFinCallBacksHolder {
            static TVector<TFinalizationCallBack>& GetCallBacks() {
                static TVector<TFinalizationCallBack> res;
                return res;
            }
        };

        TAtExitRegistrar::TAtExitRegistrar(TPyObjectPtr module) {
            TPyObjectPtr atExitModuleName(Py_BuildValue("s", "atexit"), true);
            TPyObjectPtr atExitModule(PyImport_Import(atExitModuleName.Get()));
            Y_VERIFY(atExitModule);
            TPyObjectPtr finalizerFunc(PyObject_GetAttrString(module.Get(), "finalizer"), true);
            Y_VERIFY(finalizerFunc);
            TPyObjectPtr registerName(Py_BuildValue("s", "register"), true);
            PyObject_CallMethodObjArgs(atExitModule.Get(), registerName.Get(), finalizerFunc.Get(), nullptr);
        }

        TPyBindModuleRegistrar::TPyBindModuleRegistrar() {
            TPyObjectPtr modules(PySys_GetObject("modules"));
            Y_ENSURE(modules.Get());
            if (Module = NPrivate::CreatePyBindModule()) {
                Y_VERIFY(0 == PyDict_SetItemString(modules.Get(), "pybind", Module.RefGet()));
            }
            AddFinalizationCallBack([this]() {
                auto ptr = Module;
                Y_UNUSED(ptr);
                TPyObjectPtr modules(PySys_GetObject("modules"));
                Y_ENSURE(modules.Get());
                TPyObjectPtr pyBindName(Py_BuildValue("s", "pybind"));
                if (PyDict_Contains(modules.Get(), pyBindName.Get()) == 1) {
                    Y_VERIFY(0==PyDict_DelItemString(modules.Get(), "pybind"));
                }
                if (Module) {
                    //We have to untrack the module because some refs from him refers to gc-leaked errors
                    //see exceptions.cpp fore more info
                    PyObject_GC_UnTrack(Module.Get());
                    Module.Drop();
                }
            });
        }

        void AddFinalizationCallBack(TFinalizationCallBack callback) {
            TFinCallBacksHolder::GetCallBacks().push_back(callback);
        }

        int FinalizeAll() {
            for (auto callback: Reversed(NPrivate::TFinCallBacksHolder::GetCallBacks())) {
                callback();
            }
            return 0;
        }
    }
#endif


    TModuleHolder::TModuleHolder()
        : Methods(1, new TVector<TMethodDef>)
    {
#if PY_MAJOR_VERSION >= 3
        AddModuleMethod<TModuleMethodCaller<decltype(&NPrivate::FinalizeAll), &NPrivate::FinalizeAll>::Call>("finalizer");
#endif
    }
}//NPyBind