2012-07-11 16 views
8

Tengo un widget wx.py.Shell.shell que permite al usuario ejecutar el código de Python que interactúa con mi programa. Quiero poder pasar una función que el usuario define en este espacio a mi código C++ (a través del wrapper generado wxswig alrededor de mi widget personalizado) y ejecutarlo.Devolución de llamada de Python de SWIG PyObject_Call Segfault

En ++ código que estoy usando un std :: función <> clase para invocar funciones encuadernados (C++ o Python) mi C

así que creé una clase simple para envolver el PyObject con el operador de llamada de función. Sin embargo, recibo un segfault cuando trato de llamar al PyObject *.

class PyMenuCallback 
{ 
    PyObject *Func; 
public: 
    PyMenuCallback(const PyMenuCallback &op2); 
    PyMenuCallback(PyObject *func); 
    ~PyMenuCallback(); 

    void operator() (int id); 
}; 
///////////////////////////////////////////////////////// 
PyMenuCallback::PyMenuCallback(PyObject *func) 
    : Func(func) 
{ 
    Py_XINCREF (Func); 
    if(!PyCallable_Check(Func)) 
     cout << "Not a Callable Callback." << endl; //Throw an exception or something 
} 

PyMenuCallback::PyMenuCallback(const PyMenuCallback &op2) 
    : Func (op2.Func) 
{ 
    Py_XINCREF (Func); 
    if(!PyCallable_Check(Func)) 
     cout << "Not a Callable Callback." << endl; 
} 

PyMenuCallback::~PyMenuCallback() 
{ 
    Py_XDECREF (Func); 
} 

void PyMenuCallback::operator() (int id) 
{ 
    cout << "Calling Callback" << endl; 
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func)) 
     return; 
    cout << "Building Args" << endl; 
    PyObject *arglist = Py_BuildValue ("(i)",id); 
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl; 
    PyObject *result = PyObject_Call(Func,arglist,0); //<<<<<---SEGFAULTS HERE 
    cout << "Executed" << endl; 
    Py_DECREF(arglist); 
    Py_XDECREF(result); 
} 

En mis intentos por encontrar lo que estaba pasando, puse un montón de declaraciones impresas. Uno de los cuales imprime el nombre del tipo y la referencia cuentan la línea antes de la segfault. Esto da como resultado la "función 3", así que tengo que suponer que la función aún no se ha destruido.

estoy pasando a la siguiente swig:

void AddOption (std::string name, PyObject *pycallback); 

En lo que construyo un PyMenuCallback

Estoy en una pérdida para saber qué está causando el error de segmentación, alguna idea?

+1

Creo que ha violado la [regla de tres] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) al no proporcionar un 'operator =' para 'PyMenuCallback'. No estoy seguro si ese es el problema aquí o no, pero ciertamente tiene el potencial de causar problemas. – Flexo

+0

No pude reproducir esto en mi máquina con un estuche de prueba. Logré confirmar que 'operator =' no se usaba por accidente, pero el código funcionaba y tampoco generaba advertencias en valgrind. ¿Puede expandir y simplificar un poco su caso de prueba usando '% inline' y'% {%} 'para que solo tenga un único archivo de interfaz? P.ej. Usé: [this] (http://pastebin.com/XYXj3a4p) para probar cuál puede tener diferencias sutiles a lo que estás usando/wrapping. – Flexo

+1

De hecho, buena captura, olvidé operator =. Sin embargo, no se usa en este momento, pero lo agregaré. – Tocs

Respuesta

3

Desde el C++ llamar a la devolución de llamada pitón está dentro de un wxWidget, y la envoltura trago es generada por el especial wxPython trago (wxswig?) Hay algún tipo de protección requerida hilo alrededor de la llamada a la función ...

El fijo el operador debe tener este aspecto

void PyMenuCallback::operator() (int id) 
{ 
    cout << "Calling Callback" << endl; 
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func)) 
     return; 
    cout << "Building Args" << endl; 
    PyObject *arglist = Py_BuildValue ("(i)",id); 
    cout << "Built: " << arglist << endl; 
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl; 

    wxPyBlock_t blocked = wxPyBeginBlockThreads(); //Anti-WxSwig 

    PyObject *result = PyObject_Call(Func,arglist,0); 

    wxPyEndBlockThreads(blocked); 


    cout << "Executed" << endl; 
    Py_XDECREF(arglist); 
    Py_XDECREF(result); 
} 

Asegúrese de incluir

#include "wx/wxPython/wxPython.h" 
#include "wx/wxPython/wxPython_int.h" 
Cuestiones relacionadas