This queue is for tickets about the Future-AsyncAwait CPAN distribution.

Report information
The Basics
Id:
123062
Status:
resolved
Priority:
Low/Low

People
Owner:
Nobody in particular
Requestors:
tynovsky [...] avast.com
Cc:
AdminCc:

BugTracker
Severity:
(no value)
Broken in:
(no value)
Fixed in:
0.16



Subject: AsyncAwait and LibXML
Date: Sun, 17 Sep 2017 09:10:53 +0200
To: bug-Future-AsyncAwait@rt.cpan.org
From: "Týnovský, Miroslav" <tynovsky@avast.com>
Hi,

First of all, thanks for all the great work. I discovered a strange (buggy) behaviour when using Future::AsyncAwait together with XML::LibXML. Particularly, my program exits with error code 0 in the middle of execution.

I'm using:

Future::AsyncAwait 0.10
XML::LibXML 2.0128
perl v5.24.0

Steps to reproduce:

1. Run the following program

    #!/usr/bin/env perl

    use strict;
    use warnings;

    use XML::LibXML;
    use IO::Async::Timer::Periodic;
    use IO::Async::Loop;
    use Future::AsyncAwait;
    use Test::More;

    my @futures;
    my $loop = IO::Async::Loop->new;

    run();

    my $timer = IO::Async::Timer::Periodic->new(
        interval => 1,
        on_tick => sub {
            while (my $f = shift @futures) {
                $f->done(1)
            }
        },
    );

    $loop->add($timer);
    $timer->start();

    $loop->run();

    async sub run {
        await f1();
        print "f1\n";

        await f2();
        print "f2\n";

        $loop->stop();
        pass();
        done_testing();
    }

    async sub f1 {
        await new_future();
        my $return = 1;

        return $return
    }

    sub f2 {
        return new_future();
    }

    sub new_future {
        # XML::LibXML->load_xml(string => '<a />');

        my $f = $loop->new_future();
        push @futures, $f;

        return $f
    }

You should see the following output:

    f1
    f2
    ok 1
    1..1


2. Now uncomment the line which is commented out

    XML::LibXML->load_xml(string => '<a />');

and execute again.

Now the output is incomplete - part of the program didn't get executed:

    f1

And the program still exited with exitcode 0.

3. Execute again with environment PERL_FUTURE_DEBUG=1 set. It works properly again.

4. Also note that f1 needs to contain await in order to reproduce the bug.


I have no guess about the cause. Let me know if I can provide any more details you potentially need.


Thank you,
Miroslav
It's not only XML::LibXML. Another line which breaks the program is HTTP::Tiny->get('http://www.metacpan.org'); I suspect there will be many others. I keep trying to find the simplest case.
On Sun Sep 17 03:11:45 2017, tynovsky@avast.com wrote:
Show quoted text
> You should see the following output: > > f1 > f2 > ok 1 > 1..1
Mine stops at f1 even unmodified. However, I see a potential reason here. Line 15 calls simply run(); without storing the returned Future anywhere. That's not going to go well. Saving it as my $f = run(); doesn't appear to help though. This program does seem a little confused though, as it's managing the IO::Async loop using ->run as well as working with toplevel Futures. I wonder if that's related. In any case this is all before I uncomment the line about XML::LibXML so I don't think that's related. -- Paul Evans
I now have a rather smaller test case - see attached -- Paul Evans
Subject: rt123062.pl
#!/usr/bin/env perl use strict; use warnings; use Future::AsyncAwait; use IO::Async::Loop; use IO::Async::Timer::Periodic; my $loop = IO::Async::Loop->new; my @futures; $loop->add( IO::Async::Timer::Periodic->new( interval => 1, on_tick => sub { while (my $f = shift @futures) { $f->done(1) } }, )->start ); run()->get; async sub run { await new_future(); print "f1\n"; await f2(); print "f2\n"; } async sub f1 { await new_future(); } sub f2 { return new_future(); } sub new_future { my $f = $loop->new_future(); push @futures, $f; return $f }
On Thu Jan 18 21:58:58 2018, PEVANS wrote:
Show quoted text
> I now have a rather smaller test case - see attached
Curiously, this test case fails alone but passes with PERL_FUTURE_DEBUG=1: $ perl rt123062.pl f1 $ PERL_FUTURE_DEBUG=1 perl rt123062.pl f1 f2 It also passes if you change line 26: - await f1(); + await new_future(); Clearly something quite subtle going on here -- Paul Evans
Well now this is just getting stranger. By adding an END { print "END\n"; } to the program, it prints in both cases, thus showing it to be a fairly controlled termination by perl, and not say a silent variation of a SEGV. Also the exit code is zero in both cases. By careful division down of the various effects of PERL_FUTURE_DEBUG I have narrowed it down to a single line in Future.pm: 376 $self->{ready_at} = _shortmess $_[0] if DEBUG; by making that line unconditionally execute, the test program now always passes. It seems that this line has the odd side-effect of causing it not to exit prematurely. -- Paul Evans
Almost certainly somehow related to https://rt.cpan.org/Ticket/Display.html?id=126037 -- Paul Evans
On Thu Jan 03 10:28:22 2019, PEVANS wrote:
Show quoted text
> Almost certainly somehow related to > > https://rt.cpan.org/Ticket/Display.html?id=126037
Yup. It was. With RT126037 fixed, this one is now working too: leo@shy:~/src/perl/Future-AsyncAwait [bzr] $ perl -Mblib rt123062.pl ENTER get() f1 ENTER f2() f2 EOF END leo@shy:~/src/perl/Future-AsyncAwait [bzr] $ PERL_FUTURE_DEBUG=1 perl -Mblib rt123062.pl ENTER get() f1 ENTER f2() f2 EOF END -- Paul Evans
Released in 0.16 -- Paul Evans


This service runs on Request Tracker, is sponsored by The Perl Foundation, and maintained by Best Practical Solutions.

Please report any issues with rt.cpan.org to rt-cpan-admin@bestpractical.com.