aboutsummaryrefslogtreecommitdiff
path: root/lib/libpthread/pthreads
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpthread/pthreads')
-rw-r--r--lib/libpthread/pthreads/Makefile.inc13
-rw-r--r--lib/libpthread/pthreads/cond.c204
-rw-r--r--lib/libpthread/pthreads/fd.c558
-rw-r--r--lib/libpthread/pthreads/fd_kern.c643
-rw-r--r--lib/libpthread/pthreads/fd_pipe.c264
-rw-r--r--lib/libpthread/pthreads/file.c113
-rw-r--r--lib/libpthread/pthreads/globals.c63
-rw-r--r--lib/libpthread/pthreads/malloc.c357
-rw-r--r--lib/libpthread/pthreads/mutex.c223
-rw-r--r--lib/libpthread/pthreads/pthread.c200
-rw-r--r--lib/libpthread/pthreads/pthread_attr.c96
-rw-r--r--lib/libpthread/pthreads/pthread_detach.c86
-rw-r--r--lib/libpthread/pthreads/pthread_join.c109
-rw-r--r--lib/libpthread/pthreads/pthread_once.c57
-rw-r--r--lib/libpthread/pthreads/queue.c119
-rw-r--r--lib/libpthread/pthreads/signal.c426
-rw-r--r--lib/libpthread/pthreads/sleep.c227
17 files changed, 3758 insertions, 0 deletions
diff --git a/lib/libpthread/pthreads/Makefile.inc b/lib/libpthread/pthreads/Makefile.inc
new file mode 100644
index 000000000000..29581c2264ac
--- /dev/null
+++ b/lib/libpthread/pthreads/Makefile.inc
@@ -0,0 +1,13 @@
+# from: @(#)Makefile.inc 5.6 (Berkeley) 6/4/91
+
+# pthread sources
+.PATH: ${.CURDIR}/pthreads
+
+SRCS+= cond.c fd.c fd_kern.c fd_pipe.c file.c globals.c malloc.c mutex.c \
+ pthread.c pthread_attr.c queue.c signal.c \
+ pthread_join.c pthread_detach.c sleep.c
+
+MAN2+=
+
+MAN3+=
+
diff --git a/lib/libpthread/pthreads/cond.c b/lib/libpthread/pthreads/cond.c
new file mode 100644
index 000000000000..84a90ba494c5
--- /dev/null
+++ b/lib/libpthread/pthreads/cond.c
@@ -0,0 +1,204 @@
+/* ==== cond.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Condition cariable functions.
+ *
+ * 1.00 93/10/28 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+
+/* ==========================================================================
+ * pthread_cond_init()
+ *
+ * In this implementation I don't need to allocate memory.
+ * ENOMEM, EAGAIN should never be returned. Arch that have
+ * weird constraints may need special coding.
+ */
+int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
+{
+ /* Only check if attr specifies some mutex type other than fast */
+ if ((cond_attr) && (cond_attr->c_type != COND_TYPE_FAST)) {
+ if (cond_attr->c_type >= COND_TYPE_MAX) {
+ return(EINVAL);
+ }
+ if (cond->c_flags & COND_FLAGS_INITED) {
+ return(EBUSY);
+ }
+ cond->c_type = cond_attr->c_type;
+ } else {
+ cond->c_type = COND_TYPE_FAST;
+ }
+ /* Set all other paramaters */
+ pthread_queue_init(&cond->c_queue);
+ cond->c_flags |= COND_FLAGS_INITED;
+ cond->c_lock = SEMAPHORE_CLEAR;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_cond_destroy()
+ */
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ /* Only check if cond is of type other than fast */
+ switch(cond->c_type) {
+ case COND_TYPE_FAST:
+ break;
+ case COND_TYPE_STATIC_FAST:
+ default:
+ return(EINVAL);
+ break;
+ }
+
+ /* Cleanup cond, others might want to use it. */
+ pthread_queue_init(&cond->c_queue);
+ cond->c_flags |= COND_FLAGS_INITED;
+ cond->c_lock = SEMAPHORE_CLEAR;
+ cond->c_flags = 0;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_cond_wait()
+ */
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ semaphore *lock, *plock;
+ int rval;
+
+ lock = &(cond->c_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (cond->c_type) {
+ /*
+ * Fast condition variables do not check for any error conditions.
+ */
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_enq(&cond->c_queue, pthread_run);
+ pthread_mutex_unlock(mutex);
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule will unlock pthread_run */
+ reschedule(PS_COND_WAIT);
+
+ return(pthread_mutex_lock(mutex));
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_cond_signal()
+ */
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ struct pthread *pthread;
+ semaphore *lock, *plock;
+ int rval;
+
+ lock = &(cond->c_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (cond->c_type) {
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ if (pthread = pthread_queue_get(&cond->c_queue)) {
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&cond->c_queue);
+ pthread->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ }
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_cond_broadcast()
+ *
+ * Not much different then the above routine.
+ */
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ struct pthread *pthread;
+ semaphore *lock, *plock;
+ int rval;
+
+ lock = &(cond->c_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (cond->c_type) {
+ case COND_TYPE_FAST:
+ case COND_TYPE_STATIC_FAST:
+ while (pthread = pthread_queue_get(&cond->c_queue)) {
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&cond->c_queue);
+ pthread->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ }
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
diff --git a/lib/libpthread/pthreads/fd.c b/lib/libpthread/pthreads/fd.c
new file mode 100644
index 000000000000..20f1b0105859
--- /dev/null
+++ b/lib/libpthread/pthreads/fd.c
@@ -0,0 +1,558 @@
+/* ==== fd.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : All the syscalls dealing with fds.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+
+/*
+ * These first functions really should not be called by the user.
+ *
+ * I really should dynamically figure out what the table size is.
+ */
+int dtablesize = 64;
+static struct fd_table_entry fd_entry[64];
+
+/* ==========================================================================
+ * fd_init()
+ */
+void fd_init(void)
+{
+ int i;
+
+ for (i = 0; i < dtablesize; i++) {
+ fd_table[i] = &fd_entry[i];
+
+ fd_table[i]->ops = NULL;
+ fd_table[i]->type = FD_NT;
+ fd_table[i]->fd.i = NOTOK;
+ fd_table[i]->flags = 0;
+ fd_table[i]->count = 0;
+
+ pthread_queue_init(&(fd_table[i]->r_queue));
+ pthread_queue_init(&(fd_table[i]->w_queue));
+
+ fd_table[i]->r_owner = NULL;
+ fd_table[i]->w_owner = NULL;
+ fd_table[i]->lock = SEMAPHORE_CLEAR;
+ fd_table[i]->next = NULL;
+ fd_table[i]->lockcount = 0;
+ }
+
+ /* Currently only initialize first 3 fds. */
+ fd_kern_init(0);
+ fd_kern_init(1);
+ fd_kern_init(2);
+ printf ("Warning: threaded process may have changed open file descriptors\n");
+}
+
+/* ==========================================================================
+ * fd_allocate()
+ */
+int fd_allocate()
+{
+ semaphore *lock;
+ int i;
+
+ for (i = 0; i < dtablesize; i++) {
+ lock = &(fd_table[i]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ continue;
+ }
+ if (fd_table[i]->count || fd_table[i]->r_owner
+ || fd_table[i]->w_owner) {
+ SEMAPHORE_RESET(lock);
+ continue;
+ }
+ if (fd_table[i]->type == FD_NT) {
+ /* Test to see if the kernel version is in use */
+ /* If so continue; */
+ }
+ fd_table[i]->count++;
+ SEMAPHORE_RESET(lock);
+ return(i);
+ }
+ pthread_run->error = ENFILE;
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * fd_free()
+ *
+ * Assumes fd is locked and owner by pthread_run
+ * Don't clear the queues, fd_unlock will do that.
+ */
+int fd_free(int fd)
+{
+ struct fd_table_entry *fd_valid;
+ int ret;
+
+ if (ret = --fd_table[fd]->count) {
+ /* Separate pthread queue into two distinct queues. */
+ fd_valid = fd_table[fd];
+ fd_table[fd] = fd_table[fd]->next;
+ fd_valid->next = fd_table[fd]->next;
+ }
+
+ fd_table[fd]->type = FD_NIU;
+ fd_table[fd]->fd.i = NOTOK;
+ fd_table[fd]->next = NULL;
+ fd_table[fd]->flags = 0;
+ fd_table[fd]->count = 0;
+ return(ret);
+}
+
+/* ==========================================================================
+ * fd_basic_unlock()
+ *
+ * The real work of unlock without the locking of fd_table[fd].lock.
+ */
+void fd_basic_unlock(int fd, int lock_type)
+{
+ struct pthread *pthread;
+ semaphore *plock;
+
+ if (fd_table[fd]->r_owner == pthread_run) {
+ if (pthread = pthread_queue_get(&fd_table[fd]->r_queue)) {
+
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&fd_table[fd]->r_queue);
+ fd_table[fd]->r_owner = pthread;
+ pthread->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ } else {
+ fd_table[fd]->r_owner = NULL;
+ }
+ }
+
+ if (fd_table[fd]->w_owner == pthread_run) {
+ if (pthread = pthread_queue_get(&fd_table[fd]->w_queue)) {
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&fd_table[fd]->r_queue);
+ fd_table[fd]->w_owner = pthread;
+ pthread->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ } else {
+ fd_table[fd]->w_owner = NULL;
+ }
+ }
+}
+
+/* ==========================================================================
+ * fd_unlock()
+ * If there is a lock count then the function fileunlock will do
+ * the unlocking, just return.
+ */
+void fd_unlock(int fd, int lock_type)
+{
+ semaphore *lock;
+
+ if (!(fd_table[fd]->lockcount)) {
+ lock = &(fd_table[fd]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ fd_basic_unlock(fd, lock_type);
+ SEMAPHORE_RESET(lock);
+ }
+}
+
+/* ==========================================================================
+ * fd_basic_lock()
+ *
+ * The real work of lock without the locking of fd_table[fd].lock.
+ * Be sure to leave the lock the same way you found it. i.e. locked.
+ */
+int fd_basic_lock(unsigned int fd, int lock_type, semaphore * lock)
+{
+ semaphore *plock;
+
+ /* If not in use return EBADF error */
+ if (fd_table[fd]->type == FD_NIU) {
+ return(NOTOK);
+ }
+
+ /* If not tested, test it and see if it is valid */
+ if (fd_table[fd]->type == FD_NT) {
+ /* If not ok return EBADF error */
+ if (fd_kern_init(fd) != OK) {
+ return(NOTOK);
+ }
+ }
+ if ((fd_table[fd]->type == FD_HALF_DUPLEX) ||
+ (lock_type & FD_READ)) {
+ if (fd_table[fd]->r_owner) {
+ if (fd_table[fd]->r_owner != pthread_run) {
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_enq(&fd_table[fd]->r_queue, pthread_run);
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule will unlock pthread_run */
+ reschedule(PS_FDLR_WAIT);
+
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ } else {
+ if (!fd_table[fd]->lockcount) {
+ PANIC();
+ }
+ }
+ }
+ fd_table[fd]->r_owner = pthread_run;
+ }
+ if ((fd_table[fd]->type != FD_HALF_DUPLEX) &&
+ (lock_type & FD_WRITE)) {
+ if (fd_table[fd]->w_owner) {
+ if (fd_table[fd]->w_owner != pthread_run) {
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_enq(&fd_table[fd]->w_queue, pthread_run);
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule will unlock pthread_run */
+ reschedule(PS_FDLW_WAIT);
+
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ }
+ }
+ fd_table[fd]->w_owner = pthread_run;
+ }
+ if (!fd_table[fd]->count) {
+ fd_basic_unlock(fd, lock_type);
+ return(NOTOK);
+ }
+ return(OK);
+}
+
+/* ==========================================================================
+ * fd_lock()
+ */
+int fd_lock(unsigned int fd, int lock_type)
+{
+ semaphore *lock;
+ int error;
+
+ if (fd < dtablesize) {
+ lock = &(fd_table[fd]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ error = fd_basic_lock(fd, lock_type, lock);
+ SEMAPHORE_RESET(lock);
+ return(error);
+ }
+ return(NOTOK);
+}
+
+
+/* ==========================================================================
+ * ======================================================================= */
+
+/* ==========================================================================
+ * read()
+ */
+ssize_t read(int fd, void *buf, size_t nbytes)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ)) == OK) {
+ ret = fd_table[fd]->ops->read(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * readv()
+ */
+int readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_READ)) == OK) {
+ ret = fd_table[fd]->ops->readv(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt);
+ fd_unlock(fd, FD_READ);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * write()
+ */
+ssize_t write(int fd, const void *buf, size_t nbytes)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE)) == OK) {
+ ret = fd_table[fd]->ops->write(fd_table[fd]->fd,
+ fd_table[fd]->flags, buf, nbytes);
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * writev()
+ */
+int writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_WRITE)) == OK) {
+ ret = fd_table[fd]->ops->writev(fd_table[fd]->fd,
+ fd_table[fd]->flags, iov, iovcnt);
+ fd_unlock(fd, FD_WRITE);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * lseek()
+ */
+off_t lseek(int fd, off_t offset, int whence)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ ret = fd_table[fd]->ops->seek(fd_table[fd]->fd,
+ fd_table[fd]->flags, offset, whence);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * close()
+ *
+ * The whole close procedure is a bit odd and needs a bit of a rethink.
+ * For now close() locks the fd, calls fd_free() which checks to see if
+ * there are any other fd values poinging to the same real fd. If so
+ * It breaks the wait queue into two sections those that are waiting on fd
+ * and those waiting on other fd's. Those that are waiting on fd are connected
+ * to the fd_table[fd] queue, and the count is set to zero, (BUT THE LOCK IS NOT
+ * RELEASED). close() then calls fd_unlock which give the fd to the next queued
+ * element which determins that the fd is closed and then calls fd_unlock etc...
+ */
+int close(int fd)
+{
+ union fd_data realfd;
+ int ret, flags;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ flags = fd_table[fd]->flags;
+ realfd = fd_table[fd]->fd;
+ if (fd_free(fd) == OK) {
+ ret = fd_table[fd]->ops->close(realfd, flags);
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * fd_basic_dup()
+ *
+ * Might need to do more than just what's below.
+ */
+static inline void fd_basic_dup(int fd, int newfd)
+{
+ fd_table[newfd]->next = fd_table[fd]->next;
+ fd_table[fd]->next = fd_table[newfd];
+ fd_table[fd]->count++;
+}
+
+/* ==========================================================================
+ * dup2()
+ *
+ * Always lock the lower number fd first to avoid deadlocks.
+ * newfd must be locked by hand so it can be closed if it is open,
+ * or it won't be opened while dup is in progress.
+ */
+int dup2(fd, newfd)
+{
+ union fd_data realfd;
+ semaphore *lock;
+ int ret, flags;
+
+ if (newfd < dtablesize) {
+ if (fd < newfd) {
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ /* Need to lock the newfd by hand */
+ lock = &(fd_table[newfd]->lock);
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Is it inuse */
+ if (fd_basic_lock(newfd, FD_RDWR, lock) == OK) {
+ /* free it and check close status */
+ flags = fd_table[fd]->flags;
+ realfd = fd_table[fd]->fd;
+ if (fd_free(fd) == OK) {
+ ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+ /* Lots of work to do */
+ }
+ }
+ fd_basic_dup(fd, newfd);
+ }
+ fd_unlock(fd, FD_RDWR);
+ } else {
+ /* Need to lock the newfd by hand */
+ lock = &(fd_table[newfd]->lock);
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ }
+ /* Is it inuse */
+ if ((ret = fd_basic_lock(newfd, FD_RDWR, lock)) == OK) {
+ /* free it and check close status */
+ flags = fd_table[fd]->flags;
+ realfd = fd_table[fd]->fd;
+ if (fd_free(fd) == OK) {
+ ret = fd_table[fd]->ops->close(realfd, flags);
+ } else {
+ /* Lots of work to do */
+ }
+
+ fd_basic_dup(fd, newfd);
+ fd_unlock(fd, FD_RDWR);
+ }
+ SEMAPHORE_RESET(lock);
+ }
+ } else {
+ ret = NOTOK;
+ }
+ return(ret);
+
+}
+
+/* ==========================================================================
+ * dup()
+ */
+int dup(int fd)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ ret = fd_allocate();
+ fd_basic_dup(fd, ret);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * fcntl()
+ */
+int fcntl(int fd, int cmd, ...)
+{
+ int ret, realfd, flags;
+ struct flock *flock;
+ semaphore *plock;
+ va_list ap;
+
+ flags = 0;
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ va_start(ap, cmd);
+ switch(cmd) {
+ case F_DUPFD:
+ ret = fd_allocate();
+ fd_basic_dup(va_arg(ap, int), ret);
+ break;
+ case F_SETFD:
+ flags = va_arg(ap, int);
+ case F_GETFD:
+ ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, flags | __FD_NONBLOCK);
+ break;
+ case F_GETFL:
+ ret = fd_table[fd]->flags;
+ break;
+ case F_SETFL:
+ flags = va_arg(ap, int);
+ if ((ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, flags | __FD_NONBLOCK)) == OK) {
+ fd_table[fd]->flags = flags;
+ }
+ break;
+/* case F_SETLKW: */
+ /*
+ * Do the same as SETLK but if it fails with EACCES or EAGAIN
+ * block the thread and try again later, not implemented yet
+ */
+/* case F_SETLK: */
+/* case F_GETLK:
+ flock = va_arg(ap, struct flock*);
+ ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, flock);
+ break; */
+ default:
+ /* Might want to make va_arg use a union */
+ ret = fd_table[fd]->ops->fcntl(fd_table[fd]->fd,
+ fd_table[fd]->flags, cmd, va_arg(ap, void*));
+ break;
+ }
+ va_end(ap);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/pthreads/fd_kern.c b/lib/libpthread/pthreads/fd_kern.c
new file mode 100644
index 000000000000..41b638724fb9
--- /dev/null
+++ b/lib/libpthread/pthreads/fd_kern.c
@@ -0,0 +1,643 @@
+/* ==== fd_kern.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Deals with the valid kernel fds.
+ *
+ * 1.00 93/09/27 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+
+/* ==========================================================================
+ * Variables used by both fd_kern_poll and fd_kern_wait
+ */
+static struct pthread *fd_wait_read, *fd_wait_write;
+static fd_set fd_set_read, fd_set_write;
+
+/* ==========================================================================
+ * fd_kern_poll()
+ *
+ * Called only from context_switch(). The kernel must be locked.
+ *
+ * This function uses a linked list of waiting pthreads, NOT a queue.
+ */
+static semaphore fd_wait_lock = SEMAPHORE_CLEAR;
+
+void fd_kern_poll()
+{
+ struct timeval __fd_kern_poll_timeout = { 0, 0 };
+ struct pthread **pthread;
+ semaphore *lock;
+ int count;
+
+ /* If someone has the lock then they are in RUNNING state, just return */
+ lock = &fd_wait_lock;
+ if (SEMAPHORE_TEST_AND_SET(lock)) {
+ return;
+ }
+ if (fd_wait_read || fd_wait_write) {
+ for (pthread = &fd_wait_read; *pthread; pthread = &((*pthread)->next)) {
+ FD_SET((*pthread)->fd, &fd_set_read);
+ }
+ for (pthread = &fd_wait_write; *pthread; pthread = &((*pthread)->next)) {
+ FD_SET((*pthread)->fd, &fd_set_write);
+ }
+
+ if ((count = machdep_sys_select(dtablesize, &fd_set_read,
+ &fd_set_write, NULL, &__fd_kern_poll_timeout)) < OK) {
+ if (count == -EINTR) {
+ SEMAPHORE_RESET(lock);
+ return;
+ }
+ PANIC();
+ }
+
+ for (pthread = &fd_wait_read; count && *pthread; ) {
+ if (FD_ISSET((*pthread)->fd, &fd_set_read)) {
+ /* Get lock on thread */
+
+ (*pthread)->state = PS_RUNNING;
+ *pthread = (*pthread)->next;
+ count--;
+ continue;
+ }
+ pthread = &((*pthread)->next);
+ }
+
+ for (pthread = &fd_wait_write; count && *pthread; ) {
+ if (FD_ISSET((*pthread)->fd, &fd_set_write)) {
+ semaphore *plock;
+
+ /* Get lock on thread */
+ plock = &(*pthread)->lock;
+ if (!(SEMAPHORE_TEST_AND_SET(plock))) {
+ /* Thread locked, skip it. */
+ (*pthread)->state = PS_RUNNING;
+ *pthread = (*pthread)->next;
+ SEMAPHORE_RESET(plock);
+ }
+ count--;
+ continue;
+ }
+ pthread = &((*pthread)->next);
+ }
+ }
+ SEMAPHORE_RESET(lock);
+}
+
+/* ==========================================================================
+ * fd_kern_wait()
+ *
+ * Called when there is no active thread to run.
+ */
+extern struct timeval __fd_kern_wait_timeout;
+
+void fd_kern_wait()
+{
+ struct pthread **pthread;
+ sigset_t sig_to_block;
+ int count;
+
+ if (fd_wait_read || fd_wait_write) {
+ for (pthread = &fd_wait_read; *pthread; pthread = &((*pthread)->next)) {
+ FD_SET((*pthread)->fd, &fd_set_read);
+ }
+ for (pthread = &fd_wait_write; *pthread; pthread = &((*pthread)->next)) {
+ FD_SET((*pthread)->fd, &fd_set_write);
+ }
+
+ /* Turn off interrupts for real while we set the timer. */
+
+ sigfillset(&sig_to_block);
+ sigprocmask(SIG_BLOCK, &sig_to_block, NULL);
+
+ machdep_unset_thread_timer();
+ __fd_kern_wait_timeout.tv_usec = 0;
+ __fd_kern_wait_timeout.tv_sec = 3600;
+
+ sigprocmask(SIG_UNBLOCK, &sig_to_block, NULL);
+
+ /*
+ * There is a small but finite chance that an interrupt will
+ * occure between the unblock and the select. Because of this
+ * sig_handler_real() sets the value of __fd_kern_wait_timeout
+ * to zero causing the select to do a poll instead of a wait.
+ */
+
+ while ((count = machdep_sys_select(dtablesize, &fd_set_read,
+ &fd_set_write, NULL, &__fd_kern_wait_timeout)) < OK) {
+ if (count == -EINTR) {
+ return;
+ }
+ PANIC();
+ }
+
+ for (pthread = &fd_wait_read; count && *pthread; ) {
+ if (FD_ISSET((*pthread)->fd, &fd_set_read)) {
+ /* Get lock on thread */
+
+ (*pthread)->state = PS_RUNNING;
+ *pthread = (*pthread)->next;
+ count--;
+ continue;
+ }
+ pthread = &((*pthread)->next);
+ }
+
+ for (pthread = &fd_wait_write; count && *pthread; ) {
+ if (FD_ISSET((*pthread)->fd, &fd_set_write)) {
+ semaphore *plock;
+
+ /* Get lock on thread */
+ plock = &(*pthread)->lock;
+ if (!(SEMAPHORE_TEST_AND_SET(plock))) {
+ /* Thread locked, skip it. */
+ (*pthread)->state = PS_RUNNING;
+ *pthread = (*pthread)->next;
+ SEMAPHORE_RESET(plock);
+ }
+ count--;
+ continue;
+ }
+ pthread = &((*pthread)->next);
+ }
+ } else {
+ /* No threads, waiting on I/O, do a sigsuspend */
+ sig_handler_pause();
+ }
+}
+
+/* ==========================================================================
+ * Special Note: All operations return the errno as a negative of the errno
+ * listed in errno.h
+ * ======================================================================= */
+
+/* ==========================================================================
+ * read()
+ */
+ssize_t __fd_kern_read(int fd, int flags, void *buf, size_t nbytes)
+{
+ semaphore *lock, *plock;
+ int ret;
+
+ while ((ret = machdep_sys_read(fd, buf, nbytes)) < OK) {
+ if (ret == -EWOULDBLOCK) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->next = fd_wait_read;
+ fd_wait_read = pthread_run;
+ pthread_run->fd = fd;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDR_WAIT);
+ } else {
+ pthread_run->error = -ret;
+ ret = NOTOK;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * readv()
+ */
+int __fd_kern_readv(int fd, int flags, struct iovec *iov, int iovcnt)
+{
+ semaphore *lock, *plock;
+ int ret;
+
+ while ((ret = machdep_sys_readv(fd, iov, iovcnt)) < OK) {
+ if (ret == -EWOULDBLOCK) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->next = fd_wait_read;
+ fd_wait_read = pthread_run;
+ pthread_run->fd = fd;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDR_WAIT);
+ } else {
+ pthread_run->error = -ret;
+ ret = NOTOK;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * write()
+ */
+ssize_t __fd_kern_write(int fd, int flags, const void *buf, size_t nbytes)
+{
+ semaphore *lock, *plock;
+ int ret;
+
+ while ((ret = machdep_sys_write(fd, buf, nbytes)) < OK) {
+ if (pthread_run->error == -EWOULDBLOCK) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDW_WAIT */
+ pthread_run->next = fd_wait_write;
+ fd_wait_write = pthread_run;
+ pthread_run->fd = fd;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDW_WAIT);
+ } else {
+ pthread_run->error = ret;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * writev()
+ */
+int __fd_kern_writev(int fd, int flags, struct iovec *iov, int iovcnt)
+{
+ semaphore *lock, *plock;
+ int ret;
+
+ while ((ret = machdep_sys_writev(fd, iov, iovcnt)) < OK) {
+ if (pthread_run->error == -EWOULDBLOCK) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDW_WAIT */
+ pthread_run->next = fd_wait_write;
+ fd_wait_write = pthread_run;
+ pthread_run->fd = fd;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDW_WAIT);
+ } else {
+ pthread_run->error = ret;
+ break;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * For blocking version we really should set an interrupt
+ * fcntl()
+ */
+int __fd_kern_fcntl(int fd, int flags, int cmd, int arg)
+{
+ return(machdep_sys_fcntl(fd, cmd, arg));
+}
+
+/* ==========================================================================
+ * close()
+ */
+int __fd_kern_close(int fd, int flags)
+{
+ return(machdep_sys_close(fd));
+}
+
+/* ==========================================================================
+ * lseek()
+ */
+int __fd_kern_lseek(int fd, int flags, off_t offset, int whence)
+{
+ return(machdep_sys_lseek(fd, offset, whence));
+}
+
+/*
+ * File descriptor operations
+ */
+extern machdep_sys_close();
+
+/* Normal file operations */
+static struct fd_ops __fd_kern_ops = {
+ __fd_kern_write, __fd_kern_read, __fd_kern_close, __fd_kern_fcntl,
+ __fd_kern_readv, __fd_kern_writev, __fd_kern_lseek
+};
+
+/* NFS file opperations */
+
+/* FIFO file opperations */
+
+/* Device operations */
+
+/* ==========================================================================
+ * open()
+ *
+ * Because open could potentially block opening a file from a remote
+ * system, we want to make sure the call will timeout. We then try and open
+ * the file, and stat the file to determine what operations we should
+ * associate with the fd.
+ *
+ * This is not done yet
+ *
+ * A reqular file on the local system needs no special treatment.
+ */
+int open(const char *path, int flags, ...)
+{
+ int fd, mode, fd_kern;
+ struct stat stat_buf;
+ va_list ap;
+
+ /* If pthread scheduling == FIFO set a virtual timer */
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ } else {
+ mode = 0;
+ }
+
+ if (!((fd = fd_allocate()) < OK)) {
+ fd_table[fd]->flags = flags;
+ flags |= __FD_NONBLOCK;
+
+ if (!((fd_kern = machdep_sys_open(path, flags, mode)) < OK)) {
+
+ /* fstat the file to determine what type it is */
+ if (fstat(fd_kern, &stat_buf)) {
+printf("error %d stating new fd %d\n", errno, fd);
+ }
+ if (S_ISREG(stat_buf.st_mode)) {
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ } else {
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ }
+ fd_table[fd]->fd = fd_kern;
+ return(fd);
+ }
+
+ pthread_run->error = - fd_kern;
+ fd_table[fd]->count = 0;
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * fd_kern_init()
+ *
+ * Assume the entry is locked before routine is invoked
+ *
+ * This may change. The problem is setting the fd to nonblocking changes
+ * the parents fd too, which may not be the desired result.
+ */
+static fd_kern_init_called = 0;
+void fd_kern_init(int fd)
+{
+ if ((fd_table[fd]->flags = machdep_sys_fcntl(fd, F_GETFL, NULL)) >= OK) {
+ machdep_sys_fcntl(fd, F_SETFL, fd_table[fd]->flags | __FD_NONBLOCK);
+ fd_table[fd]->ops = &(__fd_kern_ops);
+ fd_table[fd]->type = FD_HALF_DUPLEX;
+ fd_table[fd]->fd = fd;
+ fd_table[fd]->count = 1;
+
+ }
+}
+
+/* ==========================================================================
+ * Here are the berkeley socket functions. These are not POSIX.
+ * ======================================================================= */
+
+/* ==========================================================================
+ * socket()
+ */
+int socket(int af, int type, int protocol)
+{
+ int fd, fd_kern;
+
+ if (!((fd = fd_allocate()) < OK)) {
+
+ if (!((fd_kern = machdep_sys_socket(af, type, protocol)) < OK)) {
+ machdep_sys_fcntl(fd_kern, F_SETFL, __FD_NONBLOCK);
+
+ /* Should fstat the file to determine what type it is */
+ fd_table[fd]->ops = & __fd_kern_ops;
+ fd_table[fd]->type = FD_FULL_DUPLEX;
+ fd_table[fd]->fd = fd_kern;
+ fd_table[fd]->flags = 0;
+ return(fd);
+ }
+
+ pthread_run->error = - fd_kern;
+ fd_table[fd]->count = 0;
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * bind()
+ */
+int bind(int fd, const struct sockaddr *name, int namelen)
+{
+ /* Not much to do in bind */
+ semaphore *plock;
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ if ((ret = machdep_sys_bind(fd_table[fd]->fd, name, namelen)) < OK) {
+ pthread_run->error = - ret;
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * connect()
+ */
+int connect(int fd, const struct sockaddr *name, int namelen)
+{
+ semaphore *lock, *plock;
+ struct sockaddr tmpname;
+ int ret, tmpnamelen;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ if ((ret = machdep_sys_connect(fd_table[fd]->fd, name, namelen)) < OK) {
+ if ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) ||
+ (ret == -EALREADY)) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDW_WAIT */
+ pthread_run->fd = fd_table[fd]->fd.i;
+ pthread_run->next = fd_wait_write;
+ fd_wait_write = pthread_run;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDW_WAIT);
+
+ /* OK now lets see if it really worked */
+ if (((ret = machdep_sys_getpeername(fd_table[fd]->fd,
+ &tmpname, &tmpnamelen)) < OK) && (ret == -ENOTCONN)) {
+
+ /* Get the error, this function should not fail */
+ machdep_sys_getsockopt(fd_table[fd]->fd, SOL_SOCKET,
+ SO_ERROR, &pthread_run->error, &tmpnamelen);
+ }
+ } else {
+ pthread_run->error = -ret;
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * accept()
+ */
+int accept(int fd, struct sockaddr *name, int *namelen)
+{
+ semaphore *lock, *plock;
+ int ret, fd_kern;
+
+
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ while ((fd_kern = machdep_sys_accept(fd_table[fd]->fd, name, namelen)) < OK) {
+ if (fd_kern == -EWOULDBLOCK) {
+ /* Lock queue */
+ lock = &fd_wait_lock;
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->fd = fd_table[fd]->fd.i;
+ pthread_run->next = fd_wait_write;
+ pthread_run->next = fd_wait_read;
+ fd_wait_read = pthread_run;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDR_WAIT);
+ } else {
+ fd_unlock(fd, FD_RDWR);
+ return(fd_kern);
+ }
+ }
+ fd_unlock(fd, FD_RDWR);
+
+ if (!((ret = fd_allocate()) < OK)) {
+
+ /* This may be unnecessary */
+ machdep_sys_fcntl(fd_kern, F_SETFL, __FD_NONBLOCK);
+
+ /* Should fstat the file to determine what type it is */
+ fd_table[ret]->ops = & __fd_kern_ops;
+ fd_table[ret]->type = FD_FULL_DUPLEX;
+ fd_table[ret]->fd = fd_kern;
+ fd_table[ret]->flags = 0;
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * listen()
+ */
+int listen(int fd, int backlog)
+{
+ int ret;
+
+ if ((ret = fd_lock(fd, FD_RDWR)) == OK) {
+ ret = machdep_sys_listen(fd_table[fd]->fd, backlog);
+ fd_unlock(fd, FD_RDWR);
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/pthreads/fd_pipe.c b/lib/libpthread/pthreads/fd_pipe.c
new file mode 100644
index 000000000000..f504c75526b9
--- /dev/null
+++ b/lib/libpthread/pthreads/fd_pipe.c
@@ -0,0 +1,264 @@
+/* ==== fd_pipe.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : The new fast ITC pipe routines.
+ *
+ * 1.00 93/08/14 proven
+ * -Started coding this file.
+ *
+ * 1.01 93/11/13 proven
+ * -The functions readv() and writev() added.
+ */
+
+#include <pthread.h>
+#include <pthread/fd_pipe.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread/posix.h>
+
+/* ==========================================================================
+ * The pipe lock is never unlocked until all pthreads waiting are done with it
+ * read()
+ */
+ssize_t __pipe_read(struct __pipe *fd, int flags, void *buf, size_t nbytes)
+{
+ semaphore *lock, *plock;
+ int ret = 0;
+
+ if (flags & O_ACCMODE) { return(NOTOK); }
+
+ lock = &(fd->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ /* If there is nothing to read, go to sleep */
+ if (fd->count == 0) {
+ if (flags == WR_CLOSED) {
+ SEMAPHORE_RESET(lock);
+ return(0);
+ } /* Lock pthread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* queue pthread for a FDR_WAIT */
+ pthread_run->next = NULL;
+ fd->wait = pthread_run;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDR_WAIT);
+ ret = fd->size;
+ } else {
+ ret = MIN(nbytes, fd->count);
+ memcpy(buf, fd->buf + fd->offset, ret);
+ if (!(fd->count -= ret)) {
+ fd->offset = 0;
+ }
+
+ /* Should try to read more from the waiting writer */
+
+ if (fd->wait) {
+ plock = &(fd->wait->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ fd->wait->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ } else {
+ SEMAPHORE_RESET(lock);
+ }
+ }
+ return(ret);
+}
+
+/* ==========================================================================
+ * __pipe_write()
+ *
+ * First check to see if the read side is still open, then
+ * check to see if there is a thread in a read wait for this pipe, if so
+ * copy as much data as possible directly into the read waiting threads
+ * buffer. The write thread(whether or not there was a read thread)
+ * copies as much data as it can into the pipe buffer and it there
+ * is still data it goes to sleep.
+ */
+ssize_t __pipe_write(struct __pipe *fd, int flags, const void *buf, size_t nbytes) {
+ semaphore *lock, *plock;
+ int ret, count;
+
+ if (!(flags & O_ACCMODE)) { return(NOTOK); }
+
+ lock = &(fd->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ while (fd->flags != RD_CLOSED) {
+ if (fd->wait) {
+ /* Lock pthread */
+ plock = &(fd->wait->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* Copy data directly into waiting pthreads buf */
+ fd->wait_size = MIN(nbytes, fd->wait_size);
+ memcpy(fd->wait_buf, buf, fd->wait_size);
+ buf = (const char *)buf + fd->wait_size;
+ nbytes -= fd->wait_size;
+ ret = fd->wait_size;
+
+ /* Wake up waiting pthread */
+ fd->wait->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ fd->wait = NULL;
+ }
+
+ if (count = MIN(nbytes, fd->size - (fd->offset + fd->count))) {
+ memcpy(fd->buf + (fd->offset + fd->count), buf, count);
+ buf = (const char *)buf + count;
+ nbytes -= count;
+ ret += count;
+ }
+ if (nbytes) {
+ /* Lock pthread */
+ plock = &(fd->wait->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ fd->wait = pthread_run;
+ SEMAPHORE_RESET(lock);
+ reschedule(PS_FDW_WAIT);
+ } else {
+ return(ret);
+ }
+ }
+ return(NOTOK);
+}
+
+/* ==========================================================================
+ * __pipe_close()
+ *
+ * The whole close procedure is a bit odd and needs a bit of a rethink.
+ * For now close() locks the fd, calls fd_free() which checks to see if
+ * there are any other fd values poinging to the same real fd. If so
+ * It breaks the wait queue into two sections those that are waiting on fd
+ * and those waiting on other fd's. Those that are waiting on fd are connected
+ * to the fd_table[fd] queue, and the count is set to zero, (BUT THE LOCK IS NOT
+ * RELEASED). close() then calls fd_unlock which give the fd to the next queued
+ * element which determins that the fd is closed and then calls fd_unlock etc...
+ */
+int __pipe_close(struct __pipe *fd, int flags)
+{
+ semaphore *lock, *plock;
+
+ lock = &(fd->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ if (!(fd->flags)) {
+ if (fd->wait) {
+ if (flags & O_ACCMODE) {
+ fd->flags |= WR_CLOSED;
+ /* Lock pthread */
+ /* Write side closed, wake read side and return EOF */
+ plock = &((fd->wait)->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ fd->count = 0;
+
+ /* Wake up waiting pthread */
+ fd->wait->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ fd->wait = NULL;
+ } else {
+ /* Should send a signal */
+ fd->flags |= RD_CLOSED;
+ }
+ }
+ } else {
+ free(fd);
+ return(OK);
+ }
+ SEMAPHORE_RESET(lock);
+}
+
+/* ==========================================================================
+ * For those function that aren't implemented yet
+ * __pipe_enosys()
+ */
+static int __pipe_enosys()
+{
+ pthread_run->error = ENOSYS;
+ return(NOTOK);
+}
+
+/*
+ * File descriptor operations
+ */
+struct fd_ops fd_ops[] = {
+{ NULL, NULL, }, /* Non operations */
+{ __pipe_write, __pipe_read, __pipe_close, __pipe_enosys, __pipe_enosys,
+ __pipe_enosys },
+};
+
+/* ==========================================================================
+ * open()
+ */
+/* int __pipe_open(const char *path, int flags, ...) */
+int newpipe(int fd[2])
+{
+ struct __pipe *fd_data;
+
+ if ((!((fd[0] = fd_allocate()) < OK)) && (!((fd[1] = fd_allocate()) < OK))) {
+ fd_data = malloc(sizeof(struct __pipe));
+ fd_data->buf = malloc(4096);
+ fd_data->size = 4096;
+ fd_data->count = 0;
+ fd_data->offset = 0;
+
+ fd_data->wait = NULL;
+ fd_data->flags = 0;
+
+ fd_table[fd[0]]->fd.ptr = fd_data;
+ fd_table[fd[0]]->flags = O_RDONLY;
+ fd_table[fd[1]]->fd.ptr = fd_data;
+ fd_table[fd[1]]->flags = O_WRONLY;
+
+ return(OK);
+ }
+ return(NOTOK);
+}
+
diff --git a/lib/libpthread/pthreads/file.c b/lib/libpthread/pthreads/file.c
new file mode 100644
index 000000000000..d2cafc69b643
--- /dev/null
+++ b/lib/libpthread/pthreads/file.c
@@ -0,0 +1,113 @@
+/* ==== file.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : The locking functions for stdio.
+ *
+ * 1.00 93/09/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * flockfile()
+ */
+void flockfile(FILE *fp)
+{
+ semaphore *lock;
+ int fd;
+
+ fd = fileno(fp);
+ lock = &(fd_table[fd]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ if (fd_table[fd]->r_owner != pthread_run) {
+ /* This might fail but POSIX doesn't give a damn. */
+ fd_basic_lock(fd, FD_RDWR, lock);
+ }
+ fd_table[fd]->lockcount++;
+ SEMAPHORE_RESET(lock);
+}
+
+/* ==========================================================================
+ * ftrylockfile()
+ */
+int ftrylockfile(FILE *fp)
+{
+ semaphore *lock;
+ int fd;
+
+ fd = fileno(fp);
+ lock = &(fd_table[fd]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ if (fd_table[fd]->r_owner != pthread_run) {
+ if (!(fd_table[fd]->r_owner && fd_table[fd]->w_owner)) {
+ fd_basic_lock(fd, FD_RDWR, lock);
+ fd = OK;
+ } else {
+ fd = NOTOK;
+ }
+ } else {
+ fd_table[fd]->lockcount++;
+ fd = OK;
+ }
+ SEMAPHORE_RESET(lock);
+ return(fd);
+}
+
+/* ==========================================================================
+ * funlockfile()
+ */
+void funlockfile(FILE *fp)
+{
+ semaphore *lock;
+ int fd;
+
+ fd = fileno(fp);
+ lock = &(fd_table[fd]->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ if (fd_table[fd]->r_owner == pthread_run) {
+ if (--fd_table[fd]->lockcount == 0) {
+ fd_basic_unlock(fd, FD_RDWR);
+ }
+ }
+ SEMAPHORE_RESET(lock);
+}
+
diff --git a/lib/libpthread/pthreads/globals.c b/lib/libpthread/pthreads/globals.c
new file mode 100644
index 000000000000..d5ed64d9ffaa
--- /dev/null
+++ b/lib/libpthread/pthreads/globals.c
@@ -0,0 +1,63 @@
+/* ==== globals.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Global variables.
+ *
+ * 1.00 93/07/26 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+
+/*
+ * Initial thread, running thread, and top of link list
+ * of all threads.
+ */
+struct pthread *pthread_run;
+struct pthread *pthread_initial;
+struct pthread *pthread_link_list;
+
+/*
+ * default thread attributes
+ */
+pthread_attr_t pthread_default_attr = { SCHED_RR, NULL, PTHREAD_STACK_DEFAULT };
+
+/*
+ * Queue for all threads elidgeable to run this scheduling round.
+ */
+struct pthread_queue pthread_current_queue = PTHREAD_QUEUE_INITIALIZER;
+
+/*
+ * File table information
+ */
+struct fd_table_entry *fd_table[64];
+
+
diff --git a/lib/libpthread/pthreads/malloc.c b/lib/libpthread/pthreads/malloc.c
new file mode 100644
index 000000000000..c5947916a049
--- /dev/null
+++ b/lib/libpthread/pthreads/malloc.c
@@ -0,0 +1,357 @@
+/* ==== malloc.c ============================================================
+ * Copyright (c) 1983 Regents of the University of California.
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Malloc functions.
+ * This is a very fast storage allocator. It allocates blocks of a small
+ * number of different sizes, and keeps free lists of each size. Blocks that
+ * don't exactly fit are passed up to the next larger size. In this
+ * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
+ * This is designed for use in a virtual memory environment.
+ *
+ * 0.00 82/02/21 Chris Kingsley kingsley@cit-20
+ *
+ * 1.00 93/11/06 proven
+ * -Modified BSD libc malloc to be threadsafe.
+ *
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <string.h>
+#include <pthread/posix.h>
+
+/*
+ * The overhead on a block is at least 4 bytes. When free, this space
+ * contains a pointer to the next free block, and the bottom two bits must
+ * be zero. When in use, the first byte is set to MAGIC, and the second
+ * byte is the size index. The remaining bytes are for alignment.
+ * If range checking is enabled then a second word holds the size of the
+ * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
+ * The order of elements is critical: ov_magic must overlay the low order
+ * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
+ */
+union overhead {
+ union overhead *ov_next; /* when free */
+ struct {
+ u_char ovu_magic; /* magic number */
+ u_char ovu_index; /* bucket # */
+#ifdef RCHECK
+ u_short ovu_rmagic; /* range magic number */
+ u_int ovu_size; /* actual block size */
+#endif
+ } ovu;
+#define ov_magic ovu.ovu_magic
+#define ov_index ovu.ovu_index
+#define ov_rmagic ovu.ovu_rmagic
+#define ov_size ovu.ovu_size
+};
+
+#define MAGIC 0xef /* magic # on accounting info */
+#define RMAGIC 0x5555 /* magic # on range info */
+
+#ifdef RCHECK
+#define RSLOP sizeof (u_short)
+#else
+#define RSLOP 0
+#endif
+
+/*
+ * nextf[i] is the pointer to the next free block of size 2^(i+3). The
+ * smallest allocatable block is 8 bytes. The overhead information
+ * precedes the data area returned to the user.
+ */
+#define NBUCKETS 30
+static union overhead *nextf[NBUCKETS];
+extern char *sbrk();
+
+static int pagesz; /* page size */
+static int pagebucket; /* page size bucket */
+static semaphore malloc_lock = SEMAPHORE_CLEAR;
+
+#if defined(DEBUG) || defined(RCHECK)
+#define ASSERT(p) if (!(p)) botch("p")
+#include <stdio.h>
+static
+botch(s)
+ char *s;
+{
+ fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
+ (void) fflush(stderr); /* just in case user buffered it */
+ abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+/* ==========================================================================
+ * morecore()
+ *
+ * Allocate more memory to the indicated bucket
+ */
+static inline void morecore(int bucket)
+{
+ register union overhead *op;
+ register int sz; /* size of desired block */
+ int amt; /* amount to allocate */
+ int nblks; /* how many blocks we get */
+
+ /*
+ * sbrk_size <= 0 only for big, FLUFFY, requests (about
+ * 2^30 bytes on a VAX, I think) or for a negative arg.
+ */
+ sz = 1 << (bucket + 3);
+#ifdef DEBUG
+ ASSERT(sz > 0);
+#else
+ if (sz <= 0)
+ return;
+#endif
+ if (sz < pagesz) {
+ amt = pagesz;
+ nblks = amt / sz;
+ } else {
+ amt = sz + pagesz;
+ nblks = 1;
+ }
+ op = (union overhead *)sbrk(amt);
+ /* no more room! */
+ if ((int)op == -1)
+ return;
+ /*
+ * Add new memory allocated to that on
+ * free list for this hash bucket.
+ */
+ nextf[bucket] = op;
+ while (--nblks > 0) {
+ op->ov_next = (union overhead *)((caddr_t)op + sz);
+ op = (union overhead *)((caddr_t)op + sz);
+ }
+}
+
+/* ==========================================================================
+ * malloc()
+ */
+void *malloc(size_t nbytes)
+{
+ union overhead *op;
+ unsigned int amt;
+ int bucket, n;
+ semaphore *lock;
+
+ lock = &malloc_lock;
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ /*
+ * First time malloc is called, setup page size and
+ * align break pointer so all data will be page aligned.
+ */
+ if (pagesz == 0) {
+ pagesz = n = getpagesize();
+ op = (union overhead *)sbrk(0);
+ n = n - sizeof (*op) - ((int)op & (n - 1));
+ if (n < 0)
+ n += pagesz;
+ if (n) {
+ if (sbrk(n) == (char *)-1)
+ return (NULL);
+ }
+ bucket = 0;
+ amt = 8;
+ while (pagesz > amt) {
+ amt <<= 1;
+ bucket++;
+ }
+ pagebucket = bucket;
+ }
+ /*
+ * Convert amount of memory requested into closest block size
+ * stored in hash buckets which satisfies request.
+ * Account for space used per block for accounting.
+ */
+ if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
+#ifndef RCHECK
+ amt = 8; /* size of first bucket */
+ bucket = 0;
+#else
+ amt = 16; /* size of first bucket */
+ bucket = 1;
+#endif
+ n = -(sizeof (*op) + RSLOP);
+ } else {
+ amt = pagesz;
+ bucket = pagebucket;
+ }
+ while (nbytes > amt + n) {
+ amt <<= 1;
+ if (amt == 0) {
+ SEMAPHORE_RESET(lock);
+ return (NULL);
+ }
+ bucket++;
+ }
+ /*
+ * If nothing in hash bucket right now,
+ * request more memory from the system.
+ */
+ if ((op = nextf[bucket]) == NULL) {
+ morecore(bucket);
+ if ((op = nextf[bucket]) == NULL) {
+ SEMAPHORE_RESET(lock);
+ return (NULL);
+ }
+ }
+ /* remove from linked list */
+ nextf[bucket] = op->ov_next;
+ op->ov_magic = MAGIC;
+ op->ov_index = bucket;
+#ifdef RCHECK
+ /*
+ * Record allocated size of block and
+ * bound space with magic numbers.
+ */
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ op->ov_rmagic = RMAGIC;
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ SEMAPHORE_RESET(lock);
+ return ((char *)(op + 1));
+}
+
+/* ==========================================================================
+ * free()
+ */
+void free(void *cp)
+{
+ union overhead *op;
+ semaphore *lock;
+ int size;
+
+ lock = &malloc_lock;
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ if (cp == NULL) {
+ SEMAPHORE_RESET(lock);
+ return;
+ }
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+#ifdef DEBUG
+ ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
+#else
+ if (op->ov_magic != MAGIC) {
+ SEMAPHORE_RESET(lock);
+ return; /* sanity */
+ }
+#endif
+#ifdef RCHECK
+ ASSERT(op->ov_rmagic == RMAGIC);
+ ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
+#endif
+ size = op->ov_index;
+ ASSERT(size < NBUCKETS);
+ op->ov_next = nextf[size]; /* also clobbers ov_magic */
+ nextf[size] = op;
+
+ SEMAPHORE_RESET(lock);
+}
+
+/* ==========================================================================
+ * realloc()
+ *
+ * Storage compaction is no longer supported, fix program and try again.
+ */
+void *realloc(void *cp, size_t nbytes)
+{
+ u_int onb;
+ int i;
+ semaphore *lock;
+ union overhead *op;
+ char *res;
+
+ if (cp == NULL)
+ return (malloc(nbytes));
+ op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
+
+ if (op->ov_magic == MAGIC) {
+ i = op->ov_index;
+ } else {
+ /*
+ * This will cause old programs using storage compaction feature of
+ * realloc to break in a pseudo resonable way that is easy to debug.
+ * Returning a malloced buffer without the copy may cause
+ * indeterministic behavior.
+ */
+ return(NULL);
+ }
+
+ lock = &malloc_lock;
+ while(SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+ onb = 1 << (i + 3);
+ if (onb < pagesz)
+ onb -= sizeof (*op) + RSLOP;
+ else
+ onb += pagesz - sizeof (*op) - RSLOP;
+
+ /* avoid the copy if same size block */
+ if (i) {
+ i = 1 << (i + 2);
+ if (i < pagesz)
+ i -= sizeof (*op) + RSLOP;
+ else
+ i += pagesz - sizeof (*op) - RSLOP;
+ }
+
+ if (nbytes <= onb && nbytes > i) {
+#ifdef RCHECK
+ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
+ *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
+#endif
+ SEMAPHORE_RESET(lock);
+ return(cp);
+ }
+ SEMAPHORE_RESET(lock);
+
+ if ((res = malloc(nbytes)) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+
+ bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
+ free(cp);
+
+ return (res);
+}
+
diff --git a/lib/libpthread/pthreads/mutex.c b/lib/libpthread/pthreads/mutex.c
new file mode 100644
index 000000000000..0f3e9abfca7a
--- /dev/null
+++ b/lib/libpthread/pthreads/mutex.c
@@ -0,0 +1,223 @@
+/* ==== mutex.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Mutex functions.
+ *
+ * 1.00 93/07/19 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+
+/*
+ * Basic mutex functionality
+
+ * This is the basic lock order
+ * queue
+ * pthread
+ * global
+ *
+ * semaphore functionality is defined in machdep.h
+ */
+
+/* ==========================================================================
+ * pthread_mutex_init()
+ *
+ * In this implementation I don't need to allocate memory.
+ * ENOMEM, EAGAIN should never be returned. Arch that have
+ * weird constraints may need special coding.
+ */
+int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *mutex_attr)
+{
+ /* Only check if attr specifies some mutex type other than fast */
+ if ((mutex_attr) && (mutex_attr->m_type != MUTEX_TYPE_FAST)) {
+ if (mutex_attr->m_type >= MUTEX_TYPE_MAX) {
+ return(EINVAL);
+ }
+ if (mutex->m_flags & MUTEX_FLAGS_INITED) {
+ return(EBUSY);
+ }
+ mutex->m_type = mutex_attr->m_type;
+ } else {
+ mutex->m_type = MUTEX_TYPE_FAST;
+ }
+ /* Set all other paramaters */
+ pthread_queue_init(&mutex->m_queue);
+ mutex->m_flags |= MUTEX_FLAGS_INITED;
+ mutex->m_lock = SEMAPHORE_CLEAR;
+ mutex->m_owner = NULL;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutex_destroy()
+ */
+int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ /* Only check if mutex is of type other than fast */
+ switch(mutex->m_type) {
+ case MUTEX_TYPE_FAST:
+ break;
+ case MUTEX_TYPE_STATIC_FAST:
+ default:
+ return(EINVAL);
+ break;
+ }
+
+ /* Cleanup mutex, others might want to use it. */
+ pthread_queue_init(&mutex->m_queue);
+ mutex->m_flags |= MUTEX_FLAGS_INITED;
+ mutex->m_lock = SEMAPHORE_CLEAR;
+ mutex->m_owner = NULL;
+ mutex->m_flags = 0;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_mutex_trylock()
+ */
+int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ semaphore *lock;
+ int rval;
+
+ lock = &(mutex->m_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (!mutex->m_owner) {
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ } else {
+ rval = EBUSY;
+ }
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_mutex_lock()
+ */
+int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ semaphore *lock, *plock;
+ int rval;
+
+ lock = &(mutex->m_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (mutex->m_owner) {
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ pthread_queue_enq(&mutex->m_queue, pthread_run);
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule will unlock pthread_run */
+ reschedule(PS_MUTEX_WAIT);
+ return(OK);
+ }
+ mutex->m_owner = pthread_run;
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
+
+/* ==========================================================================
+ * pthread_mutex_unlock()
+ */
+int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ struct pthread *pthread;
+ semaphore *lock, *plock;
+ int rval;
+
+ lock = &(mutex->m_lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ switch (mutex->m_type) {
+ /*
+ * Fast mutexes do not check for any error conditions.
+ */
+ case MUTEX_TYPE_FAST:
+ case MUTEX_TYPE_STATIC_FAST:
+ if (pthread = pthread_queue_get(&mutex->m_queue)) {
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ mutex->m_owner = pthread;
+
+ /* Reset pthread state */
+ pthread_queue_deq(&mutex->m_queue);
+ pthread->state = PS_RUNNING;
+ SEMAPHORE_RESET(plock);
+ } else {
+ mutex->m_owner = NULL;
+ }
+ rval = OK;
+ break;
+ default:
+ rval = EINVAL;
+ break;
+ }
+ SEMAPHORE_RESET(lock);
+ return(rval);
+}
diff --git a/lib/libpthread/pthreads/pthread.c b/lib/libpthread/pthreads/pthread.c
new file mode 100644
index 000000000000..6a039d2d67d9
--- /dev/null
+++ b/lib/libpthread/pthreads/pthread.c
@@ -0,0 +1,200 @@
+/* ==== pthread.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread functions.
+ *
+ * 1.00 93/07/26 proven
+ * -Started coding this file.
+ */
+
+#include "pthread.h"
+#include <signal.h>
+#include <errno.h>
+
+/*
+ * These first functions really should not be called by the user.
+ */
+
+/* ==========================================================================
+ * pthread_init()
+ *
+ * This function should be called in crt0.o before main() is called.
+ * But on some systems It may not be possible to change crt0.o so currently
+ * I'm requiring this function to be called first thing after main.
+ * Actually I'm assuming it is, because I do no locking here.
+ */
+void pthread_init(void)
+{
+ struct machdep_pthread machdep_data = MACHDEP_PTHREAD_INIT;
+
+ /* Initialize the first thread */
+ if (pthread_initial = (pthread_t)malloc(sizeof(struct pthread))) {
+ memcpy(&(pthread_initial->machdep_data), &machdep_data, sizeof(machdep_data));
+ pthread_initial->state = PS_RUNNING;
+ pthread_initial->queue = NULL;
+ pthread_initial->next = NULL;
+ pthread_initial->pll = NULL;
+
+ pthread_initial->lock = SEMAPHORE_CLEAR;
+ pthread_initial->error = 0;
+
+ pthread_link_list = pthread_initial;
+ pthread_run = pthread_initial;
+
+ /* Initialize the signal handler. */
+ sig_init();
+
+ /* Initialize the fd table. */
+ fd_init();
+
+ return;
+ }
+ PANIC();
+}
+
+/* ==========================================================================
+ * pthread_yield()
+ */
+void pthread_yield()
+{
+ sig_handler_fake(SIGVTALRM);
+}
+
+/* ======================================================================= */
+/* ==========================================================================
+ * pthread_self()
+ */
+pthread_t pthread_self()
+{
+ return(pthread_run);
+}
+
+/* ==========================================================================
+ * pthread_equal()
+ */
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+ return(t1 == t2);
+}
+
+/* ==========================================================================
+ * pthread_exit()
+ */
+void pthread_exit(void *status)
+{
+ semaphore *lock, *plock;
+ pthread_t pthread;
+
+ lock = &pthread_run->lock;
+ if (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* Save return value */
+ pthread_run->ret = status;
+
+ /* First execute all cleanup handlers */
+
+
+ /*
+ * Are there any threads joined to this one,
+ * if so wake them and let them detach this thread.
+ */
+ if (pthread = pthread_queue_get(&(pthread_run->join_queue))) {
+ /* The current thread pthread_run can't be detached */
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+ (void)pthread_queue_deq(&(pthread_run->join_queue));
+ pthread->state = PS_RUNNING;
+
+ /* Thread will unlock itself in pthread_join() */
+ }
+
+ /* This thread will never run again */
+ reschedule(PS_DEAD);
+ PANIC();
+}
+
+/* ==========================================================================
+ * pthread_create()
+ *
+ * After the new thread structure is allocated and set up, it is added to
+ * pthread_run_next_queue, which requires a sig_prevent(),
+ * sig_check_and_resume()
+ */
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void * (*start_routine)(void *), void *arg)
+{
+ long nsec = 100000000;
+ void *stack;
+
+ if ((*thread) = (pthread_t)malloc(sizeof(struct pthread))) {
+
+ if (! attr) { attr = &pthread_default_attr; }
+
+ /* Get a stack, if necessary */
+ if ((stack = attr->stackaddr_attr) ||
+ (stack = (void *)malloc(attr->stacksize_attr))) {
+
+ machdep_pthread_create(&((*thread)->machdep_data),
+ start_routine, arg, 65536, stack, nsec);
+
+ memcpy(&(*thread)->attr, attr, sizeof(pthread_attr_t));
+
+ (*thread)->queue = NULL;
+ (*thread)->next = NULL;
+
+ (*thread)->lock = SEMAPHORE_CLEAR;
+ (*thread)->error = 0;
+
+ sig_prevent();
+
+ /* Add to the link list of all threads. */
+ (*thread)->pll = pthread_link_list;
+ pthread_link_list = (*thread);
+
+ (*thread)->state = PS_RUNNING;
+ sig_check_and_resume();
+
+ return(OK);
+ }
+ free((*thread));
+ }
+ return(ENOMEM);
+}
+
+/* ==========================================================================
+ * pthread_cancel()
+ *
+ * This routine will also require a sig_prevent/sig_check_and_resume()
+ */
diff --git a/lib/libpthread/pthreads/pthread_attr.c b/lib/libpthread/pthreads/pthread_attr.c
new file mode 100644
index 000000000000..639b240e63d0
--- /dev/null
+++ b/lib/libpthread/pthreads/pthread_attr.c
@@ -0,0 +1,96 @@
+/* ==== pthread_attr.c =======================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Pthread attribute functions.
+ *
+ * 1.00 93/11/04 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+
+/* Currently we do no locking, should we just to be safe? CAP */
+/* ==========================================================================
+ * pthread_attr_init()
+ */
+int pthread_attr_init(pthread_attr_t *attr)
+{
+ memcpy(attr, &pthread_default_attr, sizeof(pthread_attr_t));
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_destroy()
+ */
+int pthread_attr_destroy(pthread_attr_t *attr)
+{
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_getstacksize()
+ */
+int pthread_attr_getstacksize(pthread_attr_t *attr, size_t * stacksize)
+{
+ *stacksize = attr->stacksize_attr;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setstacksize()
+ */
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ if (stacksize >= PTHREAD_STACK_MIN) {
+ attr->stacksize_attr = stacksize;
+ return(OK);
+ }
+ return(EINVAL);
+}
+
+/* ==========================================================================
+ * pthread_attr_getstackaddr()
+ */
+int pthread_attr_getstackaddr(pthread_attr_t *attr, void ** stackaddr)
+{
+ *stackaddr = attr->stackaddr_attr;
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_attr_setstackaddr()
+ */
+int pthread_attr_setstackaddr(pthread_attr_t *attr, void * stackaddr)
+{
+ attr->stackaddr_attr = stackaddr;
+ return(OK);
+}
diff --git a/lib/libpthread/pthreads/pthread_detach.c b/lib/libpthread/pthreads/pthread_detach.c
new file mode 100644
index 000000000000..d996bf092dc3
--- /dev/null
+++ b/lib/libpthread/pthreads/pthread_detach.c
@@ -0,0 +1,86 @@
+/* ==== pthread_detach.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_join function.
+ *
+ * 1.00 94/01/15 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * pthread_detach()
+ */
+int pthread_detach(pthread_t pthread)
+{
+ semaphore *plock;
+ int ret;
+
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* Check that thread isn't detached already */
+ if (!(pthread->flags & PF_DETACHED)) {
+
+ pthread->flags |= PF_DETACHED;
+
+ /* Wakeup first threads waiting on a join */
+ {
+ struct pthread * next_thread;
+ semaphore * next_lock;
+
+ if (next_thread = pthread_queue_get(&(pthread->join_queue))) {
+ next_lock = &(next_thread->lock);
+ while (SEMAPHORE_TEST_AND_SET(next_lock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&(pthread->join_queue));
+ next_thread->state = PS_RUNNING;
+ /*
+ * Thread will wake up in pthread_join(), see the thread
+ * it was joined to already detached and unlock itself
+ * and pthread
+ */
+ } else {
+ SEMAPHORE_RESET(plock);
+ }
+ }
+ ret = OK;
+
+ } else {
+ SEMAPHORE_RESET(plock);
+ ret = ESRCH;
+ }
+ return(ret);
+}
diff --git a/lib/libpthread/pthreads/pthread_join.c b/lib/libpthread/pthreads/pthread_join.c
new file mode 100644
index 000000000000..773098618972
--- /dev/null
+++ b/lib/libpthread/pthreads/pthread_join.c
@@ -0,0 +1,109 @@
+/* ==== pthread_join.c =======================================================
+ * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_join function.
+ *
+ * 1.00 94/01/15 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * pthread_join()
+ */
+int pthread_join(pthread_t pthread, void **thread_return)
+{
+ semaphore *lock, *plock;
+ int ret;
+
+
+ plock = &(pthread->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* Check that thread isn't detached already */
+ if (pthread->flags & PF_DETACHED) {
+ SEMAPHORE_RESET(plock);
+ return(ESRCH);
+ }
+
+ lock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* If OK then queue current thread. */
+ pthread_queue(&(pthread->join_queue), pthread_run);
+
+ SEMAPHORE_RESET(plock);
+ reschedule(PS_JOIN);
+
+ /*
+ * At this point the thread is locked from the pthread_exit
+ * and so are we, so no extra locking is required, but be sure
+ * to unlock at least ourself.
+ */
+ if (!(pthread->flags & PF_DETACHED)) {
+ if (thread_return) {
+ *thread_return = pthread->ret;
+ }
+ pthread->flags |= PF_DETACHED;
+ ret = OK;
+ } else {
+ ret = ESRCH;
+ }
+
+ /* Cant do a cleanup until queue is cleared */
+ {
+ struct pthread * next_thread;
+ semaphore * next_lock;
+
+ if (next_thread = pthread_queue_get(&(pthread->join_queue))) {
+ next_lock = &(next_thread->lock);
+ while (SEMAPHORE_TEST_AND_SET(next_lock)) {
+ pthread_yield();
+ }
+ pthread_queue_deq(&(pthread->join_queue));
+ next_thread->state = PS_RUNNING;
+ /*
+ * Thread will wake up in pthread_join(), see the thread
+ * it was joined to already detached and unlock itself
+ */
+ } else {
+ SEMAPHORE_RESET(lock);
+ }
+ }
+
+ SEMAPHORE_RESET(plock);
+ return(ret);
+}
diff --git a/lib/libpthread/pthreads/pthread_once.c b/lib/libpthread/pthreads/pthread_once.c
new file mode 100644
index 000000000000..fe791440eda3
--- /dev/null
+++ b/lib/libpthread/pthreads/pthread_once.c
@@ -0,0 +1,57 @@
+/* ==== pthread_once.c =======================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_once function.
+ *
+ * 1.00 93/12/12 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+
+/* ==========================================================================
+ * pthread_once()
+ */
+static pthread_mutex_t __pthread_once_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+ /* Check first for speed */
+ if (*once_control == PTHREAD_ONCE_INIT) {
+ pthread_mutex_lock(&__pthread_once_mutex);
+ if (*once_control == PTHREAD_ONCE_INIT) {
+ init_routine();
+ (*once_control)++;
+ }
+ pthread_mutex_unlock(&__pthread_once_mutex);
+ }
+ return(OK);
+}
diff --git a/lib/libpthread/pthreads/queue.c b/lib/libpthread/pthreads/queue.c
new file mode 100644
index 000000000000..7e5ff372d2f7
--- /dev/null
+++ b/lib/libpthread/pthreads/queue.c
@@ -0,0 +1,119 @@
+/* ==== queue.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Queue functions.
+ *
+ * 1.00 93/07/15 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+
+/*
+ * All routines in this file assume that the queue has been appropriatly
+ * locked.
+ */
+
+/* ==========================================================================
+ * pthread_queue_init()
+ */
+void pthread_queue_init(struct pthread_queue *queue)
+{
+ queue->q_next = NULL;
+ queue->q_last = NULL;
+ queue->q_data = NULL;
+}
+
+/* ==========================================================================
+ * pthread_queue_enq()
+ */
+void pthread_queue_enq(struct pthread_queue *queue, struct pthread *thread)
+{
+ if (queue->q_last) {
+ queue->q_last->next = thread;
+ } else {
+ queue->q_next = thread;
+ }
+ queue->q_last = thread;
+ thread->queue = queue;
+ thread->next = NULL;
+
+}
+
+/* ==========================================================================
+ * pthread_queue_get()
+ */
+struct pthread *pthread_queue_get(struct pthread_queue *queue)
+{
+ return(queue->q_next);
+}
+
+/* ==========================================================================
+ * pthread_queue_deq()
+ */
+struct pthread *pthread_queue_deq(struct pthread_queue *queue)
+{
+ struct pthread *thread = NULL;
+
+ if (queue->q_next) {
+ thread = queue->q_next;
+ if (!(queue->q_next = queue->q_next->next)) {
+ queue->q_last = NULL;
+ }
+ thread->queue = NULL;
+ thread->next = NULL;
+ }
+ return(thread);
+}
+
+/* ==========================================================================
+ * pthread_queue_remove()
+ */
+void pthread_queue_remove(struct pthread_queue *queue, struct pthread *thread)
+{
+ struct pthread **current = &(queue->q_next);
+ struct pthread *prev = NULL;
+
+ while (*current) {
+ if (*current == thread) {
+ if ((*current)->next) {
+ *current = (*current)->next;
+ } else {
+ queue->q_last = prev;
+ *current = NULL;
+ }
+ }
+ prev = *current;
+ current = &((*current)->next);
+ }
+ thread->queue = NULL;
+ thread->next = NULL;
+}
diff --git a/lib/libpthread/pthreads/signal.c b/lib/libpthread/pthreads/signal.c
new file mode 100644
index 000000000000..b181b84dac14
--- /dev/null
+++ b/lib/libpthread/pthreads/signal.c
@@ -0,0 +1,426 @@
+/* ==== signal.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Queue functions.
+ *
+ * 1.00 93/07/21 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <signal.h>
+
+/*
+ * Time which select in fd_kern_wait() will sleep.
+ * If there are no threads to run we sleep for an hour or until
+ * we get an interrupt or an fd thats awakens. To make sure we
+ * don't miss an interrupt this variable gets reset too zero in
+ * sig_handler_real().
+ */
+struct timeval __fd_kern_wait_timeout = { 0, 0 };
+
+/*
+ * Global for user-kernel lock, and blocked signals
+ */
+static volatile sigset_t sig_to_tryagain;
+static volatile sigset_t sig_to_process;
+static volatile int kernel_lock = 0;
+static volatile int sig_count = 0;
+
+static void sig_handler(int signal);
+static void set_thread_timer();
+void sig_prevent(void);
+void sig_resume(void);
+
+/* ==========================================================================
+ * context_switch()
+ *
+ * This routine saves the current state of the running thread gets
+ * the next thread to run and restores it's state. To allow different
+ * processors to work with this routine, I allow the machdep_restore_state()
+ * to either return or have it return from machdep_save_state with a value
+ * other than 0, this is for implementations which use setjmp/longjmp.
+ */
+static void context_switch()
+{
+ struct pthread **current, *next, *last;
+ semaphore *lock;
+ int count;
+
+ /* save state of current thread */
+ if (machdep_save_state()) {
+ return;
+ }
+
+ last = pthread_run;
+ if (pthread_run = pthread_queue_deq(&pthread_current_queue)) {
+ /* restore state of new current thread */
+ machdep_restore_state();
+ return;
+ }
+
+ /* Poll all the kernel fds */
+ fd_kern_poll();
+
+context_switch_reschedule:;
+ /*
+ * Go through the reschedule list once, this is the only place
+ * that goes through the queue without using the queue routines.
+ *
+ * But first delete the current queue.
+ */
+ pthread_queue_init(&pthread_current_queue);
+ current = &(pthread_link_list);
+ count = 0;
+
+ while (*current) {
+ switch((*current)->state) {
+ case PS_RUNNING:
+ pthread_queue_enq(&pthread_current_queue, *current);
+ current = &((*current)->pll);
+ count++;
+ break;
+ case PS_DEAD:
+ /* Cleanup thread, unless we're using the stack */
+ if (((*current)->flags & PF_DETACHED) && (*current != last)) {
+ next = (*current)->pll;
+ lock = &((*current)->lock);
+ if (SEMAPHORE_TEST_AND_SET(lock)) {
+ /* Couldn't cleanup this time, try again later */
+ current = &((*current)->pll);
+ } else {
+ if (!((*current)->attr.stackaddr_attr)) {
+ free (machdep_pthread_cleanup(&((*current)->machdep_data)));
+ }
+ free (*current);
+ *current = next;
+ }
+ } else {
+ current = &((*current)->pll);
+ }
+ break;
+ default:
+ /* Should be on a different queue. Ignore. */
+ current = &((*current)->pll);
+ count++;
+ break;
+ }
+ }
+
+ /* Are there any threads to run */
+ if (pthread_run = pthread_queue_deq(&pthread_current_queue)) {
+ /* restore state of new current thread */
+ machdep_restore_state();
+ return;
+ }
+
+ /* Are there any threads at all */
+ if (count) {
+ /*
+ * Do a wait, timeout is set to a hour unless we get an interrupt
+ * before the select in wich case it polls and returns.
+ */
+ fd_kern_wait();
+
+ /* Check for interrupts, but ignore SIGVTALR */
+ sigdelset(&sig_to_process, SIGVTALRM);
+
+ if (sig_to_process) {
+ /* Process interrupts */
+ sig_handler(0);
+ }
+
+ goto context_switch_reschedule;
+
+ }
+ exit(0);
+}
+
+/* ==========================================================================
+ * sig_handler_pause()
+ *
+ * Wait until a signal is sent to the process.
+ */
+void sig_handler_pause()
+{
+ sigset_t sig_to_block, sig_to_pause;
+
+ sigfillset(&sig_to_block);
+ sigemptyset(&sig_to_pause);
+ sigprocmask(SIG_BLOCK, &sig_to_block, NULL);
+ if (!sig_to_process) {
+ sigsuspend(&sig_to_pause);
+ }
+ sigprocmask(SIG_UNBLOCK, &sig_to_block, NULL);
+}
+
+/* ==========================================================================
+ * context_switch_done()
+ *
+ * This routine does all the things that are necessary after a context_switch()
+ * calls the machdep_restore_state(). DO NOT put this in the context_switch()
+ * routine because sometimes the machdep_restore_state() doesn't return
+ * to context_switch() but instead ends up in machdep_thread_start() or
+ * some such routine, which will need to call this routine and
+ * sig_check_and_resume().
+ */
+void context_switch_done()
+{
+ sigdelset(&sig_to_process, SIGVTALRM);
+ set_thread_timer();
+}
+
+/* ==========================================================================
+ * set_thread_timer()
+ *
+ * Assums kernel is locked.
+ */
+static void set_thread_timer()
+{
+ static int last_sched_attr = SCHED_RR;
+
+ switch (pthread_run->attr.sched_attr) {
+ case SCHED_RR:
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ break;
+ case SCHED_FIFO:
+ if (last_sched_attr != SCHED_FIFO) {
+ machdep_unset_thread_timer();
+ }
+ break;
+ case SCHED_IO:
+ if ((last_sched_attr != SCHED_IO) && (!sig_count)) {
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ }
+ break;
+ default:
+ machdep_set_thread_timer(&(pthread_run->machdep_data));
+ break;
+ }
+ last_sched_attr = pthread_run->attr.sched_attr;
+}
+
+/* ==========================================================================
+ * sig_handler()
+ *
+ * Assumes the kernel is locked.
+ */
+static void sig_handler(int sig)
+{
+
+ /*
+ * First check for old signals, do one pass through and don't
+ * check any twice.
+ */
+ if (sig_to_tryagain) {
+ if (sigismember(&sig_to_tryagain, SIGALRM)) {
+ switch (sleep_wakeup()) {
+ case 1:
+ /* Do the default action, no threads were sleeping */
+ case OK:
+ /* Woke up a sleeping thread */
+ sigdelset(&sig_to_tryagain, SIGALRM);
+ break;
+ case NOTOK:
+ /* Couldn't get appropriate locks, try again later */
+ break;
+ }
+ } else {
+ PANIC();
+ }
+ }
+
+ /*
+ * NOW, process signal that just came in, plus any pending on the
+ * signal mask. All of these must be resolved.
+ */
+
+sig_handler_top:;
+
+ switch(sig) {
+ case 0:
+ break;
+ case SIGVTALRM:
+ if (sig_count) {
+ sigset_t sigall;
+
+ sig_count = 0;
+
+ /* Unblock all signals */
+ sigemptyset(&sigall);
+ sigprocmask(SIG_SETMASK, &sigall, NULL);
+ }
+ context_switch();
+ context_switch_done();
+ break;
+ case SIGALRM:
+ sigdelset(&sig_to_process, SIGALRM);
+ switch (sleep_wakeup()) {
+ case 1:
+ /* Do the default action, no threads were sleeping */
+ case OK:
+ /* Woke up a sleeping thread */
+ break;
+ case NOTOK:
+ /* Couldn't get appropriate locks, try again later */
+ sigaddset(&sig_to_tryagain, SIGALRM);
+ break;
+ }
+ break;
+ default:
+ PANIC();
+ }
+
+ /* Determine if there are any other signals */
+ if (sig_to_process) {
+ for (sig = 1; sig <= SIGMAX; sig++) {
+ if (sigismember(&sig_to_process, sig)) {
+
+ /* goto sig_handler_top */
+ goto sig_handler_top;
+ }
+ }
+ }
+}
+
+/* ==========================================================================
+ * sig_handler_real()
+ *
+ * On a multi-processor this would need to use the test and set instruction
+ * otherwise the following will work.
+ */
+void sig_handler_real(int sig)
+{
+ if (kernel_lock) {
+ __fd_kern_wait_timeout.tv_sec = 0;
+ sigaddset(&sig_to_process, sig);
+ return;
+ }
+ sig_prevent();
+ sig_count++;
+ sig_handler(sig);
+ sig_resume();
+}
+
+/* ==========================================================================
+ * sig_handler_fake()
+ */
+void sig_handler_fake(int sig)
+{
+ if (kernel_lock) {
+ /* Currently this should be impossible */
+ PANIC();
+ }
+ sig_prevent();
+ sig_handler(sig);
+ sig_resume();
+}
+
+/* ==========================================================================
+ * reschedule()
+ *
+ * This routine assumes that the caller is the current pthread, pthread_run
+ * and that it has a lock on itself and that it wants to reschedule itself.
+ */
+void reschedule(enum pthread_state state)
+{
+ semaphore *plock;
+
+ if (kernel_lock) {
+ /* Currently this should be impossible */
+ PANIC();
+ }
+ sig_prevent();
+ pthread_run->state = state;
+ SEMAPHORE_RESET((plock = &(pthread_run->lock)));
+ sig_handler(SIGVTALRM);
+ sig_resume();
+}
+
+/* ==========================================================================
+ * sig_prevent()
+ */
+void sig_prevent(void)
+{
+ kernel_lock++;
+}
+
+/* ==========================================================================
+ * sig_resume()
+ */
+void sig_resume()
+{
+ kernel_lock--;
+}
+
+/* ==========================================================================
+ * sig_check_and_resume()
+ */
+void sig_check_and_resume()
+{
+ /* Some routine name that is yet to be determined. */
+
+ /* Only bother if we are truely unlocking the kernel */
+ while (!(--kernel_lock)) {
+
+ /* Assume sigset_t is not a struct or union */
+ if (sig_to_process) {
+ kernel_lock++;
+ sig_handler(0);
+ } else {
+ break;
+ }
+ }
+}
+
+/* ==========================================================================
+ * sig_init()
+ *
+ * SIGVTALRM (NOT POSIX) needed for thread timeslice timeouts.
+ * Since it's not POSIX I will replace it with a
+ * virtual timer for threads.
+ * SIGALRM (IS POSIX) so some special handling will be
+ * necessary to fake SIGALRM signals
+ */
+void sig_init(void)
+{
+ int sig_to_init[] = { SIGVTALRM, SIGALRM, 0 };
+ int i;
+
+ /* Initialize only the necessary signals */
+
+ for (i = 0; sig_to_init[i]; i++) {
+ if (signal(sig_to_init[i], sig_handler_real)) {
+ PANIC();
+ }
+ }
+}
+
diff --git a/lib/libpthread/pthreads/sleep.c b/lib/libpthread/pthreads/sleep.c
new file mode 100644
index 000000000000..30b5d24d7e38
--- /dev/null
+++ b/lib/libpthread/pthreads/sleep.c
@@ -0,0 +1,227 @@
+/* ==== sleep.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : Condition cariable functions.
+ *
+ * 1.00 93/12/28 proven
+ * -Started coding this file.
+ */
+
+#include <pthread.h>
+#include <unistd.h>
+
+struct pthread * pthread_sleep = NULL;
+semaphore sleep_semaphore = SEMAPHORE_CLEAR;
+
+
+#include <sys/time.h>
+#include <stdio.h>
+
+/* ==========================================================================
+ * machdep_start_timer()
+ */
+int machdep_start_timer(struct itimerval *start_time_val)
+{
+ setitimer(ITIMER_REAL, start_time_val, NULL);
+ return(OK);
+}
+
+/* ==========================================================================
+ * machdep_stop_timer()
+ */
+struct itimerval stop_time_val = { { 0, 0 }, { 0, 0 } };
+int machdep_stop_timer(struct itimerval * current)
+{
+ setitimer(ITIMER_REAL, &stop_time_val, current);
+ return(OK);
+}
+
+/* ==========================================================================
+ * machdep_sub_timer()
+ *
+ * formula is: new -= current;
+ */
+static inline void machdep_sub_timer(struct itimerval * new,
+ struct itimerval * current)
+{
+ new->it_value.tv_usec -= current->it_value.tv_usec;
+ if (new->it_value.tv_usec < 0) {
+ new->it_value.tv_usec += 1000000;
+ new->it_value.tv_sec--;
+ }
+ new->it_value.tv_sec -= current->it_value.tv_sec;
+}
+
+
+/* ==========================================================================
+ * sleep_wakeup()
+ *
+ * This routine is called by the interrupt handler. It cannot call
+ * pthread_yield() thenrfore it returns NOTOK to inform the handler
+ * that it will have to be called at a later time.
+ */
+int sleep_wakeup()
+{
+ struct pthread *pthread_sleep_next;
+ struct itimerval current_time;
+ semaphore *lock, *plock;
+
+ /* Lock sleep queue */
+ lock = &(sleep_semaphore);
+ if (SEMAPHORE_TEST_AND_SET(lock)) {
+ return(NOTOK);
+ }
+ if (pthread_sleep) {
+
+ plock = &(pthread_sleep->lock);
+ if (SEMAPHORE_TEST_AND_SET(plock)) {
+ SEMAPHORE_RESET(lock);
+ return(NOTOK);
+ }
+
+ /* return remaining time */
+ machdep_stop_timer(&current_time);
+ pthread_sleep->time_sec = current_time.it_value.tv_sec;
+ pthread_sleep->time_usec = current_time.it_value.tv_usec;
+
+ if (pthread_sleep_next = pthread_sleep->sll) {
+ pthread_sleep_next->time_usec += current_time.it_value.tv_usec;
+ current_time.it_value.tv_usec = pthread_sleep_next->time_usec;
+ pthread_sleep_next->time_sec += current_time.it_value.tv_sec;
+ current_time.it_value.tv_sec = pthread_sleep_next->time_sec;
+ machdep_start_timer(&current_time);
+ }
+
+ /* Clean up removed thread and start it runnng again. */
+ pthread_sleep->state = PS_RUNNING;
+ pthread_sleep->sll = NULL;
+ SEMAPHORE_RESET(plock);
+
+ /* Set top of queue to next queue item */
+ pthread_sleep = pthread_sleep_next;
+ }
+ SEMAPHORE_RESET(lock);
+ return(OK);
+}
+
+/* ==========================================================================
+ * sleep()
+ */
+unsigned int sleep(unsigned int seconds)
+{
+ struct pthread *pthread_sleep_current, *pthread_sleep_prev;
+ struct itimerval current_time, new_time;
+ semaphore *lock, *plock;
+
+ if (seconds) {
+ /* Lock current thread */
+ plock = &(pthread_run->lock);
+ while (SEMAPHORE_TEST_AND_SET(plock)) {
+ pthread_yield();
+ }
+
+ /* Set new_time timer value */
+ new_time.it_value.tv_usec = 0;
+ new_time.it_value.tv_sec = seconds;
+
+ /* Lock sleep queue */
+ lock = &(sleep_semaphore);
+ while (SEMAPHORE_TEST_AND_SET(lock)) {
+ pthread_yield();
+ }
+
+ /* any threads? */
+ if (pthread_sleep_current = pthread_sleep) {
+
+ machdep_stop_timer(&current_time);
+
+ /* Is remaining time left <= new thread time */
+ if (current_time.it_value.tv_sec < new_time.it_value.tv_sec) {
+ machdep_sub_timer(&new_time, &current_time);
+ machdep_start_timer(&current_time);
+
+ while (pthread_sleep_current->sll) {
+ pthread_sleep_prev = pthread_sleep_current;
+ pthread_sleep_current = pthread_sleep_current->sll;
+ current_time.it_value.tv_sec = pthread_sleep_current->time_sec;
+
+ if ((current_time.it_value.tv_sec > new_time.it_value.tv_sec) ||
+ ((current_time.it_value.tv_sec == new_time.it_value.tv_sec) &&
+ (current_time.it_value.tv_usec > new_time.it_value.tv_usec))) {
+ pthread_run->time_usec = new_time.it_value.tv_usec;
+ pthread_run->time_sec = new_time.it_value.tv_sec;
+ machdep_sub_timer(&current_time, &new_time);
+ pthread_run->sll = pthread_sleep_current;
+ pthread_sleep_prev->sll = pthread_run;
+
+ /* Unlock sleep mutex */
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule thread */
+ reschedule(PS_SLEEP_WAIT);
+
+ return(pthread_run->time_sec);
+ }
+ machdep_sub_timer(&new_time, &current_time);
+
+ }
+
+ /* No more threads in queue, attach pthread_run to end of list */
+ pthread_sleep_current->sll = pthread_run;
+ pthread_run->sll = NULL;
+
+ } else {
+ /* Start timer and enqueue thread */
+ machdep_start_timer(&new_time);
+ current_time.it_value.tv_sec -= new_time.it_value.tv_sec;
+ pthread_run->sll = pthread_sleep_current;
+ pthread_sleep = pthread_run;
+ }
+ } else {
+ /* Start timer and enqueue thread */
+ machdep_start_timer(&new_time);
+ pthread_sleep = pthread_run;
+ pthread_run->sll = NULL;
+ }
+
+ pthread_run->time_usec = new_time.it_value.tv_usec;
+ pthread_run->time_sec = new_time.it_value.tv_sec;
+
+ /* Unlock sleep mutex */
+ SEMAPHORE_RESET(lock);
+
+ /* Reschedule thread */
+ reschedule(PS_SLEEP_WAIT);
+
+ }
+ return(pthread_run->time_sec);
+}
+