So, why the double fork?
First of all, let me quote from Bill Karwin:
UDF (User Defined Function)'s that try to change state outside the DBMS (Database Management System) (e.g. writing files, starting processes, sending notifications, etc.) are risky. They may take an unbounded amount of time to execute. Or they may be a security vulnerability. Or they may have a bug that makes them crash, which would bring down your MySQL server.
“trigger to run an external program [1]”
So, we certainly don't want to pause MySQL any longer than necessary (and Lord knows that XXXXXXXX is slow enough), and we don't want MySQL to crash either.
Now, what's the problem with a single fork()? If we do this:
>
```
{
pid = fork();
if (pid > 0) /* parent */
rc = wait(&status);
else /* child */
do_that_thang();
}
```
we could potentially make MySQL wait too long, say, waiting for the program we shell out to to timeout connecting to a database for instance. We could modify the code to do this:
>
```
{
pid = fork();
if (pid > 0) /* parent */
return;
else
do_that_thang();
}
```
Okay, MySQL doesn't have to wait now, but we have another potential problem and that's when the child process ends. When a process ends, the last thing that needs to happen before the process is truely reclaimed by the kernel is for the parent process to retreive the exit code from the child. And until the parent process does that, the child process is in the ``zombie'' state. It's not quite dead, but it's certainly not alive either.
Granted, MySQL could have set up a signal to handle children dying, but I won't want to count on that. So therefore, what I do is:
>
```
{
pid = fork();
if (pid > 0) /* parent */
rc = waitpid(pid,&status,0);
else
do_that_thang();
}
do_that_thang()
{
pid = fork();
if (pid > 0) /* this would be the child process created above */
exit(0); /* we kill ourselves, thus letting the parent */
/* process in MySQL to continue ... */
else
really_do_that_thang();
}
```
When the child process exits, the parent MySQL process gets the exit code and can continue on with its way. The grandchild process looses its parent, which therefore causes the kernel to re-parent the grandchild to init, which is set up to handle orphan child processes exiting.
And that's why the double fork.