Jacob Kiers - php-fork-seriesZola2008-12-24T00:00:00+00:00https://jacobkiers.net/tags/php-fork-series/atom.xmlPHP daemon with fork howto part 3: Creating a Hello World daemon with fork2008-12-24T00:00:00+00:002008-12-24T00:00:00+00:00Unknownhttps://jacobkiers.net/post/php-daemon-with-fork-howto-part-3-creating-a-hello-world-daemon-with-fork/<p>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 <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-1-introduction/">part 1, the introduction</a>
I talked about why I would write this series and gave an outline of it.
In part 2 we talked <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-2-about-unix-processes-and-php/">about the way UNIX processes work, what forking is</a>
and so on. In this part, we will see how to <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-3-creating-a-hello-world-daemon-with-fork/">create daemon in PHP</a>
which launches processes saying the famous Hello World!</p>
<p>Let’s first create a basic Hello World script. And no, I’m not going to
explain that 😏</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php
</span><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Hello World</span><span style="color:#96b5b4;">\n</span><span>";
</span></code></pre>
<p>Okay, we’ve covered the basics. Next thing is to create a daemon. This can
be done with <a rel="nofollow noreferrer" href="https://www.php.net/pcntl_fork"><code>pcntl_fork()</code></a>.</p>
<pre data-linenos data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><table><tbody><tr><td>1</td><td><span style="color:#ab7967;"><?php
</span></td></tr><tr><td>2</td><td><span>$</span><span style="color:#bf616a;">newpid </span><span>= </span><span style="color:#96b5b4;">pcntl_fork</span><span>();
</span></td></tr><tr><td>3</td><td><span>
</span></td></tr><tr><td>4</td><td><span style="color:#b48ead;">if </span><span>($</span><span style="color:#bf616a;">newpid </span><span>=== -</span><span style="color:#d08770;">1</span><span>) {
</span></td></tr><tr><td>5</td><td><span> </span><span style="color:#b48ead;">die</span><span>("</span><span style="color:#a3be8c;">Couldn't fork()!</span><span>");
</span></td></tr><tr><td>6</td><td><span>} </span><span style="color:#b48ead;">else if </span><span>($</span><span style="color:#bf616a;">newpid</span><span>) {
</span></td></tr><tr><td>7</td><td><span> </span><span style="color:#65737e;">// I'm the parent, and I'm going to self-destruct
</span></td></tr><tr><td>8</td><td><span> </span><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span></td></tr><tr><td>9</td><td><span>}
</span></td></tr><tr><td>10</td><td><span>
</span></td></tr><tr><td>11</td><td><span style="color:#65737e;">// Become the session leader
</span></td></tr><tr><td>12</td><td><span style="color:#96b5b4;">posix_setsid</span><span>();
</span></td></tr><tr><td>13</td><td><span style="color:#96b5b4;">usleep</span><span>(</span><span style="color:#d08770;">100000</span><span>);
</span></td></tr><tr><td>14</td><td><span>
</span></td></tr><tr><td>15</td><td><span style="color:#65737e;">// Fork again, but now as session leader.
</span></td></tr><tr><td>16</td><td><span>$</span><span style="color:#bf616a;">newpid </span><span>= </span><span style="color:#96b5b4;">pcntl_fork</span><span>();
</span></td></tr><tr><td>17</td><td><span>
</span></td></tr><tr><td>18</td><td><span style="color:#b48ead;">if </span><span>($</span><span style="color:#bf616a;">newpid </span><span>=== -</span><span style="color:#d08770;">1</span><span>) {
</span></td></tr><tr><td>19</td><td><span> </span><span style="color:#b48ead;">die</span><span>("</span><span style="color:#a3be8c;">Couldn't fork()!</span><span>");
</span></td></tr><tr><td>20</td><td><span>} </span><span style="color:#b48ead;">else if </span><span>($</span><span style="color:#bf616a;">newpid</span><span>) {
</span></td></tr><tr><td>21</td><td><span> </span><span style="color:#65737e;">// I'm the parent, and I'm going to self-destruct
</span></td></tr><tr><td>22</td><td><span> </span><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span></td></tr><tr><td>23</td><td><span>}
</span></td></tr><tr><td>24</td><td><span>
</span></td></tr><tr><td>25</td><td><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Master started with pid </span><span>" . </span><span style="color:#96b5b4;">posix_getpid</span><span>() . "</span><span style="color:#96b5b4;">\n</span><span>";
</span></td></tr><tr><td>26</td><td><span>
</span></td></tr><tr><td>27</td><td><span style="color:#b48ead;">for</span><span>($</span><span style="color:#bf616a;">i </span><span>= </span><span style="color:#d08770;">0</span><span>; $</span><span style="color:#bf616a;">i </span><span>> </span><span style="color:#d08770;">10</span><span>; $</span><span style="color:#bf616a;">i</span><span>++) {
</span></td></tr><tr><td>28</td><td><span> $</span><span style="color:#bf616a;">pid </span><span>= </span><span style="color:#96b5b4;">pcntl_fork</span><span>();
</span></td></tr><tr><td>29</td><td><span> </span><span style="color:#b48ead;">if </span><span>(-</span><span style="color:#d08770;">1 </span><span>== $</span><span style="color:#bf616a;">pid</span><span>) {
</span></td></tr><tr><td>30</td><td><span> </span><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Couldn't fork!</span><span style="color:#96b5b4;">\n</span><span>";
</span></td></tr><tr><td>31</td><td><span> } </span><span style="color:#b48ead;">elseif </span><span>($</span><span style="color:#bf616a;">pid </span><span>=== </span><span style="color:#d08770;">0</span><span>) {
</span></td></tr><tr><td>32</td><td><span> </span><span style="color:#65737e;">// I'm the child, and I'm going to say hello world!
</span></td></tr><tr><td>33</td><td><span> </span><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Hello world! from child with pid </span><span>" . </span><span style="color:#96b5b4;">posix_getpid</span><span>() . "</span><span style="color:#96b5b4;">\n</span><span>";
</span></td></tr><tr><td>34</td><td><span> </span><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span></td></tr><tr><td>35</td><td><span> } </span><span style="color:#b48ead;">else </span><span>{
</span></td></tr><tr><td>36</td><td><span> </span><span style="color:#65737e;">// I'm the parent, do nothing
</span></td></tr><tr><td>37</td><td><span> }
</span></td></tr><tr><td>38</td><td><span>}
</span></td></tr><tr><td>39</td><td><span>
</span></td></tr><tr><td>40</td><td><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span></td></tr></tbody></table></code></pre>
<p>Well, this is all of it. Let’s explain the various parts.</p>
<p>In the first nine lines we fork. The actual forking is done with:</p>
<p><code>$newpid = pcntl_fork();</code>.</p>
<p>This function spawns a new process, and then continues both in the parent
and the child process at the first line after the fork (line 4). Usually,
that will be an if-else clause. This if-else clause checks whether the
forking was successful. If it was not, the return value will be <code>-1</code>.</p>
<p>If it was successful, the parent process kills itself (lines 6-9). Note
that after that there is no check whether the child process is running.
That is not necessary: if the current process is not the parent, and
forking did not fail, then by default it is the child. So the next part of
this script runs as the child process.</p>
<p>After forking, the script detaches from the console, and become the session
leader. This means that a new process group is created, and that all child
processes that might be started from now on will become part of this new
process group, and not of the process group that started the script.</p>
<p>When a process is started on the command line, then the shell is the session
leader of that command. That is not very useful for a deamon, because when the
session leaders stops, then all the child processes will be killed as well.
Therefore, a new process group is created, with the daemon itself as the
session leader.</p>
<p>After that, we sleep for 0.1 seconds. This is all done on lines 12 and 13:</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span>posix_setsid();
</span><span>usleep(100000);
</span></code></pre>
<p>At this point, the executing script is now the session leader of its own
process group. So it is time to start the real parent process of the daemon.
This is just basic forking again, as you can see in lines 15-23. After that,
the current process id is printed on line 25.</p>
<p>By forking again, the script becomes totally detached from the context from
which it was called, in this case probably the shell. This is a technique
called double-forking, and it is necessary to make a long-running daemon
completely independent.</p>
<p>Next comes the <code>Hello World!</code> part. First a loop is started with 10 iterations.
In that loop, the script is <code>fork()</code>ed again, but now we do nothing in the
parent (it just keeps running). So the else statement for checking the parent
could safely be left out; I kept it here for the sake of clarity.</p>
<p>In the child process the famous <code>Hello World!</code> is printed, along with the
new process id. After printing, we stop the child, for there’s no need to
keep it around any longer. When all child processes are done running, then
parent process (the daemon) also stops. This can all be seen in lines 27-40.</p>
<pre data-lang="php" style="background-color:#2b303b;color:#c0c5ce;" class="language-php "><code class="language-php" data-lang="php"><span style="color:#ab7967;"><?php
</span><span style="color:#b48ead;">for</span><span>($</span><span style="color:#bf616a;">i </span><span>= </span><span style="color:#d08770;">0</span><span>; $</span><span style="color:#bf616a;">i </span><span>> </span><span style="color:#d08770;">10</span><span>; $</span><span style="color:#bf616a;">i</span><span>++) {
</span><span> $</span><span style="color:#bf616a;">pid </span><span>= </span><span style="color:#96b5b4;">pcntl_fork</span><span>();
</span><span> </span><span style="color:#b48ead;">if </span><span>(-</span><span style="color:#d08770;">1 </span><span>== $</span><span style="color:#bf616a;">pid</span><span>) {
</span><span> </span><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Couldn't fork!</span><span style="color:#96b5b4;">\n</span><span>";
</span><span> } </span><span style="color:#b48ead;">elseif </span><span>($</span><span style="color:#bf616a;">pid </span><span>=== </span><span style="color:#d08770;">0</span><span>) {
</span><span> </span><span style="color:#65737e;">// I'm the child, and I'm going to say hello world!
</span><span> </span><span style="color:#96b5b4;">echo </span><span>"</span><span style="color:#a3be8c;">Hello world! from child with pid </span><span>" . </span><span style="color:#96b5b4;">posix_getpid</span><span>() . "</span><span style="color:#96b5b4;">\n</span><span>";
</span><span> </span><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span><span> } </span><span style="color:#b48ead;">else </span><span>{
</span><span> </span><span style="color:#65737e;">// I'm the parent, do nothing
</span><span> }
</span><span>}
</span><span>
</span><span style="color:#b48ead;">exit</span><span>(</span><span style="color:#d08770;">0</span><span>);
</span></code></pre>
<p>Congratulations! This is all there is to it. At this point you created your first fully functional PHP
daemon 🚀</p>
<p>In the next part, we will add some communication between the parent and the child processes.</p>
PHP daemon with fork howto part 2: About UNIX processes and PHP2008-10-17T00:00:00+00:002008-10-17T00:00:00+00:00Unknownhttps://jacobkiers.net/post/php-daemon-with-fork-howto-part-2-about-unix-processes-and-php/<p>As promised in <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-1-introduction/">part 1, the introduction</a> of this series on PHP fork,
now we will talk about the way processes work in UNIX and Linux, and how we
can use these from PHP.</p>
<p>Much of the information in this article is based on the IBM Developerworks
article on <a rel="nofollow noreferrer" href="https://web.archive.org/web/20080529064539/http://www.ibm.com/developerworks/aix/library/au-speakingunix8/">UNIX Processes</a>. I added this part for
your convenience and for completeness, but I won’t go into detail about
UNIX processes. If you want to know more, read the aforementioned article.</p>
<p>Any program in UNIX is a process, except for the kernel. A program is in
fact a bunch of data, with some instructions to do something with that data.
A process tells when and how these instructions should be executed.</p>
<p>Each process has its own and unique (at that point in time) process id. It
is impossible for two processes to have the same process id at the same time.
It is, however, possible that some process id is assigned to another process.
This only happens when the counter for process id’s runs out of space, and is
reset, so that it starts with process id 2 (for process id 1 one never ever
stops as long as the system is running).</p>
<p>So, when a new process is launched, that process will get its own, unique
process id, which is an identifier in the whole system. Furthermore, the
process id is used to identify all resources in use by that process. A
resource can be defined as anything which is needed to run, such as memory,
disk space, a network socket, open files such as logfiles or input/output
files and anything else you can think of.</p>
<p>This also means that each PHP program or script you are running, has its own
process id, with the possible exception of the PHP scripts running inside a
webserver process, like Apache httpd sometimes does.</p>
<p>Spawning a new process is done by calling the <code>fork(1)</code> system call, which
returns one of three values:</p>
<ul>
<li>In the calling process, when successful, the process id of the child.</li>
<li>In the calling process, <code>-1</code> when something went wrong.</li>
<li>In the child process: always <code>0</code>.</li>
</ul>
<p>Using this knowledge, we can check whether we are in the parent or in the
child process, and act appropriately.</p>
<p>More on that in the <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-3-creating-a-hello-world-daemon-with-fork/">next part</a> of this series. There we will create a <a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-3-creating-a-hello-world-daemon-with-fork/">PHP
daemon</a>, which will start processes for the sole purpose of saying Hello
World multiple times.</p>
PHP daemon with fork howto part 1: Introduction2008-10-16T00:00:00+00:002008-10-16T00:00:00+00:00Unknownhttps://jacobkiers.net/post/php-daemon-with-fork-howto-part-1-introduction/<p>In the past weeks, I have been writing a daemon in PHP for my work at Alphacomm.
It now is quite finished, and I decided to share this knowledge with you in a tutorial.</p>
<p>Another reason for writing this tutorial, is the lack of information
available at the web on this subject. Generally, it’s very scattered
and not really accessible. Also, most information I found about it,
talked about a specific solution, rather than taking a more general
approach. So, I decided to write a howto in a series of articles on
PHP <code>fork()</code>-ing and daemons. I expect to add another part each week.</p>
<p>In this series, I will cover the following subjects:</p>
<ol>
<li><a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-1-introduction/">Part 1: An introduction to this series, links to all parts</a></li>
<li><a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-2-about-unix-processes-and-php/">Part 2: About UNIX processes and PHP</a></li>
<li><a href="https://jacobkiers.net/post/php-daemon-with-fork-howto-part-3-creating-a-hello-world-daemon-with-fork/">Part 3: Creating a Hello World daemon with fork()</a></li>
<li>Part 4: Adding IPC (Inter Process Communication) with PHP sockets</li>
<li>Part 5: Talking to the outer world (also with PHP sockets)</li>
<li>Part 6: Errata and other stuff (not sure of this one)</li>
</ol>
<p>Disclaimer: these can change ;)</p>
<p>At last, I’d like to thank the guys who wrote <a rel="nofollow noreferrer" href="https://web.archive.org/web/20081012102826/http://nanoweb.si.kz/">Nanoweb</a>, which really helped me to understand the whole process of creating and managing processes with PHP fork(). However, if you ever plan to actually read that sourcecode yourself, be warned. It is not for the faint-hearted.</p>