Hi,

On Tue, 16 Nov 1999 18:34:30 +0000 (PDT), Don Howard <[EMAIL PROTECTED]>
said:

>       What I expect to see is SIGRTMIN being delivered to a worker
>       thread when data arrives on one of it's sockets.  This is what
>       I get under 2.3.  Under 2.2 I see SIGIO being delivered to the
>       worker thread, rather than the RT signal.

This is very odd.  It works perfectly for me on both 2.2 and 2.3, with
the single exception that if you try to connect from localhost, 2.2 just
gives a SIGIO rather than a queued signal.  2.3 gets this case right.
Both kernels work fine for remote connections.

Has anyone got *any* idea why 2.2 would give a different signal for
localhost tcp connections???   It's as if the F_SETSIG is getting lost
in that case, although the F_SETOWN works fine (the right thread still
gets the SIGIO).

Dan's original reproducer is attached.

--Stephen

/* 
 *      thread_io.c
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/version.h>
#define  __USE_GNU
#include <poll.h>
#include <fcntl.h>


#define NR_WORKERS 4
#define THE_PORT   6789

#define p_error(fmt, args...) printf ("[%d] %s:%d:  " fmt "\n", getpid (), __FILE__, 
__LINE__ , ## args)


void handler (int sig)
{
    printf ("Thread %d: Signal queue overflow !!\n", getpid ());
}


void * worker (void *arg)
{
    int * this_pid = arg;
    sigset_t sigs;


    *this_pid = getpid ();


    sigemptyset(&sigs);
    sigaddset(&sigs, SIGRTMIN);
    if (pthread_sigmask (SIG_BLOCK, &sigs, 0) < 0)
    {
        p_error ("pthread_sigmask(): %s", strerror (errno));
        exit (1);
    }



    {
        struct sigaction sa;
        sigemptyset (&sa.sa_mask);
        sa.sa_handler = handler;
        sa.sa_flags   = 0;
        if (sigaction (SIGIO, &sa, 0) < 0)
        {
            p_error ("sigaction(): %s", strerror (errno));
            exit (1);
        }
    }


    while (1)
    {
        siginfo_t info;

        if (sigwaitinfo (&sigs, &info) < 0)
        {
            if (EINTR == errno)
            {
                continue;
            }
            else
            {
                p_error ("sigwaitinfo(): %s", strerror (errno));
                exit (1);
            }
        }
        printf ("thread %d: activity on socket %d\n", getpid (), info.si_fd);


#if 1 || (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,31)) 
        {
            struct pollfd pfd;
            printf ("Trying fallback poll()\n");
            pfd.fd     = info.si_fd;
            pfd.events = POLLIN|POLLOUT|POLLHUP;

            if (poll (&pfd, 1, 0) < 0)
            {
                p_error ("poll(): %s", strerror (errno));
                exit (1);
            }
            info.si_band = pfd.revents;
        }
#endif


        if (info.si_band & POLLHUP)
        {
            printf ("socket %d disconnected\n", info.si_fd);
            close (info.si_fd);
        }
        

        if (info.si_band & POLLIN)
        {
            int nr_bytes;
            char buf [256];     

            memset (buf, 0, 256);

            nr_bytes = read (info.si_fd, buf, 256);
            if (nr_bytes < 0)
            {
                p_error ("read(): %s", strerror (errno));
                exit (1);
            }
            else 
            {
                printf ("read: \"%s\"", buf);
            }
        }


        if (info.si_band & POLLOUT)
        {
            printf ("socket %d available for write\n", info.si_fd);
        }
    }
}


int main (int argc, char *argv[])
{
    int i;
    int listener;
    pid_t thread_pids[NR_WORKERS];

    
    if (setpgrp () < 0)
    {
        p_error ("setpgrp(): %s", strerror (errno));
        exit (1);       
    }
    

    for (i=0; i<NR_WORKERS; i++)
    {
        pthread_t thr;

        if (pthread_create (&thr, 0, worker, &thread_pids[i]) < 0)
        {
            p_error ("pthread_create(): %s", strerror (errno));
            exit (1);
        }
    }
    

    
    listener = socket(PF_INET, SOCK_STREAM, 0);
    if (listener < 0)
    {
        p_error ("socket(): %s", strerror (errno));
        exit (1);
    }

    
    {
        struct sockaddr_in addr;
        addr.sin_addr.s_addr    = INADDR_ANY;
        addr.sin_port           = htons (THE_PORT);
        addr.sin_family         = AF_INET;

        if (bind (listener, (struct sockaddr *)&addr, sizeof (addr)) < 0)
        {
            p_error ("bind(): %s", strerror (errno));
            exit (1);
        }
    }


    if (listen (listener, SOMAXCONN) < 0)
    {
        p_error ("listen(): %s", strerror (errno));
        exit (1);
    }


    {
        int ON = 1;
        if (setsockopt (listener, SOL_SOCKET, SO_REUSEADDR, &ON, sizeof (ON)) < 0)
        {
            p_error ("setsockopt(): %s", strerror (errno));
            exit (1);
        }
    }


    i=0;
    while (1)
    {
        int newsock;
        struct sockaddr addr;
        int len = sizeof (addr);

        newsock = accept (listener, &addr, &len);
        if (newsock < 0)
        {
            p_error ("accept(): %s", strerror (errno));
            exit (1);       
        }

        
        /*  Round-robbin new connections between workers. */
        if (i > NR_WORKERS) i = 0;

        if (fcntl(newsock, F_SETOWN, thread_pids[i++]) < 0) 
        {
            p_error ("fcntl(F_SETOWN) : %s", strerror (errno));
            exit (1);
        }
        printf ("socket %d assigned to thread %d\n", newsock, thread_pids[i-1]);


        if (fcntl (newsock, F_SETSIG, SIGRTMIN) < 0)
        {
            p_error ("fcntl(F_SETSIG) : %s", strerror (errno));
            exit (1);
        }

        {
            int flags = fcntl(newsock, F_GETFL, 0);
            if (flags < 0)
            {
                p_error ("fcntl(F_GETFL) : %s", strerror (errno));
                exit (1);
            }


            if (fcntl (newsock, F_SETFL, flags|O_NONBLOCK|O_ASYNC) < 0) 
            {
                p_error ("fcntl(F_SETFL) : %s", strerror (errno));
                exit (1);
            }
        }
    }

    exit (0);
}

Reply via email to