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 :)

/*
 * 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;
}
/*
 * 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;
}
_______________________________________________
Asterisk-BSD mailing list
[email protected]
http://lists.digium.com/mailman/listinfo/asterisk-bsd

Reply via email to