Handle MSG_NOSIGNAL flag in linux_send() by setting SO_NOSIGPIPE on socket

for the duration of the send() call. Such approach may be less than ideal
in threading environment, when several threads share the same socket and it
might happen that several of them are calling linux_send() at the same time
with and without SO_NOSIGPIPE set.

However, such race condition is very unlikely in practice, therefore this
change provides practical improvement compared to the previous behaviour.

PR:		kern/76426
Submitted by:	Steven Hartland <killing@multiplay.co.uk>
MFC after:	3 days
This commit is contained in:
sobomax 2005-03-07 07:26:42 +00:00
parent 7d3d18d907
commit a5d845fec6

View File

@ -816,18 +816,41 @@ linux_send(struct thread *td, struct linux_send_args *args)
caddr_t to;
int tolen;
} */ bsd_args;
int error;
int error, nosigpipe, onosigpipe;
socklen_t valsize;
if ((error = copyin(args, &linux_args, sizeof(linux_args))))
return (error);
if (linux_args.flags & LINUX_MSG_NOSIGNAL) {
valsize = sizeof(onosigpipe);
error = kern_getsockopt(td, linux_args.s, SOL_SOCKET,
SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE,
&valsize);
if (error != 0)
return error;
if (onosigpipe == 0) {
nosigpipe = 1;
error = kern_setsockopt(td, linux_args.s, SOL_SOCKET,
SO_NOSIGPIPE, &nosigpipe, UIO_SYSSPACE,
sizeof(nosigpipe));
if (error != 0)
return error;
}
}
bsd_args.s = linux_args.s;
bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
bsd_args.len = linux_args.len;
bsd_args.flags = linux_args.flags;
bsd_args.to = NULL;
bsd_args.tolen = 0;
return (sendto(td, &bsd_args));
error = sendto(td, &bsd_args);
if ((linux_args.flags & LINUX_MSG_NOSIGNAL) && (onosigpipe == 0)) {
kern_setsockopt(td, linux_args.s, SOL_SOCKET,
SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE,
sizeof(onosigpipe));
}
return error;
}
struct linux_recv_args {