kern/58647: itimers aren't cleared on fork()
Dan Nelson
dnelson at allantgroup.com
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
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Oct 28 11:40:18 PST 2003
>Closed-Date:
>Last-Modified:
>Originator: Dan Nelson
>Release: FreeBSD 5.1-CURRENT i386 / FreeBSD 4.8-RELEASE i386
>Organization:
The Allant Group, Inc.
>Environment:
System: FreeBSD dan.emsphone.com 5.1-CURRENT FreeBSD 5.1-CURRENT #295: Mon Oct 27 16:19:10 CST 2003 dan at dan.emsphone.com:/usr/src/sys/i386/compile/DANSMP i386
>Description:
POSIX says that all timers are cleared in the child after a fork()
(twice in fact):
http://www.opengroup.org/onlinepubs/007904975/functions/fork.html
[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.
>How-To-Repeat:
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;
sigemptyset(&act.sa_mask);
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 (;;)
;
}
>Fix:
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.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list