http://www.perlmonks.org?node_id=254078

as i just fork-bombed my router with a botched attempt to speed up a quick hack, i thought i'd take this opportunity to offer some wisdom on safe handling of fork() for those without the scars of personal experience. *grin*

if you aren't familiar with the concept, in a nutshell, fork-bombs are class of 'rabbit' processes (they suck up pools of pids, not just one) that have no cap on the number of of pids they syphon, or commonly have a cap far in excess of the size of the number of pids existing/possible in the system -- the modern cancer approach, grow as much and as fast as possible, and do it in a multi-threaded way.

if you have made acquaintence with fork-bombs in the past, you can ingore this, and stick to your line: "been there, done that, bought the t-shirt".


The Problem:

> is there anything that I can do to fix it?

pull the plug. the pid-space is full, nothing on the system can spawn new processes for _anything_ owning to system being all forked up. (sorry) that includes spawning processes for new connections, spawing new shells, su, shutdown, halt, etc.

there is a kernel module you can install to prevent fork-bombs, if it isn't already too late to do that. if you have privs to install kernel modules that is...


The Cause

while( ){ fork(); }

this and all isomorphisms, including loops with conditions, and loops with fork() in a conditional block, (if the condition in question is incorrect in a manner that always evaluates as true) are fork-bombs if the loop runs more than about a dozen times.


Technical Explanation

one codes fork() as:

if( fork() ){ # code } else { # code }

and this evaluates as both true AND false (one in the old process, one in the new, respectively). the kicker is, both processes continue normally after the end of the if() block, (with whatever differences they acquired in the course of the block).

that means a loop written:

while( ){ if( fork() ){ # code else{ # code } }

will run twice on the first pass, four times on the second, eight on the third, etc. producing a cheap way to test binary permutations, and a very easy way to use 1048576 threads in just 20 iterations.

this, it should be noted, is not a valid approach to programming anything short of a quantum computer. (for which, i understand, it is the only method. -- go fig.)


The Solution

fork() should never be used in a loop, except as follows:

while( ){ if( fork() ){ # code } else { # code exit; # <--- !!!! } }

which will produce exaclty one thread running the loop, and one additional thread per iteration, thus totalling only 21 threads for 20 iterations in contrast with the above.

for what it's worth, this is easiest for me to remember simplified as

"if fork, else exit"

of course, isomorphisms of the above will work, so this will also fine:

while( ){ unless( fork() ){ #code exit; } }

you may notice i only ever put the exit; in the false portion of the conditional, this may not matter to everyone, but technically fork() returns true for the parent and false for the child, and i'm in favor of orderly process management. *grin*

-- Xanatax.


"i'd like to see a positive LSD story, would that be newsworthy? just once? hear what it's all about? 'Today a young man on acid realized that all matter is merely energy condensed to a slow vibration, that we are all one consciousness experiencing itself subjectively, there no such things as death, life is only a dream and we are the imagination of ourselves. Here's Tom with the weather...'"
  --Bill Hicks