IPC-Run

 view release on metacpan or  search on metacpan

Changelog  view on Meta::CPAN

 - GH #57 - Close external input handles in parent after fork to prevent
   hangs when child exits early (PR #226)
 - GH #134 - Preserve $cur_kid when a Timer is encountered in harness(),
   fixing "No command before 'init'" errors (PR #187)
 - GH #124 - Restore compat for bare undef params in harness() (PR #190)
 - GH #141 - Passing undef as stdin/stdout/stderr no longer dies (PR #184)
 - GH #139 - Avoid "Modification of a read-only value" when passing undef
   stdin (PR #185)
 - GH #162 - Reject empty/undef command name in _search_path (PR #182)
 - GH #154 - Limit input buffer chunk size to prevent exponential memory
   growth when streaming data to slow consumers (PR #183)
 - GH #128 - Silently ignore undef arguments passed as timeout to
   harness() (PR #189)
 - GH #133 - Correct two minor documentation issues in Run.pm (PR #188)
 - GH #137 - Skip win32_compile.t when getprotobyname('tcp') is
   unavailable (PR #186)
 - GH #35 - Survive SIGPIPE when child exits before consuming all stdin
   (PR #204)
 - GH #92 - Handle EPIPE when child exits before consuming stdin (PR #195)
 - GH #93 - Handle tied STDERR without FILENO in _debug_fd (PR #194)
 - GH #85 - Invalidate path cache on $PATH change, add clearcache()

Changelog  view on Meta::CPAN

 - GH #178 - Add env option to set child process environment variables
   without modifying parent %ENV (PR #179)
 - GH #171 - Add started() method to query harness run state (PR #180)
 - GH #169 - Add finished() method to distinguish exit-0 from
   not-yet-exited (PR #181)
 - GH #44 - Add pid(), pids(), is_running(), full_path(), full_paths()
   convenience methods (PR #203)
 - GH #64 - Add <blocking_pipe operator for blocking writes to child
   stdin (PR #200)
 - PR #212 - Add close_stdin() method to prevent unbounded memory growth
   when streaming to long-running children

 Maintenance:
 - GH #208 - Consolidate CI into single testsuite.yml with dynamic Perl
   version matrix (PR #209)
 - PR #220 - Add CLAUDE.md with project guidelines for AI-assisted
   development
 - Add 5-minute timeout to all CI workflow steps
 - GH #228 - Remove TODO from Win32 autoflush test and align with Unix
   branch (PR #234)
 - GH #223 - Clean up resolved TODO tests in win32_newlines.t (PR #227)

README.md  view on Meta::CPAN


    - close\_stdin

            $h->close_stdin;

        Closes the input pipe(s) to the child process(es), signaling EOF on
        the child's STDIN.  Does **not** wait for the child to finish or drain
        remaining output.  After calling this, the caller can continue to
        `pump()` to retrieve output incrementally.

        This is useful when streaming large amounts of data through a child
        process (e.g., decompression) where you want to signal end-of-input
        but continue draining output without buffering it all in memory:

            my ( $in, $out ) = ( '', '' );
            my $h = start \@cmd, \$in, \$out, timeout( 30 );

            while ( read_more_input_into( $in ) ) {
                $h->pump;
                process_output( $out ) if length $out;
                $out = '';

lib/IPC/Run.pm  view on Meta::CPAN


=item close_stdin

   $h->close_stdin;

Closes the input pipe(s) to the child process(es), signaling EOF on
the child's STDIN.  Does B<not> wait for the child to finish or drain
remaining output.  After calling this, the caller can continue to
C<pump()> to retrieve output incrementally.

This is useful when streaming large amounts of data through a child
process (e.g., decompression) where you want to signal end-of-input
but continue draining output without buffering it all in memory:

   my ( $in, $out ) = ( '', '' );
   my $h = start \@cmd, \$in, \$out, timeout( 30 );

   while ( read_more_input_into( $in ) ) {
       $h->pump;
       process_output( $out ) if length $out;
       $out = '';

t/close_stdin.t  view on Meta::CPAN

    $h->close_stdin;

    while ( $h->pumpable ) {
        $h->pump;
    }
    $h->finish;

    is( $out, "PIPELINE TEST$nl", "close_stdin works with pipelines" );
}

## Test 8: close_stdin with multi-line streaming pattern
{
    my @counter = ( $^X, '-e', '
        $| = 1;
        my $count = 0;
        while (<STDIN>) {
            $count++;
            print "line $count\n";
        }
        print "total: $count\n";
    ' );

t/input_buffer_growth.t  view on Meta::CPAN

    # And $in must have been reduced at all (one chunk was written).
    cmp_ok( $remaining, '<', $total,
        'GH#154: pump_nb did consume some data from $in' );

    $in = '';    # clear before finish so the child sees EOF
    $h->finish;
}

## Test 3: All data arrives correctly when fed in large chunks.
##
## Verifies the fix does not lose or corrupt data when streaming
## more than chunk_size bytes through start/pump.
{
    my ( $in, $out ) = ( '', '' );
    my $h = start( \@passthrough, \$in, \$out, timeout(30) );

    my $chunk_size   = 65536;
    my $num_chunks   = 5;
    my $expected_len = $chunk_size * $num_chunks;    # 327680 bytes

    $in = 'B' x $expected_len;
    pump $h until !length($in);    # pump until all input consumed

    $h->finish;

    is( length($out), $expected_len,
        'GH#154: all data transmitted correctly over multiple chunks' );
}

## Test 4: Incremental streaming keeps $in bounded.
##
## Simulates the original bug scenario: user appends small chunks to $in
## on each pump_nb call.  With the fix, $in should stay bounded because
## the filter drains it in 65536-byte chunks.  Without the fix, $in would
## grow to the total data size before being flushed all at once.
{
    my ( $in, $out ) = ( '', '' );
    my $h = start( \@passthrough, \$in, \$out, timeout(30) );

    my $chunk_size   = 65536;



( run in 0.659 second using v1.01-cache-2.11-cpan-140bd7fdf52 )