kern/58647: itimers aren't cleared on fork()

Dan Nelson dnelson at
Tue Oct 28 11:40:21 PST 2003

>Number:         58647
>Category:       kern
>Synopsis:       itimers aren't cleared on fork()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 28 11:40:18 PST 2003
>Originator:     Dan Nelson
>Release:        FreeBSD 5.1-CURRENT i386 / FreeBSD 4.8-RELEASE i386
The Allant Group, Inc.
System: FreeBSD 5.1-CURRENT FreeBSD 5.1-CURRENT #295: Mon Oct 27 16:19:10 CST 2003 dan at i386


POSIX says that all timers are cleared in the child after a fork()
(twice in fact):

[XSI] Interval timers shall be reset in the child process.

[TMR] Per-process timers created by the parent shall not be inherited by the child process.

FreeBSD 4.x and 5.x, however, only clear ITIMER_REAL.  ITIMER_VIRTUAL
and ITIMER_PROF both continue to fire in the child process.

This could cause problems for any program that uses those timers and
also forks (note that userland pthreads uses ITIMER_PROF for its
scheduling timer).  It definitely causes programs for threaded
debuggers, since the profile timer is firing the whole time between the
child calling ptrace(PT_TRACE_ME) and exec()'ing the debug target.


Compile the following program and run it.  For each received signal, a
c or p (child/parent) will be printed, along with a R, V, or P (signal). 
"p:P", for example means the parent got a SIGPROF.  Any "c:" output
indicates a bug.

#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

char pc = 'p';			/* parent or child */

static void sig_handler(int sig)
	/* print what signal we got, and whether we're child or parent, in
	   one atomic write */
	char array[4];
	array[0] = pc;
	array[1] = ':';
	array[2] = (sig == SIGPROF ? 'P' : sig == SIGVTALRM ? 'V' : sig == SIGALRM ? 'A' : '!');
	array[3] = ' ';
	write(1, &array, 4);

int main(int argc, char *argv[])
	struct itimerval itimer;
	struct sigaction act;

	act.sa_handler = sig_handler;
	act.sa_flags = SA_RESTART;
	sigaction(SIGPROF, &act, NULL);
	sigaction(SIGALRM, &act, NULL);
	sigaction(SIGVTALRM, &act, NULL);

	itimer.it_interval.tv_sec = 1;
	itimer.it_interval.tv_usec = 0;
	itimer.it_value = itimer.it_interval;
	setitimer(ITIMER_PROF, &itimer, NULL);
	setitimer(ITIMER_VIRTUAL, &itimer, NULL);
	setitimer(ITIMER_REAL, &itimer, NULL);
	if (fork() == 0)
		pc = 'c';
	for (;;)


Unknown.  It looks like the real timer is stored in a different place
from the virtual and profiling timers, which might explain why only the
real timer is cleared during fork.


More information about the freebsd-bugs mailing list