Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Aug 2005 08:09:38 -0600 (MDT)
From:      "M. Warner Losh" <imp@bsdimp.com>
To:        deischen@freebsd.org
Cc:        freebsd-hackers@freebsd.org, lists@nbux.com
Subject:   Re: nagios and freebsd threads issue : help please ...
Message-ID:  <20050822.080938.95905450.imp@bsdimp.com>
In-Reply-To: <Pine.GSO.4.43.0508220654550.27356-100000@sea.ntplx.net>
References:  <20050822.012017.22502074.imp@bsdimp.com> <Pine.GSO.4.43.0508220654550.27356-100000@sea.ntplx.net>

next in thread | previous in thread | raw e-mail | index | archive | help
So there's something in the list, I've gone through and done a call
tree analysis to show the extensive and pervastive nature of the
functions that nagios calls after fork.  I don't know if these are all
problems or not, since I don't know if some of these functions might
be called before the first thread is created with pthread_create.
However, any that are called after that clearly have undefined
behavior.

In message: <Pine.GSO.4.43.0508220654550.27356-100000@sea.ntplx.net>
            Daniel Eischen <deischen@freebsd.org> writes:
: > So, if any of these things is an issue, and you can point to a posix
: > things that says it is an issue, then I think that the problem can be
: > resolved.
: 
: You can only execute async-signal-safe functions after a fork()
: from a threaded application.  free(), malloc(), popen(), fgets(),
: are not async-signal-safe.  The list of async-signal-safe functions
: are here:
: 
:   http://www.opengroup.org/onlinepubs/009695399/nframe.html

This can really be found at:
      http://www.opengroup.org/onlinepubs/009695399/functions/chap02_04.html


  The following table defines a set of functions that shall be either
  reentrant or non-interruptible by signals and shall be
  async-signal-safe. Therefore applications may invoke them, without
  restriction, from signal-catching functions:

_Exit, _exit, abort, accept, access, aio_error, aio_return,
aio_suspend, alarm, bind, cfgetispeed, cfgetospeed, cfsetispeed,
cfsetospeed, chdir, chmod, chown, clock_gettime, close, connect,
creat, dup, dup2, execle, execve, fchmod, fchown, fcntl, fdatasync,
fork, fpathconf, fstat, fsync, ftruncate, getegid, geteuid, getgid,
getgroups, getpeername, getpgrp, getpid, getppid, getsockname,
getsockopt, getuid, kill, link, listen, lseek, lstat, mkdir, mkfifo,
open, pathconf, pause, pipe, poll, posix_trace_event, pselect, raise,
read, readlink, recv, recvfrom, recvmsg, rename, rmdir, select,
sem_post, send, sendmsg, sendto, setgid, setpgid, setsid, setsockopt,
setuid, shutdown, sigaction, sigaddset, sigdelset, sigemptyset,
sigfillset, sigismember, sleep, signal, sigpause, sigpending,
sigprocmask, sigqueue, sigset, sigsuspend, sockatmark, socket,
socketpair, stat, symlink, sysconf, tcdrain, tcflow, tcflush,
tcgetattr, tcgetpgrp, tcsendbreak, tcsetattr, tcsetpgrp, time,
timer_getoverrun, timer_gettime, timer_settime, times, umask, uname,
unlink, utime, wait, waitpid, write
 
[[Note, I reformatted the above ]].

: The restriction on fork() is here (20th bullet down):
: 
:   http://www.opengroup.org/onlinepubs/009695399/nframe.html

      http://www.opengroup.org/onlinepubs/009695399/functions/fork.html
      
# A process shall be created with a single thread. If a multi-threaded
  process calls fork(), the new process shall contain a replica of the
  calling thread and its entire address space, possibly including the
  states of mutexes and other resources. Consequently, to avoid
  errors, the child process may only execute async-signal-safe
  operations until such time as one of the exec functions is
  called. [THR] [Option Start] Fork handlers may be established by
  means of the pthread_atfork() function in order to maintain
  application invariants across fork() calls. [Option End]

  When the application calls fork() from a signal handler and any of
  the fork handlers registered by pthread_atfork() calls a function that
  is not asynch-signal-safe, the behavior is undefined.

Later, in the informative section, we have:

  When a programmer is writing a multi-threaded program, the first
  described use of fork(), creating new threads in the same program,
  is provided by the pthread_create() function. The fork() function is
  thus used only to run new programs, and the effects of calling
  functions that require certain resources between the call to fork()
  and the call to an exec function are undefined.

Note, the 'certain resources' here means non-async-signal-safe
functions.

This means that the following functions that nagios calls are unsafe:

In set_macro_environment_var:
	malloc, strcpy, strcat, setenv, unsetenv, free
In set_argv_macro_environment:
	snprintf
In free_memory (only used in the USE_MEMORY_PERFORMANCE_TWEAKS):
	free

In my_system:
	alarm,
	(in the EMBEDDEDPERL case:
		anything that perl can call,
		strncpy,
		printf)
	popen,
	strcpy,
	fgets,
	functions called by set_macro_environment_var,
		set_argv_macro_environment, free_memory

In daemon_init:
	snprintf, getrlimit, setrlimit, sprintf and anything else
	that's done as part of the daemon after daemon_init (I didn't
		do a call graph analysis on this).
	write_to_logs_and_console
	cleanup
	broker_program_state

write_to_logs_and_console:
	strlen, write_to_all_logs, write_to_console

write_to_log
	fopen, fprintf, fclose

write_to_console
	write_to_syslog	

write_to_all_logs
	write_to_syslog, write_to_log

write_to_syslog
	syslog

(in the DEBUG0 defined case: printf for nearly all functions)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050822.080938.95905450.imp>