Arbeiten an einer Steuerung einer eGige Kamera, mit einer C-Bibliothek, habe ich einen cython Code project mit der Idee, die besten Dinge jeder Sprache zu haben.Cython Callback segfaults mit Python-c-Api Anrufe
Die Bibliothek bietet eine Möglichkeit, einen Herzschlag von der Kamera zu hören, um festzustellen, ob die Verbindung getrennt wurde. Der Callback mit in einer C++ - Klasse habe ich bereits getan, aber von dieser C++ - Klasse, rufen Sie eine Python-Methode einer Klasse in eine Segmentierungsfehler in allen Möglichkeiten, die ich versucht habe.
Ich habe es in einer bestimmten C++ Klasse gekapselt:
#include <Python.h>
/* (...) */
PyCallback::PyCallback(PyObject* self, const char* methodName)
{
Py_XINCREF(self);
_self = self;
_method = PyObject_GetAttrString(self, methodName);
}
PyCallback::~PyCallback()
{
Py_XDECREF(_self);
}
void PyCallback::execute()
{
try
{
PyObject *args = PyTuple_Pack(1,_self);
PyObject_CallFunctionObjArgs(_method, args);
}catch(...){
_error("Exception calling python");
}
}
Von einem Cython der Code-Objekt ist:
cdef class Camera(...):
# (...)
cdef registerRemovalCallback(self):
cdef:
PyCallback* obj
obj = new PyCallback(<PyObject*> self, <char*> "cameraRemovalCallback")
cdef cameraRemovalCallback(self):
self._isPresent = False
Der unterste Teil des Backtrace ist es nur, wenn versuchen, die Vorbereitung Argumente.
#0 0x00007ffff7b24592 in PyErr_Restore() from /usr/lib64/libpython2.6.so.1.0
#1 0x00007ffff7b23fef in PyErr_SetString() from /usr/lib64/libpython2.6.so.1.0
#2 0x00007ffff7b314dd in ??() from /usr/lib64/libpython2.6.so.1.0
#3 0x00007ffff7b313ca in ??() from /usr/lib64/libpython2.6.so.1.0
#4 0x00007ffff7b316c1 in ??() from /usr/lib64/libpython2.6.so.1.0
#5 0x00007ffff7b31d2f in ??() from /usr/lib64/libpython2.6.so.1.0
#6 0x00007ffff7b31e9c in Py_BuildValue() from /usr/lib64/libpython2.6.so.1.0
#7 0x00007ffff637cbf8 in PyCallback::execute (this=0x16212a0) at pylon/PyCallback.cpp:53
#8 0x00007ffff6376248 in CppCamera::removalCallback (this=0x161fb30, pDevice=<value optimized out>) at pylon/Camera.cpp:387
Ich habe versucht, die Argumente mit _Py_BuildValue ("(Selbst-)", Selbst-) zu machen; aber dann habe ich eine segfault dort. mit in diesem Objekt
Ich habe auch versucht, mit PyObject_CallFunctionObjArgs mit NULL im Argumente-Feld, zu denken, dass vielleicht der Zeiger auf „Selbst“ ist bereits als Methode Punkt zu einer bestimmten Adresse eingebettet. Aber sie habe ich die segfault dort.
Wer sieht meinen Fehler? Etwas, das anders gemacht werden soll? Ich hoffe, dass dies ein Missverständnis von mir ist, wer das tun soll.
aktualisieren @2016.08.01:
Folgende Kommentare Indikationen sind zwei Änderungen im Code gemacht:
Zunächst wird der Zeigerspeicher zum PyCallback gespeichert worden ist als Mitglied der Kamera cython Klasse:
cdef class Camera(...):
cdef:
#(...)
PyCallback* _cbObj
# (...)
cdef registerRemovalCallback(self):
self._cbObj = new PyCallback(<PyObject*> self, <char*> "cameraRemovalCallback")
cdef cameraRemovalCallback(self):
self._isPresent = False
Auch dies ist eine grundlegende Quelle von segfaults es sieht aus, es war nicht in der aktuellen beteiligt.
Dann PyCallback :: execute() in der C++, habe ich einige Änderungen vorgenommen. Nach der Lektüre über die GIL (Global Interpreter Lock) und einige Anrufe für sie hinzufügen, habe ich einen Scheck hinzugefügt, die zur Lösung führen kann:
PyCallback::PyCallback(PyObject* self, const char* methodName)
{
Py_Initialize();
Py_XINCREF(self);
_self = self;
_method = PyObject_GetAttrString(self, methodName);
}
PyCallback::~PyCallback()
{
Py_XDECREF(_self);
Py_Finalize();
}
void PyCallback::execute()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
try
{
if (PyCallable_Check(_method))
{
_info("Build arguments and call method");
PyObject *args = Py_BuildValue("(O)", _self);
PyObject *kwargs = Py_BuildValue("{}", "", NULL);
PyObject_Call(_method, args, kwargs);
}
else
{
_warning("The given method is not callable!");
}
}
catch(...)
{
// TODO: collect and show more information about the exception
_error("Exception calling python");
}
PyGILState_Release(gstate);
}
Auch ich bin nicht sicher, wie der Anruf zu tun Der Hauptpunkt ist, dass _PyCallable_Check_ false zurückgibt.
Ich habe auch zu verwenden, die typedef Option und C Zeiger auf Funktion nennen es mit dem gleichen segfault Ergebnis getestet.
aktualisieren @2016.08.03:
Ich habe mit den vorgeschlagenen Änderungen gehen. cameraRemovalCallback
wird jetzt von cdef
zu def
geändert und einige if
s in PyCallback
meldet, dass die Methode jetzt gefunden wird. Auch wurde ~PyCallback()
ein Aufruf an Py_XDECREF(_method)
hinzugefügt, falls es im Konstruktor gefunden wurde. Der nutzlose try-catch
wurde ebenfalls entfernt.
Aus dem Verweis auf die , die DavidW Erwähnung, habe ich viele der *Call*
Kombinationen überprüfen: auf den Segfault fallen.
Ich denke, diese Frage schmutzig immer und wird immer das Aussehen eines Forum (Frage-> Antwort-> Replay -> ...). Es tut mir leid, und ich werde versuchen, das nächste Mal, wenn ich schreibe, sagen, dass der Segfault gelöst wurde und was genau war.
Callback-Funktionen können in Cython-Code implementiert werden. Siehe [ein Rückrufbeispiel] (https://github.com/cython/cython/blob/master/Demos/callback/cheese.pyx), [eine alte Frage] (http://stackoverflow.com/questions/5242051/ cython-implementation-callbacks) und [eine alte Frage] (http://stackoverflow.com/questions/11700501/python-cython-c-and-callbacks-calling-a-python-function-from-cusing-) Cython). –
Die Dokumentation für 'PyObject_CallFunctionObjArgs' https://docs.python.org/2/c-api/object.html#c.PyObject_CallFunctionObjArgs impliziert, dass Sie eine variable Anzahl von' PyObject * 's gefolgt von' NULL' übergeben sollten. Das 'NULL' ist wichtig, weil es Python mitteilt, dass die Liste der Argumente overs ist. Beispiel:' PyObject_CallFunctionObjArgs (_method, self, NULL); ' – DavidW
Leider ist Ihr Beispiel nicht vollständig genug, um zu sagen, ob das das einzige Problem ist. (Außerdem: 'obj' ist zumindest im angegebenen Code nicht irgendwo in' registerRemovalCallback' gespeichert.) – DavidW