2009-12-10 13 views
5

Tanto en perlcall (en la sección "Estrategias para almacenar información de contexto de devolución de llamada") como en Extending and Embedding Perl (en la sección "Devolución de llamada") se enumeran 3 maneras diferentes de llamar sub rutinas Perl de llamadas XS/C:Registrando múltiples referencias secundarias de Perl para una biblioteca C en XS

  1. Inmediatamente: XS llama
  2. diferida: guardar el árbitro como un sub SV * para más adelante
  3. múltiple: save n árbitros sub para más adelante

El ejemplo y detalles enumerados para # 3 anterior utilizan un hash en XS para asociar la ref sub con una función de C en particular, pero predefinir un número fijo de funciones de C que no es adecuada.

Estoy trabajando en una interfaz XS a una biblioteca de C que utiliza devoluciones de llamada/punteros de función con argumentos opcionales por ejemplo:

blah(custom_type *o, void (*func) (void *data, int more_data), const void * data); 

El bla C en esta biblioteca va a terminar llamando a la función pasa a lo largo de con los datos pasados.

Si es posible, me gustaría hacer un mapeo 1 a 1 de la API de C a la de Perl. p.ej.

blah($o, \&func, $data); 

Actualmente, tengo el n. ° 2 anterior, pero otra llamada a blah() sobreescribiría el SV * guardado.

¿Cómo implementaría el # 3 anterior?

+1

"salvar mi código Perl ref ... a llamar más tarde"? ¿Qué desencadena la llamada posterior? No está claro con qué parte estás teniendo problemas. Re "múltiple", ¿lo tienes trabajando para uno y quieres expandirlo? ¿O es solo parte de la tarea completa, aún no cumplida? – ysth

+0

He actualizado la pregunta para poder aclararla –

Respuesta

1

Esta es la solución que se me ocurrió:

La mayor parte de las devoluciones de llamada en esta biblioteca C tendrá un usuario suministrado void * y pasar que como primer argumento. Así que guardar los datos suministrados por el usuario SV * y en una estructura:

typedef struct __saved_callback { 
    SV *func; 
    void *data; 
} _saved_callback; 

Mi función XS asignará una estructura _saved_callback y pasar que como primer argumento a call_perl_sub() con la referencia sub Perl y que los datos supuesta usuario .

void 
blah(obj, func, data) 
    whatever *obj 
    void *func 
    void *data 
    CODE: 
     _saved_callback *sc = NULL; 
     Newx(sc, 1, _saved_callback); 
     sc->func = (SV *)func; 
     sc->data = data; 
     blah(obj, call_perl_sub, sc); 

Luego llame la referencia sub Perl (He omitido la manipulación de pila para el argumento de datos suministrada por el usuario):

void call_perl_sub(void *data) { 
    dSP; 
    int count; 
    _saved_callback *perl_saved_cb = data; 

    count = call_sv(perl_saved_cb->func, G_DISCARD); 
    if (count != 0) 
     croak("Expected 0 value got %d\n", count); 
} 
+0

Nota: estoy seguro de que hay una mejor solución, pero sigo aprendiendo XS. –

0

que no puedo dar una respuesta completa, por desgracia. En su lugar, te voy a dar algunos consejos:

  • no se puede asignar una referencia de código Perl (técnicamente un CV *) a una función C. Las referencias de código de Perl son realmente datos (un árbol de PO) con algunos punteros de funciones adjuntos para hacer los bits de trabajo específicos en cada OP. (Cf. perl guts illustrated para detalles sobre estructuras OP).

  • Lo que puede conseguir es escribir su propia función C con la firma requerida, pasarla al nivel C bla. Luego, en su código XS, obtenga las devoluciones de llamada de Perl (que se pasa como un escalador de Perl (SV)). Ver "perldoc perlapi". Busque svtype y los SVt_ * bits.) Almacene esos SV en algún lugar. Luego, cuando desee que la biblioteca C realice las devoluciones de llamada, su devolución de llamada C tendrá el control y podrá enviar sus devoluciones de llamada a nivel de Perl. Cf. "perldoc perlcall".

Buena suerte. Estás a punto de hacer cosas extrañas.

+0

También, déjenme agregar que mi respuesta se refiere a lo que creo que están tratando de hacer. No estoy 100% convencido de haber entendido tus objetivos correctamente. (Cf. ysth's comment on your question.) – tsee

+1

tsee: Solo los CV de perl-level se almacenan como optactos, los CV de nivel c no. perlcall enumera las diversas estrategias callback c a perl, y muchas funciones básicas también lo usan. p.ej. ordenar llamadas perl subs con varargs desde c. La solución de Adam Flott es la estrategia general, pero no la he examinado a fondo. – rurban

+0

rurban: Interesante que señale esto. Ha pasado alrededor de un año desde que escribí esa respuesta y he aprendido mucho sobre los aspectos internos desde entonces. Es curioso leer esta vieja respuesta mía :) – tsee

Cuestiones relacionadas