Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Pass signals and argv from C to embedded Perl

by ikegami (Pope)
on Jan 30, 2019 at 16:18 UTC ( #1229173=note: print w/replies, xml ) Need Help??


in reply to Pass signals and argv from C to embedded Perl

I can not figure out how to pass C's argv to Perl script as ARGV

You don't want to pass argv to the Perl interpreter; you want to pass arguments to it. That's done via 3rd and 4th argument of perl_parse.

char** perl_argv = malloc( (argc+3) * sizeof(char*) ); perlargv[0] = "perl"; perlargv[1] = "-e"; perlargv[2] = "1"; perlargv[3] = "--"; int i = argc-1; while (i--) perlargv[i+4] = argv[i+1]; perl_parse(my_perl, NULL, argc+3, perlargv, NULL);

Don't forget to free the memory you allocated for the arguments. This should be done after freeing the Perl interpreter.


I can not figure out how to pass any signal the C program gets, for example Ctrl-C/SIGINT, to the Perl script.

You don't want to "pass signals"; you simply want the Perl program to handle them. That's done by setting $SIG{INT}. The system calls whatever handler was set to handle the signal, whether this was done by C code or by Perl code. You've already proved that this works.

As for not getting the message, could you have been suffering from buffering because you didn't end your messages with a line feed?

Replies are listed 'Best First'.
Re^2: Pass signals and argv from C to embedded Perl
by bliako (Vicar) on Jan 31, 2019 at 11:13 UTC

    Cool! the ARGV method you suggested works just fine. I would not be able to figure that out from perlembed. Thanks.

    And you were right about buffering. Ending the message with a line feed fixed that. So now I get the sighandler message BUT still the Perl code terminates even if Perl's sighandler has no die() and is meant to just ignore it/print message.

    Update: just a warning that an infinite loop ensues if argc==0

    Update2: of course argc is always > 0.

    Update3: it turns out one can send parameters to perl -e ... using perl -e 'print join(",",@ARGV)."\n"' -- -a -b -c 12, ikegami adds -- before any user-specified arguments to perl.

    Update4: I have changed perlargv[i+3] to perlargv[i+4] so that -- is not overwritten.

    Update5: kschwab found out why ctrl-c kills the program (because of the long sleep, sleep(1000)),

    Update6: based on all the suggestions by ikegami and kschwab, this works for me:

    /* harness for embedding Perl into C modified by Bliako from https://perldoc.perl.org/perlembed.html Compile: $(perl -MConfig -e 'print $Config{cc}') perl_embed_argv_signal.c $ +(perl -MExtUtils::Embed -e ccopts -e ldopts) -o perl_embed_argv_signa +l 30/01/2019 */ #include <stdio.h> #include <signal.h> #include <EXTERN.h> /* from the Perl distribution */ #include <perl.h> /* from the Perl distribution */ static PerlInterpreter *my_perl; /*** The Perl interpreter ***/ void cleanup(void); //let perl handle it void signal_handler(int signum){ printf("got signal %d\n", signum); } int main(int argc, char **argv, char **env){ signal(SIGINT, signal_handler); PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); printf("%s : perl_alloc()\n", argv[0]); perl_construct(my_perl); printf("%s : perl_construct()\n", argv[0]); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; char** perlargv = malloc( (argc+3) * sizeof(char*) ); perlargv[0] = "perl"; perlargv[1] = "-e"; perlargv[2] = "1"; perlargv[3] = "--"; int i = argc-1; while (i--) perlargv[i+4] = argv[i+1]; perl_parse(my_perl, NULL, argc+3, perlargv, NULL); const char perlcode[] = "#$SIG{INT} = sub { print \"Caught your ctrl-c and exiting!\\n\"; exit +(0); };\n" "$SIG{INT} = sub { print \"Caught your ctrl-c but ignoring it!\\n\" }; +\n" "print \"$0: ARGV:\"; print ' '.$_ foreach(@ARGV); print \"\\n\";\n" "print \"my pid $$\\n\";\n" "print \"now sleeping, and you ctrl-c me\\n\";\n" "for(1..100){sleep(1);print\"$_\\n\";}\n" ; printf("%s : executing :\n%s\n", argv[0], perlcode); SV *ret = eval_pv(perlcode, FALSE); if( SvTRUE(ERRSV) ){ fprintf(stderr, "%s : eval_sv() has failed wi +th:\n%s\nfor the code:\n%s\n", argv[0], SvPVx_nolen(ERRSV), perlcode) +; cleanup(); exit(1); } printf("%s : done.\n", argv[0]); exit(EXIT_SUCCESS); } void cleanup(void){ perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); }

      kschwab found out why ctrl-c kills the program (because of the long sleep, sleep(1000)),

      While it should interrupt the sleep, it shouldn't cause it to exit; the message from the SIGINT handle should be printed. In your question, you said the message wasn't being printed.

      If you want an uninterruptible sleep (i.e. one that resumes after handling a signal),

      sub uninterruptible_sleep { my $sleep_until = time() + $_[0]; while (1) { my $time_left = $sleep_until - time(); return if $time_left <= 0; sleep($time_left); } }

      I have changed perlargv[i+3] to perlargv[i+4] so that -- is not overwritten.

      Fixed. I originally had -e1 as one argument (as I wold write it on the command line), but forgot to adjust the offset when I split them into two arguments.

      I've had problems linking, as there is a discrepancy between what the bash command returns for the path for an EXTERN.h and what exists on this machine.

      We also have some shell evaluations. The first expression evaluates and works just fine:

      $ (perl -MConfig -e 'print $Config{cc}') x86_64-linux-gnu-gcc$

      The second one seems to work; the problem is that I don't have an EXTERN.h exactly there:

      $ (perl -MExtUtils::Embed -e ccopts -e ldopts) -Wl,-E -fstack-protector-strong -L/usr/local/lib -L/usr/lib/x86_64-l +inux-gnu/perl/5.26/CORE -lperl -ldl -lm -lpthread -lc -lcrypt -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pip +e -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I +/usr/lib/x86_64-linux-gnu/perl/5.26/CORE $

      One thing I figured out is that it has a newline in it. The bigger problem is that I do not have a perl.h nor an EXTERN.h in this location.

      Where do I have one?

      $ locate EXTERN.h /usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE/EXTERN.h $

      5.26 is just a link:

      $ pwd /usr/lib/x86_64-linux-gnu/perl $ ls -l 5.26* lrwxrwxrwx 1 root root 6 Jul 18 2018 5.26 -> 5.26.1

      I read up a bit with ExtUtils::Embed, gave this a look-see:

      perl -MExtUtils::Embed -e perl_inc  -I/usr/lib/x86_64-linux-gnu/perl/5.26/CORE

      Let's try re-ordering:

      x86_64-linux-gnu-gcc perl_embed_argv_signal.c -Wl,-E  -fstack-protector-strong  -I/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -L/usr/local/lib  -L/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -lperl -ldl -lm -lpthread -lc -lcrypt -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  -o embedex

      A different linking problem:

      /usr/bin/ld: cannot find -lperl collect2: error: ld returned 1 exit status

      Then from all those years in comp.lang.c, I remember that the thing you do is s/l/lib/, so:

      Update the package index: # sudo apt-get update Install libperl-dev deb package: # sudo apt-get install libperl-dev

      Same command with necessary library:

      $ x86_64-linux-gnu-gcc perl_embed_argv_signal.c -Wl,-E -fstack-protec +tor-strong -I/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -L/usr/local +/lib -L/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -lperl -ldl -lm -l +pthread -lc -lcrypt -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno- +strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FIL +E_OFFSET_BITS=64 -o embedex $ ls 1.84.txt 2.analyse_text.pl embedex 1.analyse_text.pl 2.bliako.pl hs_ref_GRCh38.p12_chr20.fa 1.bliako.pl 2.bliako.txt hs_ref_GRCh38.p12_chr20.fa.3. +state 1.bliako.txt 2.create.bash hs_ref_GRCh38.p12_chr20.fa.gz 1.c_calls_perl.c 3.bliako.txt Markov 1.em_perl.c 84-0.txt perl_embed_argv_signal.c 1.manifest 84.state 'Untitled Document 1' 1.predict.pl bliako1.pm 'Untitled Document 2' $ ./embedex fruit flying dutchman ./embedex : perl_alloc() ./embedex : perl_construct() ./embedex : executing : #$SIG{INT} = sub { print "Caught your ctrl-c and exiting!\n"; exit(0); + }; $SIG{INT} = sub { print "Caught your ctrl-c but ignoring it!\n" }; print "$0: ARGV:"; print ' '.$_ foreach(@ARGV); print "\n"; print "my pid $$\n"; print "now sleeping, and you ctrl-c me\n"; for(1..100){sleep(1);print"$_\n";} -e: ARGV: fruit flying dutchman my pid 21007 now sleeping, and you ctrl-c me 1 2 3 4 5 ^CCaught your ctrl-c but ignoring it! 6 7 8 9 ^CCaught your ctrl-c but ignoring it! 10 11 12 13 ... 99 100 ./embedex : done. $

      And now with ctrl-c commented out the other way:

      $ x86_64-linux-gnu-gcc 2.perl_embed_argv_signal.c -Wl,-E -fstack-prot +ector-strong -I/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -L/usr/loc +al/lib -L/usr/lib/x86_64-linux-gnu/perl/5.26.1/CORE -lperl -ldl -lm +-lpthread -lc -lcrypt -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fn +o-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_F +ILE_OFFSET_BITS=64 -o embedex2 $ ./embedex2 slithy toves wirr and wimbel ./embedex2 : perl_alloc() ./embedex2 : perl_construct() ./embedex2 : executing : $SIG{INT} = sub { print "Caught your ctrl-c and exiting!\n"; exit(0); +}; #$SIG{INT} = sub { print "Caught your ctrl-c but ignoring it!\n" }; print "$0: ARGV:"; print ' '.$_ foreach(@ARGV); print "\n"; print "my pid $$\n"; print "now sleeping, and you ctrl-c me\n"; for(1..15){sleep(1);print"$_\n";} -e: ARGV: slithy toves wirr and wimbel my pid 21094 now sleeping, and you ctrl-c me 1 2 3 4 5 ^CCaught your ctrl-c and exiting! $

      I'm glad to finally see output....

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1229173]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2019-11-13 07:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (70 votes). Check out past polls.

    Notices?