summaryrefslogtreecommitdiffstats
path: root/lib/libc_r/uthread/uthread_fd.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc_r/uthread/uthread_fd.c')
-rw-r--r--lib/libc_r/uthread/uthread_fd.c216
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
OpenPOWER on IntegriCloud