1

I need to pass loop object which is contained in perl EV::Loop module (EV::default_loop) to my C library.

I have a test library written on C that has a function test that takes struct ev_loop* object as input (EV_DEFAULT).

ev_lib/EvManager.h:

#pragma once

#include<stdio.h>
#include <ev.h>

void test (struct ev_loop* loop);
static void time_cb (EV_P_ ev_timer *w, int revents);

static ev_timer timeout_watcher;

ev_lib/EvManager.c:

#include "EvManager.h"

void test (struct ev_loop* loop)
{
  printf("%s\n", __PRETTY_FUNCTION__);
  ev_verify(loop);
  printf("%s\n", "test(): ev_verify OK!");

  ev_timer_init (&timeout_watcher, time_cb, 2, 2);
  ev_timer_start (loop, &timeout_watcher);

  return;
};

static void time_cb (EV_P_ ev_timer *w, int revents)
{
  printf("EvManager.c: time_cb");
};

compile:

gcc -c -Wall -fpic EvManager.c
gcc -shared -o libevmanager.so EvManager.o -lev

I wrote .xs module that used EVAPI.h to access the C loop object ( https://metacpan.org/pod/EV::MakeMaker):

EvTest.xs:

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "EVAPI.h"

#include "./ev_lib/EvManager.h"

static ev_timer timeout_watcher;

static void time_cb (EV_P_ ev_timer *w, int revents)
{
  puts ("ev_timer_start (EvTest.xs): is called roughly every 2s (repeat = 2)");
};

static HV *stash;

MODULE = My::EvTest  PACKAGE = My::EvTest
PROTOTYPES: ENABLE

BOOT:
{
    stash     = gv_stashpv ("My::EvTest"    , 1);
    I_EV_API ("My::EvTest");
}

void pass_loop_to_lib()
    CODE:
{
    ev_verify(EV_DEFAULT);
    printf("%s\n", "pass_loop_to_lib(): ev_verify OK!");

    ev_timer_init (&timeout_watcher, time_cb, 2, 2);
    ev_timer_start (EV_DEFAULT, &timeout_watcher);
    ev_verify(EV_DEFAULT);

    printf("%s\n", "pass_loop_to_lib(): ev_verify (2) OK!");

    test(EV_DEFAULT); // call ev_lib::test()
}

lib/My/EvTest.pm:

package My::EvTest;
use strict;
use warnings;
use Exporter qw(import);
our %EXPORT_TAGS = ( 'all' => [ qw(    ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(    );
our $VERSION = 0.01;
require XSLoader;

XSLoader::load();
1;

Makefile.PL:

use 5.020;
use strict;
use warnings;
use utf8;
use ExtUtils::MakeMaker 6.98; # for XSMULTI option
use EV::MakeMaker qw(ev_args);

WriteMakefile(ev_args(
  NAME          => 'My::EvTest',
  VERSION_FROM  => 'lib/My/EvTest.pm',
  PREREQ_PM     => { 'ExtUtils::MakeMaker' => '6.98' },
  ABSTRACT_FROM => 'lib/My/EvTest.pm',
  OPTIMIZE      => '-O2',
  LICENSE       => 'perl',
  LIBS          =>  ["-L./ev_lib -levmanager -lev"],
  INC           => '-I. -I/usr/include -I./ev_lib/'));

compile:

perl Makefile.PL
make -f Makefile

my perl script thats used module My::EvTest:

#!/usr/bin/perl -w

use FindBin 1.51 qw( $RealBin );

use strict;
use warnings;

use Devel::Peek;
use ExtUtils::testlib;

use EV;
use My::EvTest;

my $w = EV::timer 3, 3, sub
{
   warn "EV::timer (.pm): is called roughly every 3s (repeat = 3)";
};

my $loop = EV::default_loop;
Dump $loop;

My::EvTest::pass_loop_to_lib();

EV::run;

exit(0);

And i have this output:

➜ ./test_ev
SV = IV(0x9a8d30) at 0x9a8d40
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  RV = 0x9c6738
  SV = PVMG(0x99eb60) at 0x9c6738
    REFCNT = 3
    FLAGS = (OBJECT,IOK,pIOK)
    IV = 139812219366784
    NV = 0
    PV = 0
    STASH = 0xa03ad0    "EV::Loop"
pass_loop_to_lib(): ev_verify OK!
pass_loop_to_lib(): ev_verify (2) OK!
test
perl: ev.c:2848: ev_verify: Assertion «((loop)->anfdmax) >= 0» failed.
Aborted

What i doing wrong?

ikegami
  • 367,544
  • 15
  • 269
  • 518
Mjöllnir
  • 11
  • 2
  • *"ev_verify: Проверочное утверждение «((loop)->anfdmax) >= 0» не выполнено. Аварийный останов"* Could you translate the output to english? – Håkon Hægland Feb 28 '23 at 09:52
  • *"((loop)->anfdmax) >= 0"*: I belive the error comes from line 3625 (most recent version of ev.c) see: http://cvs.schmorp.de/libev/ev.c?revision=1.536&view=markup#l3625 – Håkon Hægland Feb 28 '23 at 10:01
  • updated: "perl: ev.c:2848: ev_verify: Assertion «((loop)->anfdmax) >= 0» failed. Aborted" – Mjöllnir Feb 28 '23 at 10:09
  • 1
    This is also on Reddit at https://www.reddit.com/r/perl/comments/11e1ojx/how_to_pass_evloop_object_to_your_c_library/ – user20284150 Feb 28 '23 at 11:48
  • *"ev_verify: Assertion «((loop)->anfdmax) >= 0» failed."* A wild guess about why this happens could be that the perl module `EV` uses a different shared object `libev.so` than `EvManager.c` does. Then the shared object that `EvManager.c` uses has not been initialized when you call `ev_verify()` .. – Håkon Hægland Feb 28 '23 at 13:39
  • Any reason why you would create a separate library `libevmanager.so` in addition to the `EvTest.so` library? If you could move all the logic in `EvManager.c` into `EvTest.xs` and just use `EvTest.so` I think you should be fine. – Håkon Hægland Feb 28 '23 at 14:00
  • i want to use amqp-cpp v4 in my libevmanager.so which supports ev_loop and integrate it into my perl program. EV.pm is compiled with libev as a static library. Maybe for this reason there is no access to the object after transfer to another library .. – Mjöllnir Feb 28 '23 at 14:25
  • *"EV.pm is compiled with libev as a static library"* : Actually it seems `libev` is included in the the distribution of the Perl module `EV` (there is no static library `libev.a`). It seems everything is compiled into the `EV.so` shared object using `ExtUtils::MakeMaker`, see: https://metacpan.org/release/MLEHMANN/EV-4.33/source/Makefile.PL#L413 – Håkon Hægland Feb 28 '23 at 14:34
  • 1
    *"i want to use amqp-cpp v4 in my libevmanager.so"* If you want to compile with the `libev` that is included in `EV.so`, you could use a similar approach as in `EV::MakeMaker`, see line 31: https://metacpan.org/release/MLEHMANN/EV-4.33/source/EV/MakeMaker.pm#L31. This is used to determine the correct location of `EV.so` and the header file `EVAPI.h` – Håkon Hægland Feb 28 '23 at 14:41
  • Re "*Actually it seems libev is included in the the distribution of the Perl module EV*", So this is probably a version or configuration incompatibility between the two builds – ikegami Mar 01 '23 at 15:26
  • I compiled my c library with using a similar approach as in EV::MakeMaker, call I_EV_API in function test() and it is working good, thank you very much! – Mjöllnir Mar 02 '23 at 09:02
  • @Mjöllnir Great to hear that you found a solution and that it is working! Would you mind writing an answer regarding the details of how to compile the library to make it work? ([You can answer your own question](https://stackoverflow.com/help/self-answer) when you get more than 15 reputation points, just click the button below) – Håkon Hægland Mar 02 '23 at 09:13

0 Answers0