From 4af9874148b61feb347eb59c1200da38653576c1 Mon Sep 17 00:00:00 2001 From: Kurt Miller Date: Tue, 3 Jun 2008 14:45:06 +0000 Subject: 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@ --- lib/libpthread/uthread/uthread_getpeername.c | 22 +++++++++++++++++----- lib/libpthread/uthread/uthread_getsockname.c | 22 +++++++++++++++++----- lib/libpthread/uthread/uthread_getsockopt.c | 20 ++++++++++++++++---- lib/libpthread/uthread/uthread_setsockopt.c | 20 ++++++++++++++++---- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/lib/libpthread/uthread/uthread_getpeername.c b/lib/libpthread/uthread/uthread_getpeername.c index 378f23f7416..7a026a6885c 100644 --- a/lib/libpthread/uthread/uthread_getpeername.c +++ b/lib/libpthread/uthread/uthread_getpeername.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getpeername.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getpeername.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getpeername.c,v 1.5 1999/08/28 00:03:34 peter Exp $ */ +#include #include #include #ifdef _THREAD_SAFE @@ -41,12 +42,23 @@ int getpeername(int fd, struct sockaddr * peer, socklen_t *paddrlen) { - int ret; + int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { - ret = _thread_sys_getpeername(fd, peer, paddrlen); - _FD_UNLOCK(fd, FD_READ); + 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_getpeername(fd, peer, paddrlen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif diff --git a/lib/libpthread/uthread/uthread_getsockname.c b/lib/libpthread/uthread/uthread_getsockname.c index 683cc910f15..22ad8075c8e 100644 --- a/lib/libpthread/uthread/uthread_getsockname.c +++ b/lib/libpthread/uthread/uthread_getsockname.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getsockname.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getsockname.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getsockname.c,v 1.5 1999/08/28 00:03:36 peter Exp $ */ +#include #include #include #ifdef _THREAD_SAFE @@ -39,14 +40,25 @@ #include "pthread_private.h" int -getsockname(int s, struct sockaddr * name, socklen_t *namelen) +getsockname(int fd, struct sockaddr * name, socklen_t *namelen) { int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(s, FD_READ, NULL)) == 0) { - ret = _thread_sys_getsockname(s, name, namelen); - _FD_UNLOCK(s, FD_READ); + 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_getsockname(fd, name, namelen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif diff --git a/lib/libpthread/uthread/uthread_getsockopt.c b/lib/libpthread/uthread/uthread_getsockopt.c index f73b54780ea..09d31955652 100644 --- a/lib/libpthread/uthread/uthread_getsockopt.c +++ b/lib/libpthread/uthread/uthread_getsockopt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getsockopt.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getsockopt.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getsockopt.c,v 1.5 1999/08/28 00:03:36 peter Exp $ */ +#include #include #include #ifdef _THREAD_SAFE @@ -42,11 +43,22 @@ int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { - ret = _thread_sys_getsockopt(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_getsockopt(fd, level, optname, optval, optlen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif 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 * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_setsockopt.c,v 1.5 1999/08/28 00:03:47 peter Exp $ */ +#include #include #include #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 -- cgit v1.2.3