diff options
Diffstat (limited to 'lib/libpthread/pthreads')
| -rw-r--r-- | lib/libpthread/pthreads/Makefile.inc | 13 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/cond.c | 204 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/fd.c | 558 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/fd_kern.c | 643 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/fd_pipe.c | 264 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/file.c | 113 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/globals.c | 63 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/malloc.c | 357 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/mutex.c | 223 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/pthread.c | 200 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/pthread_attr.c | 96 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/pthread_detach.c | 86 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/pthread_join.c | 109 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/pthread_once.c | 57 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/queue.c | 119 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/signal.c | 426 | ||||
| -rw-r--r-- | lib/libpthread/pthreads/sleep.c | 227 |
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(¤t_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(¤t_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(¤t_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, ¤t_time); + machdep_start_timer(¤t_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(¤t_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, ¤t_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); +} + |
