[Asterisk-bsd] Re: [Asterisk-Dev] moh issues

Luigi Rizzo rizzo at icir.org
Wed Jun 15 05:58:22 CDT 2005


On Wed, Jun 15, 2005 at 03:57:36AM -0700, Luigi Rizzo wrote:
> [background: i noticed a strange behaviour of asterisk on FreeBSD 4.11
> and userland pthreads library when using res_musiconhold.]

forgot the attachments :)

-------------- next part --------------
/*
 * test descriptor issues on threads.
 *
 * compile with cc -o simple simple.c
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int
main(int argc, char *argv[])
{
	pid_t p;
	int fd[2];
	FILE *f;

	pipe(fd);
	sleep(atoi(argv[1]));
	dup2(fd[0], STDOUT_FILENO);
	fcntl(0, F_SETFL, ~O_NONBLOCK & fcntl(0, F_GETFL));
	fcntl(1, F_SETFL, ~O_NONBLOCK & fcntl(1, F_GETFL));
	fcntl(2, F_SETFL, ~O_NONBLOCK & fcntl(2, F_GETFL));
	sleep(atoi(argv[1]));
	return 0;
}
-------------- next part --------------
/*
 * test descriptor issues on threads.
 *
 * compile with cc -o thre -lc_r thre.c
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>

int dump_desc(char *s, int w)
{
	int i;
        fprintf(stderr, "-- [pid %d thr %p] %s --\n", getpid(),
                pthread_self(), s);
	for (i=0; i<8; i++) {
		fprintf(stderr, "fd %d flags 0x%lx (system 0x%lx)\n", i,
			_thread_fd_getflags(i),
			__sys_fcntl(i, F_GETFL));
	}
	sleep(w);
        return 0;
}

int
main(int argc, char *argv[])
{
	pid_t p;
	int i, fd[2];

	pipe(fd);
	fprintf(stderr, "child-end %d    parent end %d max %d\n",
		fd[0], fd[1], getdtablesize());
	dump_desc("start main", 0);
	p = fork();
	if (p == 0) { /* child */
		/*
		 * close parent's end. It's a pipe so O_NONBLOCK remains.
		 * You can also do it in the loop below.
		 */
		close(fd[1]);
		/*
		 * First tell libc_r to leave O_NONBLOCK on the descriptors
		 * even after a close() or exec(), 
		 * _After_ that, close() all descriptors you don't need
		 * in the child, because they are shared and the child
		 * could change their mode in unexpected way causing us
		 * trouble.
		 * You can limit the loop (getdtablesize() is often large)
		 * but at least make sure to act on the descriptor you are
		 * using on the parent threads in blocking mode.
		 */ 
		if (argc > 1)
		    for (i=0; i < getdtablesize(); i++) {
			long fl = fcntl(i, F_GETFL);
			if (fl != -1 && i != fd[0]) {
				/* open and must be closed in the child */
				fcntl(i, F_SETFL, O_NONBLOCK | fl);
				close(i);
			}
		    }
		dup2(fd[0], STDOUT_FILENO);
		sleep(2);
		/*
		 * now we can finally exec a process without risking
		 * trouble. The process will only play with its own
		 * side of the pipes, which is not shared by the parent
		 * and so any action on it does not change the status
		 * on the parent side.
		 * The example process below does some weird things
		 * with the descriptors, and we use it to show that it
		 * does not harm us.
		 */
		execl("./simple", "simple", "2", NULL);
	} else {	/* parent */
		close(fd[0]);	/* close child end of the pipe */
		sleep(1);
		dump_desc("parent", 2);
		dump_desc("parent after exec done", 2);
		dump_desc("parent after child fcntl", 2);
		dump_desc("parent after child dead", 0);
	}
	return 0;
}


More information about the Asterisk-BSD mailing list