The program atfork.c shows the use of fork handlers. When run with no argument, or with a nonzero argument, the program will install fork handlers. When run with a zero argument, such as atfork 0, it will not.
With fork handlers installed, the result will be two output lines reporting the result of the fork call and, in parentheses, the pid of the current process. Without fork handlers, the child process will be created while the initial thread owns the mutex. Because the initial thread does not exist in the child, the mutex cannot be unlocked, and the child process will hang — only the parent process will print its message.
13-25 Function fork_prepare is the
31-42 Function fork_parent is the
48-60 Function fork_child is the
65-91 After creating a child process, which will continue executing the thread_ routine code, the thread_routine function locks the mutex. When run with fork handlers, the fork call will be blocked (when the
108-123 The main program locks the mutex before creating the thread that will fork. It then sleeps for several seconds, to ensure that the thread will be able to call fork while the mutex is locked, and then unlocks the mutex. The thread running thread_routine will always succeed in the parent process, because it will simply block until main releases the lock.
However, without the fork handlers, the child process will be created while the mutex is locked. The thread (main) that locked the mutex does not exist in the child, and cannot unlock the mutex in the child process. Mutexes can be unlocked
in the child only if they were locked by the thread that called fork — and fork handlers provide the best way to ensure that.
■ atfork.c
1 #include
2 #include
3 #include
4 #include "errors.h"
5
6 pid_t self_pid; /* pid of current process */
7 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
8
9 /*
10 * This routine will be called prior to executing the fork,
11 * within the parent process.
12 */
13 void fork_prepare (void)
14 {
15 int status;
16
17 /*
18 * Lock the mutex in the parent before creating the child,
19 * to ensure that no other thread can lock it (or change any
20 * associated shared state) until after the fork completes.
21 */
22 status = pthread_mutex_lock (&mutex);
23 if (status != 0)
24 err_abort (status, "Lock in prepare handler");
25 }
26
27 /*
28 * This routine will be called after executing the fork, within
29 * the parent process
30 */
31 void fork_parent (void)
32 {
33 int status;
34
35 /*
36 * Unlock the mutex in the parent after the child has been
37 * created.
38 */
39 status = pthread_mutex_unlock (&mutex);
40 if (status != 0)
41 err_abort (status, "Unlock in parent handler");
42 }
43
44 /*