diff options
author | Marco S Hyman <marc@cvs.openbsd.org> | 2003-02-14 03:58:43 +0000 |
---|---|---|
committer | Marco S Hyman <marc@cvs.openbsd.org> | 2003-02-14 03:58:43 +0000 |
commit | b01693ca1d1c5a0ba958682d11729c5b100a0669 (patch) | |
tree | 2ebb2affcb5ce542561c6fb8255090d6552f6046 /lib/libpthread/uthread | |
parent | 312b62ee1af124aafa5a9451db4d79c571c39776 (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.h | 3 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_close.c | 9 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_fd.c | 28 |
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 |