XS: Passing Perl XS External Library Callback Function

Disclaimer: defined in perlmonks .

I hope that I correctly describe and describe my problem ... In XS, I try to send a callback to an external library function, where the callback has specific Perl functions. XSUB is passed as a function of a pointer to an external function C. The XSUB callback, sent one at a time, forwards back to the subroutine in the `main` perl application:

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

// example extern call

externFunc(&callback);

These are segfaults. I think because the external library does not understand the perl functions that call. Everything works fine if I call the callback () function directly, though.

Is there any magic I can do to make the external library “see” the Perl C functions, or am I doing something wrong?

Here is the code I'm testing:

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);
}

Conclusion:

in init
in perl callback
Segmentation fault

If I remove per c-specific C calls from the callback and just do `printf ()` or other work with pure C, everything happens without segfault.

+4
source share
1 answer

Just stumbled upon this question and thought that I would give him my own answer, since I decided to solve it some time ago.

There were some important bits that I was missing to set the Perl context, as well as in the C function exec_perl_callback().

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;
}

Conclusion:

hello world, from perl!
+1
source

Source: https://habr.com/ru/post/1651224/


All Articles