2016-08-14 2 views
4

Disclaimer: fragte über perlmonks.XS: Übergeben einer externen Bibliotheksfunktion ein Perl XS Callback

Ich hoffe, ich beschreiben und zeigen mein Problem richtig ... In XS, ich versuche, einen Rückruf in eine externe Bibliotheksfunktion zu senden, wo der Rückruf Perl spezifische Funktionen hat. Der XSUB wird als Funktionszeiger an eine externe C-Funktion übergeben. Der XSUB Rückruf wiederum gesendet werden ruft zurück zu einem Unter in `main` Perl-Anwendung:

void callback(){ 
    dSP; 
    PUSHMARK(SP); 
    call_pv("p_callback", G_DISCARD|G_NOARGS); 
} 

// example extern call 

externFunc(&callback); 

Diese segfaults. Ich denke es ist, weil die externe Bibliothek die Perl-Funktionen nicht versteht, die aufgerufen werden. Die Dinge funktionieren gut, wenn ich die Callback() `-Funktion direkt aufrufen.

Gibt es Magie, die ich machen kann, damit die externe Bibliothek die Perl C-Funktionen "sieht" oder mache ich etwas falsch?

Hier ist der Code, den ich mit dem Testen bin:

use warnings; 
use strict; 

use Inline ('C' => 'DATA', libs => '-lwiringPi'); 

init(); 
setInterrupt(27, 3); 

# direct call 

callback(); 

# on() triggers the external function and sends 
# it the callback 

on(27); 

sub p_callback { 
    print "in perl callback\n"; 
} 

__DATA__ 
__C__ 

#include <stdlib.h> 
#include <stdio.h> 
#include <wiringPi.h> 

void init(); 
void on(int pin); 
void off(int pin); 
void setInterrupt(int pin, int edge); 
void callback(); 

void init(){ 
    printf("in init\n"); 
    wiringPiSetup(); 
} 
void on(int pin){ 
    pinMode(pin, 1); 
    digitalWrite(pin, 1); 
} 

void off(int pin){ 
    digitalWrite(pin, 0); 
    pinMode(pin, 0); 
} 

void setInterrupt(int pin, int edge){ 
    wiringPiISR(pin, edge, &callback); 
} 

void callback(){ 
    dSP; 
    PUSHMARK(SP); 
    call_pv("p_callback", G_DISCARD|G_NOARGS); 
} 

Ausgang:

in init 
in perl callback 
Segmentation fault 

Wenn ich die Perl-spezifische C Anrufe innerhalb der Callback zu entfernen und einfach eine `printf()` oder andere reine C-Arbeit, die Dinge laufen ohne Segfault ab.

+2

Aufruf in Perl von einem ISR scheint wie eine schlechte Idee. Es gibt viele Dinge, die schief gehen könnten. Zum Beispiel: Führen Sie einen Perl-Thread aus und wird der ISR von einem anderen Thread aufgerufen? – nwellnhof

+0

@nwellnhof Ich bin brandneu, um die Handhabung zu unterbrechen, und auch ein C newb, also ist dies eine große Lernkurve :) Sie haben darauf hingewiesen, dass ich hier etwas Forschung betreiben muss, bevor ich fortfahre. Vielen Dank! – stevieb

Antwort

1

Ich bin gerade auf diese Frage gestoßen und dachte, ich würde ihr meine eigene Antwort geben, wie ich es vor einiger Zeit gelöst habe.

Es gab einige wichtige Bits, die ich fehlte, um den Perl-Kontext zu setzen, sowie innerhalb der C exec_perl_callback()-Funktion.

use warnings; 
use strict; 

use Inline 'C'; 
use Inline 'NoClean'; 

sub p_callback { 
    print "hello, world from perl!\n"; 
} 

exec_perl_callback('p_callback'); 

__END__ 
__C__ 

#define PERL_NO_GET_CONTEXT 

PerlInterpreter * mine; 

void callback(char* perl_callback){ 
    PERL_SET_CONTEXT(mine); 

    dSP; 
    ENTER; 
    SAVETMPS; 
    PUSHMARK(SP); 
    PUTBACK; 

    exec_perl_callback(perl_callback, G_DISCARD|G_NOARGS); 

    FREETMPS; 
    LEAVE; 
} 

Ausgang:

hello world, from perl! 
Verwandte Themen