summaryrefslogtreecommitdiff
path: root/lib/libpthread/uthread
diff options
context:
space:
mode:
authorMarco S Hyman <marc@cvs.openbsd.org>2003-02-14 03:58:43 +0000
committerMarco S Hyman <marc@cvs.openbsd.org>2003-02-14 03:58:43 +0000
commitb01693ca1d1c5a0ba958682d11729c5b100a0669 (patch)
tree2ebb2affcb5ce542561c6fb8255090d6552f6046 /lib/libpthread/uthread
parent312b62ee1af124aafa5a9451db4d79c571c39776 (diff)
fix bug that would leave an FD locked if dup'd, then closed.
Also, for safety lock the _thread_fd_table when removing entries.
Diffstat (limited to 'lib/libpthread/uthread')
-rw-r--r--lib/libpthread/uthread/pthread_private.h3
-rw-r--r--lib/libpthread/uthread/uthread_close.c9
-rw-r--r--lib/libpthread/uthread/uthread_fd.c28
3 files changed, 27 insertions, 13 deletions
diff --git a/lib/libpthread/uthread/pthread_private.h b/lib/libpthread/uthread/pthread_private.h
index 9d5b9bf2747..4a244e89075 100644
--- a/lib/libpthread/uthread/pthread_private.h
+++ b/lib/libpthread/uthread/pthread_private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pthread_private.h,v 1.44 2003/02/04 22:14:27 marc Exp $ */
+/* $OpenBSD: pthread_private.h,v 1.45 2003/02/14 03:58:42 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -1112,6 +1112,7 @@ void _thread_seterrno(pthread_t,int);
void _thread_fd_init(void);
int _thread_fd_table_init(int);
int _thread_fd_table_dup(int, int);
+void _thread_fd_table_remove(int);
void _thread_fd_unlock_owned(pthread_t);
void _thread_fd_unlock_thread(struct pthread *, int, int, const char *, int);
pthread_addr_t _thread_gc(pthread_addr_t);
diff --git a/lib/libpthread/uthread/uthread_close.c b/lib/libpthread/uthread/uthread_close.c
index 7597338269d..cba4afab6db 100644
--- a/lib/libpthread/uthread/uthread_close.c
+++ b/lib/libpthread/uthread/uthread_close.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_close.c,v 1.9 2003/02/04 22:14:27 marc Exp $ */
+/* $OpenBSD: uthread_close.c,v 1.10 2003/02/14 03:58:42 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -47,7 +47,6 @@ close(int fd)
int flags;
int ret;
struct stat sb;
- struct fd_table_entry *entry;
/* This is a cancelation point: */
_thread_enter_cancellation_point();
@@ -100,11 +99,7 @@ close(int fd)
/* XXX: Assumes well behaved threads. */
/* XXX: Defer real close to avoid race condition */
- entry = _thread_fd_table[fd];
- _thread_fd_table[fd] = NULL;
- if (--entry->refcnt == 0)
- free(entry);
-
+ _thread_fd_table_remove(fd);
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
}
diff --git a/lib/libpthread/uthread/uthread_fd.c b/lib/libpthread/uthread/uthread_fd.c
index 4a48a8dd48c..ac81f56e1f1 100644
--- a/lib/libpthread/uthread/uthread_fd.c
+++ b/lib/libpthread/uthread/uthread_fd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_fd.c,v 1.20 2003/02/05 06:20:36 marc Exp $ */
+/* $OpenBSD: uthread_fd.c,v 1.21 2003/02/14 03:58:42 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -233,10 +233,8 @@ _thread_fd_table_dup(int from_fd, int to_fd)
entry = _thread_fd_table[to_fd];
if (entry != NULL) {
ret = _FD_LOCK(to_fd, FD_RDWR, NULL);
- if (ret != -1) {
- if (--entry->refcnt == 0)
- free(entry);
- }
+ if (ret != -1)
+ _thread_fd_table_remove(to_fd);
} else
ret = 0;
@@ -254,6 +252,26 @@ _thread_fd_table_dup(int from_fd, int to_fd)
}
/*
+ * Remove an fd entry from the table and free it if it's reference count
+ * goes to zero. The entry is assumed to be locked with a RDWR lock! It
+ * will be unlocked if it is not freed.
+ */
+void
+_thread_fd_table_remove(int fd)
+{
+ struct fd_table_entry *entry;
+
+ _SPINLOCK(&fd_table_lock);
+ entry = _thread_fd_table[fd];
+ if (--entry->refcnt == 0)
+ free(entry);
+ else
+ _FD_UNLOCK(fd, FD_RDWR);
+ _thread_fd_table[fd] = NULL;
+ _SPINUNLOCK(&fd_table_lock);
+}
+
+/*
* Unlock the fd table entry for a given thread, fd, and lock type.
*/
void