summaryrefslogtreecommitdiff
path: root/lib/libpthread/uthread/uthread_close.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/uthread/uthread_close.c')
-rw-r--r--lib/libpthread/uthread/uthread_close.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/lib/libpthread/uthread/uthread_close.c b/lib/libpthread/uthread/uthread_close.c
index fa45be87e68..05057dd026f 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.12 2006/09/22 19:04:33 kurt Exp $ */
+/* $OpenBSD: uthread_close.c,v 1.13 2006/09/26 14:18:28 kurt Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -51,15 +51,22 @@ close(int fd)
(fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) {
errno = EBADF;
ret = -1;
- } else if (_thread_fd_table[fd] == NULL)
- /* unknown to thread kernel, let system handle the close */
- ret = _thread_sys_close(fd);
- else if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
- /* XXX: Assumes well behaved threads. */
- /* XXX: Defer real close to avoid race condition */
- _thread_fd_table_remove(fd);
+ } else if ((ret = _FD_LOCK(fd, FD_RDWR_CLOSE, NULL)) != -1) {
+ /*
+ * We need to hold the entry spinlock till after
+ * _thread_sys_close() to stop races caused by the
+ * fd state transition.
+ */
+ _SPINLOCK(&_thread_fd_table[fd]->lock);
+
+ _thread_fd_entry_close(fd);
+
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
+
+ _SPINUNLOCK(&_thread_fd_table[fd]->lock);
+
+ _FD_UNLOCK(fd, FD_RDWR_CLOSE);
}
/* No longer in a cancellation point: */