Subject: Re: struct emul modification
To: =?ISO-8859-1?Q?Jarom=EDr_Dolecek?= <jdolecek@netbsd.org>
From: Emmanuel Dreyfus <p99dreyf@criens.u-psud.fr>
List: tech-kern
Date: 06/11/2001 23:46:15
Here is the fix I propose to this problem:
- no more emulation code in sys/kern/uipc_socket2.c
- fixes both pipes and sockets inconsitencies
- async I/O state is consistent if the Linux process re-reads it.

The key point is using the socket buffer SB_ASYNC flag in sowakeup() instead
of using the socket flags SS_ASYNC. It has no bad side effect on my NetBSD
system, I'd like to be sure it's okay before commiting the code. Is it safe to
do it like this?

Also, I'd like to do the fix for SunOS emulation, but I need someone to test
it.

Index: sys_socket.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/sys_socket.c,v
retrieving revision 1.30
diff -U4 -r1.30 sys_socket.c
--- sys_socket.c        2001/05/19 17:28:33     1.30
+++ sys_socket.c        2001/06/11 21:24:21
@@ -99,14 +99,9 @@
                        so->so_state &= ~SS_NBIO;
                return (0);
 
        case FIOASYNC:
-               if (
-#ifndef __HAVE_MINIMAL_EMUL
-                   (!(so->so_state & SS_ISAPIPE) ||
-                   (!(p->p_emul->e_flags & EMUL_NO_BSD_ASYNCIO_PIPE))) &&
-#endif
-                   *(int *)data) {
+               if (*(int *)data) {
                        so->so_state |= SS_ASYNC;
                        so->so_rcv.sb_flags |= SB_ASYNC;
                        so->so_snd.sb_flags |= SB_ASYNC;
                } else {
Index: uipc_socket2.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/uipc_socket2.c,v
retrieving revision 1.38
diff -U4 -r1.38 uipc_socket2.c
--- uipc_socket2.c      2001/04/30 03:32:56     1.38
+++ uipc_socket2.c      2001/06/11 21:24:27
@@ -289,9 +289,9 @@
 
 /*
  * Wakeup processes waiting on a socket buffer.
  * Do asynchronous notification via SIGIO
- * if the socket has the SS_ASYNC flag set.
+ * if the socket buffer has the SB_ASYNC flag set.
  */
 void
 sowakeup(struct socket *so, struct sockbuf *sb)
 {
@@ -302,9 +302,9 @@
        if (sb->sb_flags & SB_WAIT) {
                sb->sb_flags &= ~SB_WAIT;
                wakeup((caddr_t)&sb->sb_cc);
        }
-       if (so->so_state & SS_ASYNC) {
+       if (sb->sb_flags & SB_ASYNC) {
                if (so->so_pgid < 0)
                        gsignal(-so->so_pgid, SIGIO);
                else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
                        psignal(p, SIGIO);
Index: proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.130
diff -U4 -r1.130 proc.h
--- proc.h      2001/05/19 17:28:33     1.130
+++ proc.h      2001/06/11 21:26:27
@@ -122,18 +122,8 @@
 /* 
  * Emulation miscelaneous flags
  */
 #define        EMUL_HAS_SYS___syscall  0x001   /* Has SYS___syscall */
-/* 
- * No BSD style async I/O pipes. Aync I/O request through
- * fcntl() for pipes will be ignored.  
- */
-#define EMUL_NO_BSD_ASYNCIO_PIPE       0x002 
-/* 
- * No SIGIO fired on read() calls when async I/O is enabled
- * This is not implemented yet
- */
-#define EMUL_NO_SIGIO_ON_READ  0x004 
 
 /*
  * Description of a process.
  *
Index: linux_file.c
===================================================================
RCS file: /cvsroot/syssrc/sys/compat/linux/common/linux_file.c,v
retrieving revision 1.37
diff -U4 -r1.37 linux_file.c
--- linux_file.c        2001/01/22 21:31:37     1.37
+++ linux_file.c        2001/06/11 21:27:35
@@ -53,8 +53,9 @@
 #include <sys/mount.h>
 #include <sys/malloc.h>
 #include <sys/vnode.h>
 #include <sys/tty.h>
+#include <sys/socketvar.h>
 #include <sys/conf.h>
 
 #include <sys/syscallargs.h>
 
@@ -319,9 +320,61 @@
                val = linux_to_bsd_ioflags((unsigned long)SCARG(uap, arg));
                SCARG(&fca, fd) = fd;
                SCARG(&fca, cmd) = F_SETFL;
                SCARG(&fca, arg) = (caddr_t) val;
-               return sys_fcntl(p, &fca, retval);
+               error = sys_fcntl(p, &fca, retval);
+               /*
+                * Linux does not send a SIGIO to the write end of a socket,
+                * neither it does send any SIGIO for pipes. If async I/O
+                * was requested, we keep the SS_ASYNC iin struct socket flag
+                * set, but we clear SB_ASYNC flags on the sending buffer 
+                * (for socket), and on the sending and the receiving buffer 
+                * (for pipes). 
+                * 
+                * Because we do not alter to SS_ASYNC in struct socket, 
+                * the Linux process keeps a consistent view of async I/O
+                * status if it attemps to read the async flag (SS_ASYNC)
+                * 
+                * This async I/O problem does matters, since some Linux 
+                * programs such as the JDK request async I/O on pipes, 
+                * but they fail if they happen to get a SIGIO to the write
+                * end of the pipe.
+                */
+               if ((error == 0) && (val & O_ASYNC)) {
+                       struct filedesc *fdp;
+                       struct file     *fp;
+                       struct socket *so;
+
+                       fdp = p->p_fd;
+
+                       if ((u_int)fd >= fdp->fd_nfiles ||
+                           (fp = fdp->fd_ofiles[fd]) == NULL ||
+                           (fp->f_iflags & FIF_WANTCLOSE) != 0)
+                           return (EBADF);
+
+                       FILE_USE(fp);
+
+                       if ((fp->f_type == DTYPE_SOCKET) && 
+                           (so = (struct socket*)fp->f_data)) {
+                               /*
+                                * Clear async I/O on sending buffer 
+                                * This will disable SIGIO for the 
+                                * write end of sockets and pipes.
+                                */
+                               so->so_snd.sb_flags &= ~SB_ASYNC;
+                               /*
+                                * If it's a pipe, also clear
+                                * it on the receiving buffer.
+                                * This will disable SIGIO for the
+                                * read end of pipes.
+                                */
+                               if (so->so_state & SS_ISAPIPE)
+                                       so->so_rcv.sb_flags &= ~SB_ASYNC;
+                       }
+
+                       FILE_UNUSE(fp, p);
+               }
+               return error;
        case LINUX_F_GETLK:
                sg = stackgap_init(p->p_emul);
                bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
                if ((error = copyin(arg, &lfl, sizeof lfl)))

-- 
Emmanuel Dreyfus
p99dreyf@criens.u-psud.fr