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