diff options
Diffstat (limited to 'lib/libpthread/uthread/uthread_closefrom.c')
-rw-r--r-- | lib/libpthread/uthread/uthread_closefrom.c | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/lib/libpthread/uthread/uthread_closefrom.c b/lib/libpthread/uthread/uthread_closefrom.c index d80c0cff21d..62176ec2d24 100644 --- a/lib/libpthread/uthread/uthread_closefrom.c +++ b/lib/libpthread/uthread/uthread_closefrom.c @@ -1,10 +1,11 @@ -/* $OpenBSD: uthread_closefrom.c,v 1.2 2006/09/22 19:04:33 kurt Exp $ */ +/* $OpenBSD: uthread_closefrom.c,v 1.3 2006/09/26 14:18:28 kurt Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ #include <sys/stat.h> #include <errno.h> +#include <stdlib.h> #include <pthread.h> #include <unistd.h> @@ -13,9 +14,10 @@ int closefrom(int fd) { - int ret; + int ret = 0; int safe_fd; int lock_fd; + int *flags; _thread_enter_cancellation_point(); @@ -33,13 +35,52 @@ closefrom(int fd) for (safe_fd++; fd < safe_fd; fd++) close(fd); - /* Reset flags and clean up the fd table for fds to close */ - for (lock_fd = fd; lock_fd < _thread_dtablesize; lock_fd++) - if (_thread_fd_table[lock_fd] != NULL) - _thread_fd_table_remove(lock_fd); + flags = calloc((size_t)_thread_dtablesize, sizeof *flags); + if (flags == NULL) { + /* use calloc errno */ + ret = -1; + } else { + /* Lock and record all fd entries */ + for (lock_fd = fd; lock_fd < _thread_dtablesize; lock_fd++) { + if (_thread_fd_table[lock_fd] != NULL && + _thread_fd_table[lock_fd]->state != FD_ENTRY_CLOSED) { + ret = _FD_LOCK(lock_fd, FD_RDWR_CLOSE, NULL); + if (ret != -1) + flags[lock_fd] = 1; + else + break; + } + } - /* Now let the system do its thing */ - ret = _thread_sys_closefrom(fd); + if (ret != -1) { + /* + * Close the entries and reset the non-bocking + * flag when needed. + */ + for (lock_fd = fd; lock_fd < _thread_dtablesize; lock_fd++) { + if (flags[lock_fd] != NULL) { + _thread_fd_entry_close(lock_fd); + } + } + /* + * Now let the system do its thing. It is not practical + * to try to prevent races with other threads that can + * create new file descriptors. We just have to assume + * the application is well behaved when using closefrom. + */ + ret = _thread_sys_closefrom(fd); + } + + /* + * Unlock any locked entries. + */ + for (lock_fd = fd; lock_fd < _thread_dtablesize; lock_fd++) { + if (flags[lock_fd] != NULL) { + _FD_UNLOCK(lock_fd, FD_RDWR_CLOSE); + } + } + free(flags); + } } _thread_leave_cancellation_point(); |