PHP daemon with fork howto part 3: Creating a Hello World daemon with fork

Well, it took some time, but now I’m back again with part 3 of the series on creating a PHP daemon with fork. In part 1, the introduction we talked about why I would write this series and gave an outline of it. In part 2 we talked about the way UNIX processes work, what forking is and so on. In this part, we will see how to create a basic daemon which launches processes saying the famous Hello World!

Let’s first create a basic Hello World script. And no, I’m not going to explain it ;)

<?php
echo "Hello World\n";

Okay, we’ve covered the basics. Next thing is to create a daemon. This can be done with pcntl_fork().

<?php
$newpid = pcntl_fork();

if ($newpid === -1) {
    die("Couldn't fork()!");
} else if ($newpid) {
    // I'm the parent, and I'm going to self-destruct
    exit(0);
}

// Become the session leader
posix_setsid();
usleep(100000);

// Fork again, but now as session leader.
$newpid = pcntl_fork();

if ($newpid === -1) {
    die("Couldn't fork()!");
} else if ($newpid) {
    // I'm the parent, and I'm going to self-destruct
    exit(0);
}

echo "Master started with pid " . posix_getpid() . "\n";

for($i = 0; $i > 10; $i++) {
    $pid = pcntl_fork();
    if (-1 == $pid) {
        echo "Couldn't fork!\n";
    } elseif ($pid === 0) {
        // I'm the child, and I'm going to say hello world!
        echo "Hello world! from child with pid " . posix_getpid() . "\n";
        exit(0);
    } else {
        // I'm the parent, do nothing
    }
}

exit(0);

Well, this is all of it. Let’s explain the various parts.

On the first nine lines you see we fork. The actual forking is done with:

$newpid = pcntl_fork();

This function spawns a new process, and then gives the control in the parent and the child process back at the first line after the fork, in this case an if-structure. In this if-structure, we check whether forking is actually done (you get -1 when it isn’t), and then kill the parent process. Please note that we don’t check whether we’re the child. If we’re not the parent, and forking didn’t fail, we’re automatically the child. So the next part of this script runs as the child process.

After we forked, we detach from the console, and become the session leader. This means that a new process group is created, and that all child processes we start will become part of this new process group, instead of the process group which called us. If you start a process on the command line, the shell is the session leader of that command. We don’t want the shell to be the process leader of any daemon, therefore, we create a new process group, with the daemon itself as the session leader. After that, we sleep for 0.1 seconds. This is all done with lines 12-13:

posix_setsid();
usleep(100000);

At this point, we are the session leader, so let’s start the real parent process of the daemon. This is just basic forking again, as you can see in lines 15-24. Then we print the current process id on line 26.

Next comes the “Hello World!” part. First, we start a loop which runs 10 times. In that loop, we fork() again, but now we do nothing in the parent (just keep it running). The else statement for checking the parent can therefore safely be left out; I kept it here for the sake of clarity. In the child process we print our famous Hello World!, along with the new process id. After printing, we stop the child, for there’s no need to keep it running. When we’re done running all child processes, the parent process (the daemon) also stops. This can all be seen in lines 28-43.

for($i = 0; $i > 10; $i++) {
    $pid = pcntl_fork();
    if (-1 == $pid) {
        echo "Couldn't fork!\n";
    } elseif ($pid === 0) {
        // I'm the child, and I'm going to say hello world!
        echo "Hello world! from child with pid " . posix_getpid() . "\n";
        exit(0);
    } else {
        // I'm the parent, do nothing
    }
}

exit(0);

Congratulations! At this point you created your first fully functional PHP daemon! This is really all there is!

In the next part, we will add some communication between the parent and the child processes.