Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Jun 2010 08:33:54 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        threads@freebsd.org
Cc:        kib@freebsd.org
Subject:   SIGPIPE and threads
Message-ID:  <201006280833.54224.jhb@freebsd.org>

next in thread | raw e-mail | index | archive | help
Currently when a thread performs a write(2) on a disconnected socket or a FIFO 
with no readers the SIGPIPE signal is posted to the entire process via 
psignal().  This means that the signal can be delivered to any thread in the 
process.  However, it seems more intuitive to me that SIGPIPE should be sent 
to the "offending" thread similar to signals sent in response to traps via 
trapsignal().  POSIX seems to require this in that the description of the 
EPIPE error return value for write(2) and fflush(3) in the Open Group's online 
manpages both say that SIGPIPE should be sent to the current thread in 
addition to returning EPIPE:

http://www.opengroup.org/onlinepubs/000095399/functions/write.html

http://www.opengroup.org/onlinepubs/000095399/functions/fflush.html

I have an untested (only compiled) patch below:

Index: kern/uipc_syscalls.c
===================================================================
--- kern/uipc_syscalls.c	(revision 209571)
+++ kern/uipc_syscalls.c	(working copy)
@@ -738,6 +738,7 @@
 	struct mbuf *control;
 	enum uio_seg segflg;
 {
+	struct ksiginfo ksi;
 	struct file *fp;
 	struct uio auio;
 	struct iovec *iov;
@@ -793,8 +794,11 @@
 		/* Generation of SIGPIPE can be controlled per socket */
 		if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
 		    !(flags & MSG_NOSIGNAL)) {
+			ksiginfo_init(&ksi);
+			ksi.ksi_signo = SIGPIPE;
+			ksi.ksi_code = SI_KERNEL;
 			PROC_LOCK(td->td_proc);
-			psignal(td->td_proc, SIGPIPE);
+			tdsignal(td->td_proc, td, SIGPIPE, &ksi);
 			PROC_UNLOCK(td->td_proc);
 		}
 	}
@@ -2379,6 +2383,7 @@
 {
 #if (defined(INET) || defined(INET6)) && defined(SCTP)
 	struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
+	struct ksiginfo ksi;
 	struct socket *so;
 	struct file *fp = NULL;
 	int use_rcvinfo = 1;
@@ -2443,8 +2448,11 @@
 		/* Generation of SIGPIPE can be controlled per socket. */
 		if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
 		    !(uap->flags & MSG_NOSIGNAL)) {
+			ksiginfo_init(&ksi);
+			ksi.ksi_signo = SIGPIPE;
+			ksi.ksi_code = SI_KERNEL;
 			PROC_LOCK(td->td_proc);
-			psignal(td->td_proc, SIGPIPE);
+			tdsignal(td->td_proc, td, SIGPIPE, &ksi);
 			PROC_UNLOCK(td->td_proc);
 		}
 	}
@@ -2483,6 +2491,7 @@
 {
 #if (defined(INET) || defined(INET6)) && defined(SCTP)
 	struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL;
+	struct ksiginfo ksi;
 	struct socket *so;
 	struct file *fp = NULL;
 	int use_rcvinfo = 1;
@@ -2561,8 +2570,11 @@
 		/* Generation of SIGPIPE can be controlled per socket */
 		if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&
 		    !(uap->flags & MSG_NOSIGNAL)) {
+			ksiginfo_init(&ksi);
+			ksi.ksi_signo = SIGPIPE;
+			ksi.ksi_code = SI_KERNEL;
 			PROC_LOCK(td->td_proc);
-			psignal(td->td_proc, SIGPIPE);
+			tdsignal(td->td_proc, td, SIGPIPE, &ksi);
 			PROC_UNLOCK(td->td_proc);
 		}
 	}
Index: kern/sys_socket.c
===================================================================
--- kern/sys_socket.c	(revision 209571)
+++ kern/sys_socket.c	(working copy)
@@ -92,6 +92,7 @@
     int flags, struct thread *td)
 {
 	struct socket *so = fp->f_data;
+	struct ksiginfo ksi;
 	int error;
 
 #ifdef MAC
@@ -101,8 +102,11 @@
 #endif
 	error = sosend(so, 0, uio, 0, 0, 0, uio->uio_td);
 	if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) {
+		ksiginfo_init(&ksi);
+		ksi.ksi_signo = SIGPIPE;
+		ksi.ksi_code = SI_KERNEL;
 		PROC_LOCK(uio->uio_td->td_proc);
-		psignal(uio->uio_td->td_proc, SIGPIPE);
+		tdsignal(uio->uio_td->td_proc, uio->uio_td, SIGPIPE, &ksi);
 		PROC_UNLOCK(uio->uio_td->td_proc);
 	}
 	return (error);
Index: kern/sys_generic.c
===================================================================
--- kern/sys_generic.c	(revision 209571)
+++ kern/sys_generic.c	(working copy)
@@ -509,6 +509,7 @@
 	off_t offset;
 	int flags;
 {
+	struct ksiginfo ksi;
 	ssize_t cnt;
 	int error;
 #ifdef KTRACE
@@ -531,8 +532,11 @@
 			error = 0;
 		/* Socket layer is responsible for issuing SIGPIPE. */
 		if (fp->f_type != DTYPE_SOCKET && error == EPIPE) {
+			ksiginfo_init(&ksi);
+			ksi.ksi_signo = SIGPIPE;
+			ksi.ksi_code = SI_KERNEL;
 			PROC_LOCK(td->td_proc);
-			psignal(td->td_proc, SIGPIPE);
+			tdsignal(td->td_proc, td, SIGPIPE, &ksi);
 			PROC_UNLOCK(td->td_proc);
 		}
 	}

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201006280833.54224.jhb>