SIGPIPE and threads

John Baldwin jhb at freebsd.org
Mon Jun 28 12:33:56 UTC 2010


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


More information about the freebsd-threads mailing list