Changes in the sockets: SIGIO handling

From: Julian Anastasov (uli@linux.tu-varna.acad.bg)
Date: Thu Mar 02 2000 - 09:41:49 EST


        Hello,

        Here is a list of proposed changes in the SIGIO handling for
sockets. This is a patch for 2.3.48. I have a patch for 2.2 too if
someone is interested. I'm still wondering if there are working
applications for 2.2 which expect si_code=SI_SIGIO!

List of proposed changes:

- Don't return POLL_HUP at EOF, return POLL_IN instead. We will use
POLL_HUP as a marker. Or we can add another POLL_xxx event and not
to change the POLL_HUP semantic? But this leads to changes in
/usr/include ?

- return POLL_HUP when:
        - close(): sock->shutdown != SHUTDOWN_MASK (or may be always?)
        - FASYNC off: send POLL_HUP. We can send POLL_HUP when needed,
        i.e. not on each close() - this can help very much

- tcp_reset() to send POLL_ERR/SIGIO on error

- add SO_ACCEPT_FLAGS socket option. Now accept() can check flags in
sock->accept_flags. One of these flags is SO_ACCEPT_F_ASYNC: inherit
FASYNC, O_NONBLOCK/O_NDELAY, F_SETSIG and F_SETOWN values from the
listening socket. Send POLL_IN/POLL_ERR according to the sock state.
This fills the gap between receiving the data in sock and accepting
the connection (creating the new fd). This saves the extra syscalls
F_SETSIG, FASYNC, F_SETOWN and the read() needed to check for the
first data. We can expect that there is data in the "sock" even
before accept(), so accept() must generate the proper event if there
is activity for the accepted sock before accept().
SO_ACCEPT_FLAGS is included in i386 only for now.

        I know, the flags can be renamed and stored in a better
place. But this is a patch for beta testing.

        We want to reduce the number of syscalls. More
flags can be added for SO_ACCEPT_FLAGS sock ioctl. For now I
added only the O_NONBLOCK/FASYNC/ownership inheritance but
some TCP options can be inherited too. The other option is
to create new acceptXXX() syscall but may be this is more difficult
task.

        For now, I think SO_ACCEPT_F_ASYNC is very useful because
we save 4 syscalls needed after accept(). Using this flag we even
receive notification if the accepted sock has data for us.
Without this feature we have to put extra read() after accept(),
F_SETSIG, F_SETOWN and FASYNC to detect the activity.

        I'm still not sure if the POLL_HUP must be always send on
close() or after some checks. We can't be sure if there are other
unread events while we try to close(). May be we can't rely on
sock->shutdown ? If sock->shutdown=SEND_SHUTDOWN on close() it
is still possible some events for the fd to be in the rt queue,
i.e. unread.

        May be one solution can be instead of sending POLL_HUP
on each close(), to send it when needed, i.e. using FASYNC=off
ioctl and not to send POLL_HUP from close(). For example:

        shutdown(fd,1)
        timeout waiting for data from fd
        fcntl FASYNC off (send POLL_HUP as last event for this fd)
        close()
        // reuse this fd safely without reading the long long rt queue

        One example when we don't need to send POLL_HUP on close():

        read(fd)=0
        write(fd,last_our_data)=OK
        // Here we don't expect more events, may be only POLL_ERR ?
        close(fd)

        With current behavior, when we receive POLL_HUP we know
that the remote end closed its end of the connection. But what
if we can't wait remote end to close the connection and we close()
the socket, even after shutdown(fd,1). After our close() when the
fd is released and can be reused again it is still possible unread
events to stay in the rt queue (POLL_IN in this case). When we
create/accept new file descriptor (with the same value) and continue
to read the events (from the long long rt queue) using sigwaitinfo(),
we can dequeue unexpected notifications for the old file descriptor.

        For example:

                <-- POLL_IN for fd
        sigwaitinfo(): POLL_IN for fd
        read(fd)=100
        // We remember that we can write(), so we try to write()
        write(fd)=100
        shutdown(fd,1)
        // We wait remote end to close
        // Here we expect POLL_IN but it is not received (after some
        // timeout)
                <-- POLL_IN for the listener enqueue
                <-- POLL_IN/POLL_ERR enqueued after our last check of
                the rt queue
        // We decide to close(fd)
        close(fd)
        sigwaitinfo(): POLL_IN for the listener
        fd = accept()
        set fd FASYNC, ... (or inherited from accept)
        sigwaitinfo(): POLL_IN/POLL_ERR for the old fd but we think it
        is for the new fd. Not fatal, one extra read()=EAGAIN

        What if we receive POLL_ERR from old fd when the new fd is
        in connecting state? We think the connection failed for the
        new fd. FATAL!

        So, in this patch the POLL_HUP notification from tcp_close()
can be removed. It is there only for test purposes. Instead of
receiving POLL_HUP from each close() we can try to remove the
FASYNC flag before close(one syscall), i.e. we decide when the
unexpected events are possible and put POLL_HUP marker at the end.
Or may be the close() notification is always required if the sock
is still in FASYNC mode? Is there any other way to put markers in
the rt queue for a fd?

        The patch is not tested for IPV6. I assume that locks
used in this patch are not correct! Please, correct me :)

        Are there any plans SIGIO to be supported for AF_UNIX?

Regards

--
Julian Anastasov <uli@linux.tu-varna.acad.bg>


- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Mar 07 2000 - 21:00:12 EST