Sometimes, when we use fork to create one or more child-processes we would like to know if the child process has stopped working or if it is still alive.

Normally we use wait or waitpid to notice when a child process has finished. The problem with that these functions will wait, and block our execution till the child process stops working.

What if we would like to do something while the child is still running but stop doing it when the child has finished?

In a nutshell, calling waitpid() with the process ID of the child process and with the WNOHANG flag imported from the POSIX module is a non-blocking call. It will return immediately, without waiting for the child to stop working.

It will return a status code which is the actual process id we passed to it ($pid) if the child has already stopped running. the status code is -1 in case of some failure and it is 0 if the child is still running.

The actual exit code of the child process is saved in the high byte of $?.

A very simple usage would look like this:

use POSIX ":sys_wait_h";

my $res = waitpid($pid, WNOHANG);

Example

use strict;
use warnings;
use 5.010;

use POSIX ":sys_wait_h";
use Time::HiRes qw(sleep);

my $pid = fork();
die "Could not fork\n" if not defined $pid;

if (not $pid) {
    say "In child";
    sleep 1;
    exit 3;
}

say "In parent of $pid";
while (1) {
    my $res = waitpid($pid, WNOHANG);
    say "Res: $res";
    sleep(0.1);

    if ($res == -1) {
        say "Some error occurred ", $? >> 8;
        exit();
    }
    if ($res) {
        say "Child $res ended with ", $? >> 8;
        last;
    }
}

say "about to wait()";
say wait();
say "wait() done";

In this example we create a single child process that will sleep for one second and then exit with exit code 3. (Just an arbitrary number to show how it works.)

In the meantime the parent process enters an infinite while-loop and checks if the process is still running every 0.1 seconds. (We use the sleep function of Time::HiRes for this.)

If the result is -1, there was some error.

If the result is some other non-null number then the child process has finished. We print the content of $res which is supposed to be the same as $pid, and the content of $? shifted 8 bit to the right. That is we print the high-byte of $? which is the exit code of the child process. (The number 3 we used for the demonstrations.)

Lastly, we can see that if we call wait() after exiting the while-loop, it won't block as there are no more running child processes.

The output:

In parent of 15469
Res: 0
In child
Res: 0
Res: 0
Res: 0
Res: 0
Res: 0
Res: 0
Res: 0
Res: 0
Res: 0
Res: 15469
Child 15469 ended with 3
about to wait()
-1
wait() done