📄 living_without_forks.html
字号:
<span class="kw1">while</span> <span class="br0">(</span><span class="br0">(</span>wpid = wait<span class="br0">(</span>&stat<span class="br0">)</span><span class="br0">)</span> != pid<span class="br0">)</span> <span class="kw1">if</span> <span class="br0">(</span>wpid == <span class="nu0">-1</span> && errno == ECHILD<span class="br0">)</span> <span class="br0">{</span> <span class="coMULTI">/* see wait(2) manpage */</span> stat = <span class="nu0">0</span>; <span class="kw2">break</span>; <span class="br0">}</span> <span class="br0">}</span> <span class="br0">}</span> <span class="kw1">else</span> <span class="kw1">if</span><span class="br0">(</span>pid < <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// error in vfork caught here</span> err<span class="br0">(</span><span class="st0">"fork of rc shell failed<span class="es0">\n</span>"</span><span class="br0">)</span>; stat = <span class="nu0">-1</span>; <span class="br0">}</span> st = WEXITSTATUS<span class="br0">(</span>stat<span class="br0">)</span>; <span class="kw1">return</span> st;<span class="br0">}</span> </pre><p>The <strong>inetd</strong> internet daemon is given the task of monitoring a number of internet sockets and waiting ofr a connection on one of them. When a connection is established the daemon has to fork a new process to handle the connection. The <strong>/etc/inetd.conf</strong> file contains details of the ports to be monotired and the programs used to handle incoming connections.</p><p> Example /etc/inetd.conf file </p><pre class="code"></pre><p>Having extablished a connection attepmt on a designated port the daemon is required to start executing the handler task for that connection. The complication here is that the child has to have the incoming socket as its <strong>stdin</strong> and <strong>stdout</strong> devices.</p><p>The incoming port (<strong>fd</strong> in this case ) is transferred to <strong>stdin</strong> and <strong>stdout</strong> of the new task after the vfork.</p><p>Here is a code example showing this.</p><pre class="code c"> <span class="co1">// here fd is the incoming socket</span><span class="kw4">static</span> pid_tstart_child<span class="br0">(</span><span class="kw4">struct</span> stService *p, <span class="kw4">int</span> fd<span class="br0">)</span><span class="br0">{</span> pid_t pid; pid = vfork<span class="br0">(</span><span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>pid == <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// if we are the child</span> <span class="kw1">if</span> <span class="br0">(</span>fd != <span class="nu0">0</span><span class="br0">)</span> dup2<span class="br0">(</span>fd, <span class="nu0">0</span><span class="br0">)</span>; <span class="co1">// fd becomes stdin</span> <span class="kw1">if</span> <span class="br0">(</span>fd != <span class="nu0">1</span><span class="br0">)</span> dup2<span class="br0">(</span>fd, <span class="nu0">1</span><span class="br0">)</span>; <span class="co1">// fd becomes stdout</span> <span class="kw1">if</span> <span class="br0">(</span>fd != <span class="nu0">2</span><span class="br0">)</span> dup2<span class="br0">(</span>fd, <span class="nu0">2</span><span class="br0">)</span>; <span class="co1">// fd becomes stderr</span> <span class="kw1">if</span> <span class="br0">(</span>fd > <span class="nu0">2</span><span class="br0">)</span> close<span class="br0">(</span>fd<span class="br0">)</span>; <span class="co1">// now we can close it (the dups stay open)</span> close_all_fds<span class="br0">(</span><span class="nu0">2</span><span class="br0">)</span>; execlp<span class="br0">(</span>p->args<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>, <span class="co1">// run the new program with fd as stdin etc</span> p->args<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>, p->args<span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span>, p->args<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span>, p->args<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span>, p->args<span class="br0">[</span><span class="nu0">4</span><span class="br0">]</span>, p->args<span class="br0">[</span><span class="nu0">5</span><span class="br0">]</span>, <span class="kw2">NULL</span> <span class="br0">)</span>; _exit<span class="br0">(</span><span class="nu0">0</span><span class="br0">)</span>; <span class="br0">}</span> <span class="kw1">return</span><span class="br0">(</span>pid<span class="br0">)</span>; <span class="co1">// back to the parent here</span><span class="br0">}</span> </pre></div><!-- SECTION [2106-6533] --><h3><a name="webservers" id="webservers">Webservers</a></h3><div class="level3"><p> A webserver is another example of a process needing to use forks. Each incoming socket is normally passed to a forked clone of the parent.</p><p>Consider this code from <strong>cgi.c</strong> ( in directory <strong>user/boa/src</strong> ). Here the switch to <strong>MMUless</strong> is quite painless. </p><pre class="code c"> <span class="co1">// either fork or vfork will do here </span> <span class="co2">#if HAVE_FORK</span> child_pid = fork<span class="br0">(</span><span class="br0">)</span>;<span class="co2">#else</span> child_pid = vfork<span class="br0">(</span><span class="br0">)</span>;<span class="co2">#endif</span> </pre><p>Consider this code from <strong>thttpd.c</strong> ( in directory <strong>user/thttpd/</strong> ) which shows the modification made to the MMUfull version of this code to make it run as a foreground process , skipping the <strong>daemonize</strong> fork</p><pre class="code c"> */<span class="co2">#ifndef EMBED</span> <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> fclose<span class="br0">(</span> stdin <span class="br0">)</span>; <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> fclose<span class="br0">(</span> stdout <span class="br0">)</span>; <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span> fclose<span class="br0">(</span> stderr <span class="br0">)</span>; <span class="coMULTI">/* Daemonize - make ourselves a subprocess. */</span> <span class="kw1">switch</span> <span class="br0">(</span> fork<span class="br0">(</span><span class="br0">)</span> <span class="br0">)</span> <span class="br0">{</span> <span class="kw1">case</span> <span class="nu0">0</span>: <span class="kw2">break</span>; <span class="kw1">case</span> <span class="nu0">-1</span>: syslog<span class="br0">(</span> LOG_CRIT, <span class="st0">"fork - %m"</span> <span class="br0">)</span>; exit<span class="br0">(</span> <span class="nu0">1</span> <span class="br0">)</span>; <span class="kw1">default</span>: exit<span class="br0">(</span> <span class="nu0">0</span> <span class="br0">)</span>; <span class="br0">}</span><span class="co2">#endif</span></pre></div><!-- SECTION [6534-7605] --><h3><a name="stubborn_cases" id="stubborn_cases">Stubborn Cases</a></h3><div class="level3"><p> There are a few. You have to fork and you origianlly ( in MMUfull world) wanted an exact copy of yourself.</p><p>These are the problem cases. Normally you can save important data in environment variables and then restart yourself in a call to <strong>execve</strong> using a command line argument to select the <strong>child</strong> mode of operation.</p><p>The new child task will detect that it is functioning in <strong>child</strong> mode and restore the needed data from environment variables and continue.</p></div><!-- SECTION [7606-] --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -