Re: Bad Network SIGIO on Linux-2.4.19

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 7 Oct 2002 kuznet@ms2.inr.ac.ru wrote:

> Hello!
> 
> > If you log-in over the network, so that a socket is being used,
> 
> I do not understand how to use it in a way that a socket happened
> to be stdin. Please, explain.
> 
> Alexey

Well stdin actually comes from a virtual terminal, a 'pty', obtained
with openpty() from the next available /dev/pty,  which gets its
data (and SIGIO information) from the connected socket.

I modified the prog to show what bits actually being set (none).
This should clearly show that something is broken because we can
get served a SIGIO signal with no information about the nature of
the signal. Also, this signal happens many thousands of times per
second. I had over 20,000 lines to delete in only about 2 seconds
of operation. I first noted a bad I/O problem with 2.4.19. The
network data-transfer rate through a virtual terminal was down from
about 2 megabytes per second to about 1.5 kilobytes per second.
This was on an embedded system.

I traced this down to the overhead necessary to service all the
SIGIO signals. I then wrote a program to show the problem.
Unfortunately, most all I get is retorts like "Your program is
broken...". The program is, clearly, not written to do anything
except demonstrate the problem.


/*
 *  Modified to show /count the poll bits
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/resource.h>

#define ERRORS(s) { \
    fprintf(stderr, "Error from line %d, file %s, call %s, (%s)\n", \
    __LINE__,__FILE__,(s), strerror(errno)); \
    }


#define FAIL -1

int enab = 0;
int alive = 0;

static void set_sig(int sig, sig_t funct, int flags);

static void set_sig(int sig, sig_t funct, int flags)
{
    struct sigaction sa;
    if(sigaction(sig, NULL, &sa) == FAIL)
        ERRORS("sigaction");
    sa.sa_flags = flags;
    sa.sa_handler = funct;
    if(sigaction(sig, &sa, NULL) == FAIL)
        ERRORS("sigaction");
    return;
}

unsigned long polout = 0;
unsigned long polerr = 0;  

static void iotrap(int unused)
{
   struct pollfd pf;
   pf.fd = STDIN_FILENO;
   pf.events = POLLIN;
   pf.revents = 0;
   (void)poll(&pf, 1, 0);
   if(pf.revents & POLLIN)
       enab = 0;
   if(pf.revents & POLLOUT)
       polout++;
   if(pf.revents & POLLERR)
       polerr++;
   fprintf(stderr, "POLLOUT = %lu POLLERR = %lu (0x%08lx)\n",
               polout, polerr, pf.revents); 
}
static void reaper(int unused)
{
    alive = 0;
    while(wait3(&unused, WNOHANG, NULL) > 0)
        ;

}
int main(int args, char *argv[]);

int main(int args, char *argv[])
{
    int flags;
    size_t i;
    pid_t pid;
    struct termios term, save;

    set_sig(SIGCHLD, reaper, SA_INTERRUPT|SA_RESTART);
    set_sig(SIGIO,   iotrap, SA_INTERRUPT|SA_RESTART);
    alive = 1;
    switch((pid = fork()))
    {
    case 0:                 /*  Child */
        (void)sleep(1);
        for(i=0; i < 0x10; i++)
        {
            fprintf(stderr, ".");
            (void)sleep(1);
        }
        exit(EXIT_SUCCESS);
    default:
        break;
    }


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
 *  Save terminal characteristics and then set the terminal for raw
 *  input generating a signal upon any received character.
 */ 
    if(tcgetattr(STDIN_FILENO, &term) == FAIL)
        ERRORS("tcgetattr");
    save = term;
    term.c_lflag = ISIG;
    term.c_iflag = 0;
    if(tcsetattr(STDIN_FILENO, TCSANOW, &term) == FAIL)
        ERRORS("tcsetattr");
    if((flags = fcntl(STDIN_FILENO, F_GETFL)) == FAIL)
        ERRORS("fcntl");
    flags |= (FNDELAY|FASYNC);
    if(fcntl(STDIN_FILENO, F_SETFL, flags) == FAIL)
        ERRORS("fcntl");
    if(fcntl(STDIN_FILENO, F_SETOWN, getpid()) == FAIL)
        ERRORS("fcntl");
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
    fprintf(stderr, "Waiting for input.......");
    enab = 1;
    while(enab)
    {
        pause();
        fprintf(stderr, "Got out of pause\n");

    }
    if(alive) kill(pid, SIGINT);
    fprintf(stderr, "Exit okay, cleaning up...\n");
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
 *  Restore the terminal characteristics before we exit. Note, the
 *  terminal is shared. We can't just exit!
 */
    flags &= ~(FNDELAY|FASYNC);
    if(fcntl(STDIN_FILENO, F_SETFL, flags) == FAIL)
        ERRORS("fcntl");
    if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &save) == FAIL)
        ERRORS("tcsetattr");
    set_sig(SIGIO,  SIG_DFL, SA_INTERRUPT);
    fprintf(stderr, "Done!\n");
    return 0;
}


If you execute this, logged into a terminal, you get:

Waiting for input..........POLLOUT = 0 POLLERR = 0 (0x00000001)
Got out of pause
Exit okay, cleaning up...
Done!

If you do `telnet hostname` and execute it, logged in over the network,
you get (clearly showing that something is wrong):

Note that we got a signal (zillions of times), but no signal bits
are set.

Waiting for input.......POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)

[over 20,000 lines deleted...]

POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)
POLLOUT = 0 POLLERR = 0 (0x00000000)



Cheers,
Dick Johnson
Penguin : Linux version 2.4.19 on an i686 machine (797.90 BogoMips).
The US military has given us many words, FUBAR, SNAFU, now ENRON.
Yes, top management were graduates of West Point and Annapolis.

-
: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux