summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKurt Miller <kurt@cvs.openbsd.org>2006-10-17 20:57:29 +0000
committerKurt Miller <kurt@cvs.openbsd.org>2006-10-17 20:57:29 +0000
commite8d3b6a8553a5f79a00b959f9a6e7211edadc424 (patch)
treeb4df683a68f7d7c48a3daa52cc8317361a3d0339 /lib
parent2a11b595da5be15d0b96062f21c6b158c2afa031 (diff)
Don't grab _FD_LOCK and queue up behind other threads as
this can potentially block indefinitely. Instead just protect against fd state transitions and perform the _thread_sys_shutdown(). Fixes deadlock reported by Tero Koskinen <tero.koskinen at iki.fi>. okay kettenis@
Diffstat (limited to 'lib')
-rw-r--r--lib/libpthread/uthread/uthread_shutdown.c35
1 files changed, 13 insertions, 22 deletions
diff --git a/lib/libpthread/uthread/uthread_shutdown.c b/lib/libpthread/uthread/uthread_shutdown.c
index b3219ec73a5..e8f3e776afb 100644
--- a/lib/libpthread/uthread/uthread_shutdown.c
+++ b/lib/libpthread/uthread/uthread_shutdown.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_shutdown.c,v 1.4 2003/02/14 02:34:16 marc Exp $ */
+/* $OpenBSD: uthread_shutdown.c,v 1.5 2006/10/17 20:57:28 kurt Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -43,31 +43,22 @@ int
shutdown(int fd, int how)
{
int ret;
+ struct fd_table_entry *entry;
- switch (how) {
- case 0:
- if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) {
+ 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_shutdown(fd, how);
- _FD_UNLOCK(fd, FD_READ);
+ } else {
+ ret = -1;
+ errno = EBADF;
}
- break;
- case 1:
- if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
- ret = _thread_sys_shutdown(fd, how);
- _FD_UNLOCK(fd, FD_WRITE);
- }
- break;
- case 2:
- if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
- ret = _thread_sys_shutdown(fd, how);
- _FD_UNLOCK(fd, FD_RDWR);
- }
- break;
- default:
- errno = EBADF;
- ret = -1;
- break;
+ _SPINUNLOCK(&entry->lock);
}
+
return (ret);
}
#endif