diff options
author | 2008-06-03 14:45:05 +0000 | |
---|---|---|
committer | 2008-06-03 14:45:05 +0000 | |
commit | 068e7b4ffe89de86c23917842bc1c41c907f25f8 (patch) | |
tree | 2f55734dc7696b5f5c91ee61c6a12848168ec211 /lib/libpthread/uthread/uthread_setsockopt.c | |
parent | Allow aucat to play/record from input-only or output-only devices. (diff) | |
download | wireguard-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.c | 20 |
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 |