change LINUX_F_SETFL so that SIGIO handling for sockets

matches more closely
add support for NEW_PIPE to the SIGIO hack
This commit is contained in:
jdolecek 2001-09-04 20:27:29 +00:00
parent 9f971c1da2
commit a065626465
1 changed files with 43 additions and 46 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_file.c,v 1.40 2001/07/22 13:34:09 wiz Exp $ */
/* $NetBSD: linux_file.c,v 1.41 2001/09/04 20:27:29 jdolecek Exp $ */
/*-
* Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
@ -56,6 +56,7 @@
#include <sys/tty.h>
#include <sys/socketvar.h>
#include <sys/conf.h>
#include <sys/pipe.h>
#include <sys/syscallargs.h>
@ -318,63 +319,59 @@ linux_sys_fcntl(p, v, retval)
return error;
retval[0] = bsd_to_linux_ioflags(retval[0]);
return 0;
case LINUX_F_SETFL:
case LINUX_F_SETFL: {
struct file *fp = NULL;
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;
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 in 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).
* Linux seems to have same semantics for sending SIGIO to the
* read side of socket, but slighly different semantics
* for SIGIO to the write side. Rather than sending the SIGIO
* every time it's possible to write (directly) more data, it
* only sends SIGIO if last write(2) failed due to insufficient
* memory to hold the data. This is compatible enough
* with NetBSD semantics to not do anything about the
* difference.
*
* 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.
* Linux does NOT send SIGIO for pipes. Deal with socketpair
* ones and DTYPE_PIPE ones. For these, we don't set
* the underlying flags (we don't pass O_ASYNC flag down
* to sys_fcntl()), but set the FASYNC flag for file descriptor,
* so that F_GETFL would report the ASYNC i/o is on.
*/
if ((error == 0) && (val & O_ASYNC)) {
struct filedesc *fdp;
struct file *fp;
struct socket *so;
fdp = p->p_fd;
if (((fp = fd_getfile(fdp, fd)) == NULL) ||
(fp->f_iflags & FIF_WANTCLOSE) != 0)
if (val & O_ASYNC) {
if (((fp = fd_getfile(p->p_fd, fd)) == NULL))
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;
if (((fp->f_type == DTYPE_SOCKET) && fp->f_data
&& ((struct socket *)fp->f_data)->so_state & SS_ISAPIPE)
|| (fp->f_type == DTYPE_PIPE))
val &= ~O_ASYNC;
else {
/* not a pipe, do not modify anything */
FILE_UNUSE(fp, p);
fp = NULL;
}
}
SCARG(&fca, fd) = fd;
SCARG(&fca, cmd) = F_SETFL;
SCARG(&fca, arg) = (caddr_t) val;
error = sys_fcntl(p, &fca, retval);
/* Now set the FASYNC flag for pipes */
if (fp) {
if (!error)
fp->f_flag |= FASYNC;
FILE_UNUSE(fp, p);
}
return error;
return (error);
}
case LINUX_F_GETLK:
sg = stackgap_init(p->p_emul);
bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);