diff options
Diffstat (limited to 'lib/libc_r/uthread/uthread_fd.c')
-rw-r--r-- | lib/libc_r/uthread/uthread_fd.c | 216 |
1 files changed, 193 insertions, 23 deletions
diff --git a/lib/libc_r/uthread/uthread_fd.c b/lib/libc_r/uthread/uthread_fd.c index 76069bf..3b69639 100644 --- a/lib/libc_r/uthread/uthread_fd.c +++ b/lib/libc_r/uthread/uthread_fd.c @@ -40,9 +40,29 @@ #include <pthread.h> #include "pthread_private.h" +#define FDQ_INSERT(q,p) \ +do { \ + TAILQ_INSERT_TAIL(q,p,qe); \ + p->flags |= PTHREAD_FLAGS_IN_FDQ; \ +} while (0) + +#define FDQ_REMOVE(q,p) \ +do { \ + if ((p->flags & PTHREAD_FLAGS_IN_FDQ) != 0) { \ + TAILQ_REMOVE(q,p,qe); \ + p->flags &= ~PTHREAD_FLAGS_IN_FDQ; \ + } \ +} while (0) + + /* Static variables: */ static spinlock_t fd_table_lock = _SPINLOCK_INITIALIZER; +/* Prototypes: */ +static inline pthread_t fd_next_reader(int fd); +static inline pthread_t fd_next_writer(int fd); + + /* * This function *must* return -1 and set the thread specific errno * as a system call. This is because the error return from this @@ -201,11 +221,11 @@ _thread_fd_unlock(int fd, int lock_type) * Get the next thread in the queue for a * read lock on this file descriptor: */ - else if ((_thread_fd_table[fd]->r_owner = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) == NULL) { + else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) { } else { /* Remove this thread from the queue: */ - TAILQ_REMOVE(&_thread_fd_table[fd]->r_queue, - _thread_fd_table[fd]->r_owner, qe); + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); /* * Set the state of the new owner of @@ -243,11 +263,11 @@ _thread_fd_unlock(int fd, int lock_type) * Get the next thread in the queue for a * write lock on this file descriptor: */ - else if ((_thread_fd_table[fd]->w_owner = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) == NULL) { + else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) { } else { /* Remove this thread from the queue: */ - TAILQ_REMOVE(&_thread_fd_table[fd]->w_queue, - _thread_fd_table[fd]->w_owner, qe); + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); /* * Set the state of the new owner of @@ -290,6 +310,9 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) * entry: */ if ((ret = _thread_fd_table_init(fd)) == 0) { + /* Clear the interrupted flag: */ + _thread_run->interrupted = 0; + /* * Lock the file descriptor table entry to prevent * other threads for clashing with the current @@ -300,10 +323,10 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) /* Check the file descriptor and lock types: */ if (lock_type == FD_READ || lock_type == FD_RDWR) { /* - * Enter a loop to wait for the file descriptor to be - * locked for read for the current thread: + * Wait for the file descriptor to be locked + * for read for the current thread: */ - while (_thread_fd_table[fd]->r_owner != _thread_run) { + if (_thread_fd_table[fd]->r_owner != _thread_run) { /* * Check if the file descriptor is locked by * another thread: @@ -315,7 +338,7 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) * queue of threads waiting for a * read lock on this file descriptor: */ - TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->r_queue, _thread_run, qe); + FDQ_INSERT(&_thread_fd_table[fd]->r_queue, _thread_run); /* * Save the file descriptor details @@ -350,6 +373,10 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) */ _SPINLOCK(&_thread_fd_table[fd]->lock); + if (_thread_run->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_run); + } } else { /* * The running thread now owns the @@ -365,8 +392,9 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) } } - /* Increment the read lock count: */ - _thread_fd_table[fd]->r_lockcount++; + if (_thread_fd_table[fd]->r_owner == _thread_run) + /* Increment the read lock count: */ + _thread_fd_table[fd]->r_lockcount++; } /* Check the file descriptor and lock types: */ @@ -388,7 +416,7 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) * write lock on this file * descriptor: */ - TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->w_queue, _thread_run, qe); + FDQ_INSERT(&_thread_fd_table[fd]->w_queue, _thread_run); /* * Save the file descriptor details @@ -421,6 +449,11 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) * table entry again: */ _SPINLOCK(&_thread_fd_table[fd]->lock); + + if (_thread_run->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_run); + } } else { /* * The running thread now owns the @@ -437,12 +470,23 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout) } } - /* Increment the write lock count: */ - _thread_fd_table[fd]->w_lockcount++; + if (_thread_fd_table[fd]->w_owner == _thread_run) + /* Increment the write lock count: */ + _thread_fd_table[fd]->w_lockcount++; } /* Unlock the file descriptor table entry: */ _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + if (_thread_run->interrupted != 0) { + if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) == 0) { + ret = -1; + errno = EINTR; + } else { + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + } + } } /* Return the completion status: */ @@ -492,11 +536,11 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno) * Get the next thread in the queue for a * read lock on this file descriptor: */ - else if ((_thread_fd_table[fd]->r_owner = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) == NULL) { + else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) { } else { /* Remove this thread from the queue: */ - TAILQ_REMOVE(&_thread_fd_table[fd]->r_queue, - _thread_fd_table[fd]->r_owner, qe); + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); /* * Set the state of the new owner of @@ -534,11 +578,11 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno) * Get the next thread in the queue for a * write lock on this file descriptor: */ - else if ((_thread_fd_table[fd]->w_owner = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) == NULL) { + else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) { } else { /* Remove this thread from the queue: */ - TAILQ_REMOVE(&_thread_fd_table[fd]->w_queue, - _thread_fd_table[fd]->w_owner, qe); + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); /* * Set the state of the new owner of @@ -582,6 +626,9 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, * entry: */ if ((ret = _thread_fd_table_init(fd)) == 0) { + /* Clear the interrupted flag: */ + _thread_run->interrupted = 0; + /* * Lock the file descriptor table entry to prevent * other threads for clashing with the current @@ -607,7 +654,7 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, * queue of threads waiting for a * read lock on this file descriptor: */ - TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->r_queue, _thread_run, qe); + FDQ_INSERT(&_thread_fd_table[fd]->r_queue, _thread_run); /* * Save the file descriptor details @@ -689,7 +736,7 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, * write lock on this file * descriptor: */ - TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->w_queue, _thread_run, qe); + FDQ_INSERT(&_thread_fd_table[fd]->w_queue, _thread_run); /* * Save the file descriptor details @@ -753,9 +800,132 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, /* Unlock the file descriptor table entry: */ _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + if (_thread_run->interrupted != 0) { + if ((_thread_run->cancelflags & PTHREAD_CANCEL_NEEDED) == 0) { + ret = -1; + errno = EINTR; + } else { + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + } + } } /* Return the completion status: */ return (ret); } + +void +_thread_fd_unlock_owned(pthread_t pthread) +{ + int fd; + + for (fd = 0; fd < _thread_dtablesize; fd++) { + if ((_thread_fd_table[fd] != NULL) && + ((_thread_fd_table[fd]->r_owner == pthread) || + (_thread_fd_table[fd]->w_owner == pthread))) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Check if the thread owns the read lock: */ + if (_thread_fd_table[fd]->r_owner == pthread) { + /* Clear the read lock count: */ + _thread_fd_table[fd]->r_lockcount = 0; + + /* + * Get the next thread in the queue for a + * read lock on this file descriptor: + */ + if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) != NULL) { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING); + } + } + + /* Check if the thread owns the write lock: */ + if (_thread_fd_table[fd]->w_owner == pthread) { + /* Clear the write lock count: */ + _thread_fd_table[fd]->w_lockcount = 0; + + /* + * Get the next thread in the queue for a + * write lock on this file descriptor: + */ + if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) != NULL) { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING); + + } + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary. + */ + _thread_kern_sig_undefer(); + } + } +} + +static inline pthread_t +fd_next_reader(int fd) +{ + pthread_t pthread; + + while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) != NULL) && + (pthread->interrupted != 0)) { + /* + * This thread has either been interrupted by a signal or + * it has been canceled. Remove it from the queue. + */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread); + } + + return (pthread); +} + +static inline pthread_t +fd_next_writer(int fd) +{ + pthread_t pthread; + + while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) != NULL) && + (pthread->interrupted != 0)) { + /* + * This thread has either been interrupted by a signal or + * it has been canceled. Remove it from the queue. + */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread); + } + + return (pthread); +} #endif |