summaryrefslogtreecommitdiffstats
path: root/lib/libpthread/uthread/uthread_setsockopt.c
diff options
context:
space:
mode:
authorkurt <kurt@openbsd.org>2008-06-03 14:45:05 +0000
committerkurt <kurt@openbsd.org>2008-06-03 14:45:05 +0000
commit068e7b4ffe89de86c23917842bc1c41c907f25f8 (patch)
tree2f55734dc7696b5f5c91ee61c6a12848168ec211 /lib/libpthread/uthread/uthread_setsockopt.c
parentAllow aucat to play/record from input-only or output-only devices. (diff)
downloadwireguard-openbsd-068e7b4ffe89de86c23917842bc1c41c907f25f8.tar.xz
wireguard-openbsd-068e7b4ffe89de86c23917842bc1c41c907f25f8.zip
Don't grab the fd read lock for getsockopt(2), setsockopt(2),
getpeername(2) or getsockname(2). Its not needed and causes threads to block when another thread is blocked and holding the read lock. Instead just protect against fd state transitions. Blocking problem reported by David S H Rosenthal from lockss.org okay beck@ "looks sane" deraadt@
Diffstat (limited to 'lib/libpthread/uthread/uthread_setsockopt.c')
-rw-r--r--lib/libpthread/uthread/uthread_setsockopt.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/lib/libpthread/uthread/uthread_setsockopt.c b/lib/libpthread/uthread/uthread_setsockopt.c
index 77cda0a65c1..bf6041985be 100644
--- a/lib/libpthread/uthread/uthread_setsockopt.c
+++ b/lib/libpthread/uthread/uthread_setsockopt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_setsockopt.c,v 1.4 1999/11/25 07:01:44 d Exp $ */
+/* $OpenBSD: uthread_setsockopt.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -32,6 +32,7 @@
*
* $FreeBSD: uthread_setsockopt.c,v 1.5 1999/08/28 00:03:47 peter Exp $
*/
+#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef _THREAD_SAFE
@@ -42,11 +43,22 @@ int
setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
int ret;
+ struct fd_table_entry *entry;
- if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
- ret = _thread_sys_setsockopt(fd, level, optname, optval, optlen);
- _FD_UNLOCK(fd, FD_RDWR);
+ ret = _thread_fd_table_init(fd, FD_INIT_UNKNOWN, NULL);
+ if (ret == 0) {
+ entry = _thread_fd_table[fd];
+
+ _SPINLOCK(&entry->lock);
+ if (entry->state == FD_ENTRY_OPEN) {
+ ret = _thread_sys_setsockopt(fd, level, optname, optval, optlen);
+ } else {
+ ret = -1;
+ errno = EBADF;
+ }
+ _SPINUNLOCK(&entry->lock);
}
+
return ret;
}
#endif