Proc::Fork(3pm)

πŸ“¦
version 0.807 Β· 4 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Proc::Fork πŸ’–

okay so bestie, welcome to Proc::Fork β€” it's a Perl module from the User Contributed Perl Documentation crew, and it's literally the cutest, most intuitive interface to the fork() system call you're ever gonna meet ✨ no cap.


🌸 NAME 🌸

Proc::Fork β€” a simple, intuitive interface to the fork() system call, and yes it's giving exactly what it says on the tin πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

use Proc::Fork;

run_fork {
    child {
        # child code goes here.
    }
    parent {
        my $child_pid = shift;
        # parent code goes here.
        waitpid $child_pid, 0;
    }
    retry {
        my $attempts = shift;
        # what to do if fork() fails:
        # return true to try again, false to abort
        return if $attempts > 5;
        sleep 1, return 1;
    }
    error {
        # Error-handling code goes here
        # (fork() failed and the retry block returned false)
    }
};

like, look at it. gorgeous. flawless. we stan 🫢


πŸ¦‹ DESCRIPTION πŸ¦‹

so this module gives you a very Perl-ish, very intuitive way to write forking programs β€” you literally use blocks to show which chunk of code runs in which fork. the parent code, the child code, the retry handler, and the error handler all live together inside one "fork block". the clauses can show up in any order you want, but they have to be consecutive β€” no sneaking other statements in between, bestie, i'm serious πŸ™ˆ

and listen, you don't need all four clauses. nope. not required:

  • no retry clause? then only one fork attempt happens, periodt.
  • no error clause? the program will die with a simple message if it can't retry.
  • no parent or child clause? then whichever one you left out just starts executing after the final clause. so if one side only has to do something simple, you literally only describe that one side. iconic, honestly.

example time:

# spawn off a child process to do some simple processing
run_fork { child {
    exec '/bin/ls', '-l';
    die "Couldn't exec ls: $!\n";
} };
# Parent will continue execution from here
# ...

and if the code inside any of the clauses doesn't die or exit, it'll just keep going after the fork block. no drama πŸ’…


⭐ INTERFACE ⭐

all of these functions are exported by default, so you get them for free:

🌈 run_fork

run_fork { ... }

does the actual fork operation configured in its block. main character energy πŸ”₯

πŸ’œ child

child { ... }

declares the block that runs in the child process.

🌸 parent

parent { ... }

declares the block that runs in the parent process. the child's PID gets passed to the block as an argument, so you can waitpid on it like a good parent πŸ₯Ί

✨ retry

retry { ... }

declares the block that runs in case of an error β€” i.e. when fork returned undef. if the code returns true, another fork gets attempted. the number of fork attempts so far is passed as an argument to the block.

this is how you do the whole wait-and-retry thing that some apps (looking at you, daemons πŸ‘€) genuinely need.

and if you don't use a retry clause at all? no retries, bestie β€” a fork failure goes straight to the error clause.

🧚 error

error { ... }

declares the block that runs if there's an error β€” meaning fork returned undef and the retry clause returned false. the number of forks attempted is passed as an argument to the block.

if you don't use an error clause, errors raise an exception via die. dramatic but valid πŸ’€


πŸ”₯ EXAMPLES πŸ”₯

the distribution ships the following examples as separate files in the eg/ directory:

πŸ“ Simple example with IPC via pipe

use strict;
use Proc::Fork;

use IO::Pipe;
my $p = IO::Pipe->new;

run_fork {
    parent {
        my $child = shift;
        $p->reader;
        print while <$p>;
        waitpid $child,0;
    }
    child {
        $p->writer;
        print $p "Line 1\n";
        print $p "Line 2\n";
        exit;
    }
    retry {
        if( $_[0] < 5 ) {
            sleep 1;
            return 1;
        }
        return 0;
    }
    error {
        die "That's all folks\n";
    }
};

πŸ’– Multi-child example

use strict;
use Proc::Fork;
use IO::Pipe;

my $num_children = 5;    # How many children we'll create
my @children;            # Store connections to them
$SIG{CHLD} = 'IGNORE';   # Don't worry about reaping zombies

# Spawn off some children
for my $num ( 1 .. $num_children ) {
    # Create a pipe for parent-child communication
    my $pipe = IO::Pipe->new;

    # Child simply echoes data it receives, until EOF
    run_fork { child {
        $pipe->reader;
        my $data;
        while ( $data = <$pipe> ) {
            chomp $data;
            print STDERR "child $num: [$data]\n";
        }
        exit;
    } };

    # Parent here
    $pipe->writer;
    push @children, $pipe;
}

# Send some data to the kids
for ( 1 .. 20 ) {
    # pick a child at random
    my $num = int rand $num_children;
    my $child = $children[$num];
    print $child "Hey there.\n";
}

πŸ‘‘ Daemon example

use strict;
use Proc::Fork;
use POSIX;

# One-stop shopping: fork, die on error, parent process exits.
run_fork { parent { exit } };

# Other daemon initialization activities.
$SIG{INT} = $SIG{TERM} = $SIG{HUP} = $SIG{PIPE} = \&some_signal_handler;
POSIX::setsid() == -1 and die "Cannot start a new session: $!\n";
close $_ for *STDIN, *STDOUT, *STDERR;

# rest of daemon program follows

πŸ¦‹ Forking socket-based network server example

use strict;
use IO::Socket::INET;
use Proc::Fork;

$SIG{CHLD} = 'IGNORE';

my $server = IO::Socket::INET->new(
    LocalPort => 7111,
    Type      => SOCK_STREAM,
    Reuse     => 1,
    Listen    => 10,
) or die "Couln't start server: $!\n";

my $client;
while ($client = $server->accept) {
    run_fork { child {
        # Service the socket
        sleep(10);
        print $client "Ooga! ", time % 1000, "\n";
        exit; # child exits. Parent loops to accept another connection.
    } }
}

πŸ’… AUTHOR πŸ’…

Aristotle Pagaltzis <pagaltzis@gmx.de>

Documentation by Eric J. Roode.


This documentation is copyright (c) 2002 by Eric J. Roode.

This software is copyright (c) 2018 by Aristotle Pagaltzis.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. slay πŸ’–


and that's the whole vibe check bestie β€” brought to you by perl v5.34.0, dated 2022-08-12, the iconic Proc::Fork(3pm) era ✨🫢 go forth and fork responsibly πŸ’œ

πŸ“¦ where this page comes from