diff options
author | 1998-07-21 13:18:53 +0000 | |
---|---|---|
committer | 1998-07-21 13:18:53 +0000 | |
commit | f952fe14eda234ea5d83f0b522bb74b1b138dec8 (patch) | |
tree | d163cb6c22fefe1aeb984101bd7bf3bf8a2fd7d9 /lib/libpthread | |
parent | Complete initial import from mySQL 3.22.4 (mit-pthreads/). (diff) | |
download | wireguard-openbsd-f952fe14eda234ea5d83f0b522bb74b1b138dec8.tar.xz wireguard-openbsd-f952fe14eda234ea5d83f0b522bb74b1b138dec8.zip |
Complete initial import from mySQL 3.22.4 (mit-pthreads/).
Lots of dross to move and remove yet.
At minimum:
o remove GNU config and GNU Makefiles
o build arch directory and migrate away machdep/
o rebuild BSD Makefiles
o move notes etc. into doc/
Diffstat (limited to 'lib/libpthread')
83 files changed, 4622 insertions, 1632 deletions
diff --git a/lib/libpthread/COPYRIGHT b/lib/libpthread/COPYRIGHT index 1fb4e43cf26..1b727cd8dac 100644 --- a/lib/libpthread/COPYRIGHT +++ b/lib/libpthread/COPYRIGHT @@ -1,5 +1,5 @@ -Copyright (c) 1993 by Chris Provenzano and contributors, proven@mit.edu -All rights reserved. +Copyright (c) 1993, 1994, 1995, 1996 by Chris Provenzano and contributors, +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 diff --git a/lib/libpthread/README b/lib/libpthread/README index f546325d948..0a55bcd94bb 100644 --- a/lib/libpthread/README +++ b/lib/libpthread/README @@ -1,15 +1,19 @@ -This pthread package is/will be based on the POSIX1003.4a Draft 7 pthread -standard, and Frank Mullers paper on signal handelling presented -at the Winter 93 USENIX conference. +This pthread package is/will be based on the POSIX1003.1c Draft 10 pthread +standard, and Frank Muellers paper on signal handeling presented at the +Winter 93 USENIX conference. It is currently being designed and written by me, Chris Provenzano. -All bug, comments, and questions can be sent me at either -proven@athena.mit.edu or proven@sun-lamp.cs.berkeley.edu -PLEASE, don't send questions, bugs or patches to any of the *BSD* mailing lists. +All bug, comments, and questions can be sent me at proven@mit.edu, +or pthreads@mit.edu. -Thanks goes to John Carr jfc@mit.edu for porting this to the IBM/RT, -and for his bug reports and fixes, Greg Hudson and Mark Eichin for the -testing they've done, and all the others. +PLEASE, don't send questions, bugs or patches to any of the *BSD*, Linux +or GNU mailing lists. + +Thanks goes to Ken Raeburn for his help on the Sparc port, the configurator, +and his many suggestions, Greg Hudson for the thread safe net routines and +all the testing he's done. + +More thanks to Mark Eichin and all the others for the testing they have done. PORTING One of the goals of this user space implementation of pthreads is that it @@ -18,68 +22,19 @@ but some is. If you want to port it to another platform here are a few basic hints. -There are currently three files you'll have to creat for your -architecture, machdep.h, machdep.c and syscall.S. -The first two are necessary to get the context switch section of -the pthread package running, the third is for all the syscalls. - -To do an initial port, create an appropriate machdep.h, and machdep.c -and define PTHREAD_INITIAL_PORT in the Makefile - -Comment out references to the stdio package. +You will need to create a machdep.h, machdep.c and syscall.S for the +new architecture. The first two are necessary to get the context switch +section of the pthread package running, the third is for all the syscalls. INCLUDE FILES AND PORTING -To continue to make this package portable, some basic rules on includes -files must be followed. - -pthread.h should be included first (if it is to be included). -machdep.h should define size_t if the system doesn't define it already - -posix.h should be included last. This file is used to correct non -POSIX features, after everything else has been defined. - -INTERNAL LOCKING -To prevent deadlocks the following rules were used for locks. - -1. Local locks for mutex queues and other like things are only locked - by running threads, at NO time will a local lock be held by - a thread in a non running state. -2. Only threads that are in a run state can attempt to lock another thread, - this way, we can assume that the lock will be released shortly, and don't - have to unlock the local lock. -3. The only time a thread will have a pthread->lock and is not in a run - state is when it is in the reschedule routine. -4. The reschedule routine assumes all local locks have been released, - there is a lock on the currently running thread (pthread_run), - and that this thread is being rescheduled to a non running state. - It is safe to unlock the currently running threads lock after it - has been rescheduled. -5. The reschedule routine locks the kernel, sets the state of the currently - running thread, unlocks the currently running thread, calls the - context switch routines. -6 the kernel lock is used only ... - - -7. The order of locking is ... - -1 local locks -2 pthread->lock /* Assumes it will get it soon */ -3 pthread_run->lock /* Assumes it will get it soon, but must release 2 */ -4 kernel lock /* Currently assumes it will ALWAYS get it. */ - -8. The kernel lock will be changed to a spin lock for systems that -already support kernel threads, this way we can mutiplex threads onto -kernel threads. -9. There are points where the kernel is locked and it needs to get -either a local lock or a pthread lock, if at these points the code -fails to get the lock the kernel gives up and sets a flag which will -be checked at a later point. -10. Interrupts are dissabled while the kernel is locked, the interrupt -mask must be checked afterwards or cleared in some way, after interrputs -have been reenabled, this allows back to back interrupts, but should always -avoid missing one. - -Copyright (c) 1993 Chris Provenzano. All rights reserved. +In addition to the above three files you need to create a slew of .h files. +Take a look at an existing port to determine what is in each, and then +take a look at your system header files to determine what to put in them. +------------------------------------------------------------------------------ +Copyright (c) 1993, 1994, 1995, 1996 Chris Provenzano. All rights reserved. This product includes software developed by the Univeristy of California, Berkeley and its contributors. + +For further licencing and distribution restrictions see the file COPYRIGHT +included in this directory. diff --git a/lib/libpthread/pthreads/Makefile.inc b/lib/libpthread/pthreads/Makefile.inc index 86c63233c1a..dfb02045351 100644 --- a/lib/libpthread/pthreads/Makefile.inc +++ b/lib/libpthread/pthreads/Makefile.inc @@ -1,9 +1,65 @@ # from: @(#)Makefile.inc 5.6 (Berkeley) 6/4/91 # pthread sources -.PATH: ${.CURDIR}/pthreads +.PATH: ${srcdir}/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 +SRCS+= cleanup.c 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 machdep.c syscall.S \ + pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \ + process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \ + pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \ + dump_state.c pthread_kill.c condattr.c pthread_cancel.c panic.c + +.if $(HAVE_SYSCALL_TEMPLATE) == yes +OBJS+= syscalls.o +.if !defined(NOPIC) +SOBJS+= syscalls.so +SYSCALL_PIC_COMPILE= $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -DPIC -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.so +.else +SYSCALL_PIC_COMPILE= true +.endif +.if !defined(NOPROFILE) +POBJS+= syscalls.po +SYSCALL_PROF_COMPILE= $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -pg -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.po +.else +SYSCALL_PROF_COMPILE= true +.endif + +syscalls.o syscalls.so syscalls.po : syscall-template.S + -rm -rf ${.OBJDIR}/syscalls + mkdir ${.OBJDIR}/syscalls + for syscall in $(AVAILABLE_SYSCALLS) ; do \ + case " $(SYSCALL_EXCEPTIONS) " in \ + *" "$$syscall" "*) ;; \ + *) echo $$syscall ; \ + $(CC) $(CFLAGS) -DSYSCALL_NAME=$$syscall -c ${.CURDIR}/syscall-template.S -o ${.OBJDIR}/syscalls/S$$syscall.o ; \ + $(SYSCALL_PIC_COMPILE) ; \ + $(SYSCALL_PROF_COMPILE) ;; \ + esac ; \ + done + x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.o *.o && cd $$x +.if !defined(NOPIC) + x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.so *.so && cd $$x +.endif +.if !defined(NOPROFILE) + x=`pwd` && cd ${.OBJDIR}/syscalls && ld -r -o ../syscalls.po *.po && cd $$x +.endif + rm -r ${.OBJDIR}/syscalls +.endif + +syscall.o: syscall.S + cpp ${CPPFLAGS} ${.CURDIR}/syscall.S > syscall.i + as syscall.i + rm syscall.i + mv a.out syscall.o + +syscall.po: syscall.S + cpp ${CPPFLAGS} ${.CURDIR}/syscall.S > syscall.i + as syscall.i + rm syscall.i + mv a.out syscall.po + +MAN2+= + +MAN3+= diff --git a/lib/libpthread/pthreads/cond.c b/lib/libpthread/pthreads/cond.c index 50e7c8e3905..f84cfce0aab 100644 --- a/lib/libpthread/pthreads/cond.c +++ b/lib/libpthread/pthreads/cond.c @@ -29,19 +29,47 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Description : Condition cariable functions. + * Description : Condition variable functions. * * 1.00 93/10/28 proven * -Started coding this file. */ #ifndef lint -static const char rcsid[] = "$Id: cond.c,v 1.1.1.1 1995/10/18 08:43:04 deraadt Exp $ $provenid: cond.c,v 1.16 1994/02/07 02:18:35 proven Exp $"; +static const char rcsid[] = "$Id: cond.c,v 1.1.1.2 1998/07/21 13:19:50 peter Exp $"; #endif #include <pthread.h> +#include <sys/time.h> +#include <stdlib.h> +#include <timers.h> #include <errno.h> +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif + +/* ========================================================================== + * pthread_cond_is_debug() + * + * Check that cond is a debug cond and if so returns entry number into + * array of debug condes. + */ +static int pthread_cond_debug_count = 0; +static pthread_cond_t ** pthread_cond_debug_ptrs = NULL; +static pthread_mutex_t pthread_cond_debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +static inline int pthread_cond_is_debug(pthread_cond_t * cond) +{ + int i; + + for (i = 0; i < pthread_cond_debug_count; i++) { + if (pthread_cond_debug_ptrs[i] == cond) { + return(i); + } + } + return(NOTOK); +} /* ========================================================================== * pthread_cond_init() * @@ -49,24 +77,52 @@ static const char rcsid[] = "$Id: cond.c,v 1.1.1.1 1995/10/18 08:43:04 deraadt E * 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) +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) { + enum pthread_condtype type; + /* 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) { + type = cond_attr->c_type; + } else { + type = COND_TYPE_FAST; + } + + switch (type) { + case COND_TYPE_FAST: + case COND_TYPE_COUNTING_FAST: + break; + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_cond_t ** new; + + if ((new = (pthread_cond_t **)realloc(pthread_cond_debug_ptrs, + (pthread_cond_debug_count + 1) * (sizeof(void *)))) == NULL) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + return(ENOMEM); + } + pthread_cond_debug_ptrs = new; + pthread_cond_debug_ptrs[pthread_cond_debug_count++] = cond; + } else { + pthread_mutex_unlock(&pthread_cond_debug_mutex); return(EBUSY); } - cond->c_type = cond_attr->c_type; - } else { - cond->c_type = COND_TYPE_FAST; + pthread_mutex_unlock(&pthread_cond_debug_mutex); + break; + case COND_TYPE_STATIC_FAST: + defualt: + return(EINVAL); + break; } + /* Set all other paramaters */ pthread_queue_init(&cond->c_queue); cond->c_flags |= COND_FLAGS_INITED; - cond->c_lock = SEMAPHORE_CLEAR; + cond->c_type = type; return(OK); } @@ -75,10 +131,29 @@ int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) */ int pthread_cond_destroy(pthread_cond_t *cond) { + int i; + /* Only check if cond is of type other than fast */ switch(cond->c_type) { case COND_TYPE_FAST: + case COND_TYPE_COUNTING_FAST: break; + case COND_TYPE_DEBUG: + if (pthread_queue_get(&(cond->c_queue))) { + return(EBUSY); + } + pthread_mutex_lock(&pthread_cond_debug_mutex); + if ((i = pthread_cond_is_debug(cond)) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + return(EINVAL); + } + + /* Remove the cond from the list of debug condition variables */ + pthread_cond_debug_ptrs[i] = + pthread_cond_debug_ptrs[--pthread_cond_debug_count]; + pthread_cond_debug_ptrs[pthread_cond_debug_count] = NULL; + pthread_mutex_unlock(&pthread_cond_debug_mutex); + break; case COND_TYPE_STATIC_FAST: default: return(EINVAL); @@ -87,8 +162,6 @@ int pthread_cond_destroy(pthread_cond_t *cond) /* 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); } @@ -98,38 +171,170 @@ int pthread_cond_destroy(pthread_cond_t *cond) */ 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(); + pthread_sched_prevent(); + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + + /* + * Fast condition variables do not check for any error conditions. + */ + case COND_TYPE_FAST: + case COND_TYPE_STATIC_FAST: + pthread_queue_enq(&cond->c_queue, pthread_run); + pthread_mutex_unlock(mutex); + + pthread_run->data.mutex = mutex; + + SET_PF_WAIT_EVENT(pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + pthread_run->data.mutex = NULL; + + rval = pthread_mutex_lock(mutex); + return(rval); + break; + case COND_TYPE_COUNTING_FAST: + { + int count = mutex->m_data.m_count; + + pthread_queue_enq(&cond->c_queue, pthread_run); + pthread_mutex_unlock(mutex); + mutex->m_data.m_count = 1; + + pthread_run->data.mutex = mutex; + + SET_PF_WAIT_EVENT(pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + pthread_run->data.mutex = NULL; + + rval = pthread_mutex_lock(mutex); + mutex->m_data.m_count = count; + return(rval); + break; + } + default: + rval = EINVAL; + break; } + pthread_sched_resume(); + return(rval); +} + +/* ========================================================================== + * pthread_cond_timedwait() + */ +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + struct timespec current_time, new_time; + int rval = OK; + pthread_sched_prevent(); + machdep_gettimeofday(& current_time); + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + /* * 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(); + + /* Set pthread wakeup time*/ + pthread_run->wakeup_time = *abstime; + + /* Install us on the sleep queue */ + sleep_schedule (¤t_time, &(pthread_run->wakeup_time)); + + pthread_queue_enq(&cond->c_queue, pthread_run); + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + + pthread_run->data.mutex = mutex; + + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { + SET_ERRNO(ETIME); + rval = ETIME; } + + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_mutex_lock(mutex); + return(rval); + break; + case COND_TYPE_COUNTING_FAST: + { + int count = mutex->m_data.m_count; + + /* Set pthread wakeup time*/ + pthread_run->wakeup_time = *abstime; + + /* Install us on the sleep queue */ + sleep_schedule (¤t_time, &(pthread_run->wakeup_time)); + pthread_queue_enq(&cond->c_queue, pthread_run); + SET_PF_WAIT_EVENT(pthread_run); pthread_mutex_unlock(mutex); - SEMAPHORE_RESET(lock); + pthread_run->data.mutex = mutex; + + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ /* Reschedule will unlock pthread_run */ - reschedule(PS_COND_WAIT); + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { + SET_ERRNO(ETIME); + rval = ETIME; + } - return(pthread_mutex_lock(mutex)); + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_mutex_lock(mutex); + mutex->m_data.m_count = count; + return(rval); break; + } default: rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + pthread_sched_resume(); return(rval); } @@ -139,25 +344,28 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 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(); - } - + pthread_sched_prevent(); switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + 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(); + if (pthread = pthread_queue_deq(&cond->c_queue)) { + if ((SET_PF_DONE_EVENT(pthread)) == OK) { + pthread_sched_other_resume(pthread); + } else { + pthread_sched_resume(); } - pthread_queue_deq(&cond->c_queue); - pthread->state = PS_RUNNING; - SEMAPHORE_RESET(plock); + return(OK); } rval = OK; break; @@ -165,7 +373,7 @@ int pthread_cond_signal(pthread_cond_t *cond) rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + pthread_sched_resume(); return(rval); } @@ -176,26 +384,46 @@ int pthread_cond_signal(pthread_cond_t *cond) */ int pthread_cond_broadcast(pthread_cond_t *cond) { - struct pthread *pthread; - semaphore *lock, *plock; + struct pthread * pthread, * high_pthread, * low_pthread; int rval; - lock = &(cond->c_lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } - + pthread_sched_prevent(); switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + 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); + if (pthread = pthread_queue_deq(&cond->c_queue)) { pthread->state = PS_RUNNING; - SEMAPHORE_RESET(plock); + high_pthread = pthread; + + while (pthread = pthread_queue_deq(&cond->c_queue)) { + if (pthread->pthread_priority > + high_pthread->pthread_priority) { + low_pthread = high_pthread; + high_pthread = pthread; + } else { + low_pthread = pthread; + } + if ((SET_PF_DONE_EVENT(low_pthread)) == OK) { + pthread_prio_queue_enq(pthread_current_prio_queue, + low_pthread); + low_pthread->state = PS_RUNNING; + } + } + if ((SET_PF_DONE_EVENT(high_pthread)) == OK) { + pthread_sched_other_resume(high_pthread); + } else { + pthread_sched_resume(); + } + return(OK); } rval = OK; break; @@ -203,6 +431,7 @@ int pthread_cond_broadcast(pthread_cond_t *cond) rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + pthread_sched_resume(); return(rval); } + diff --git a/lib/libpthread/pthreads/fd.c b/lib/libpthread/pthreads/fd.c index 158dea9b00e..b7bf501dbab 100644 --- a/lib/libpthread/pthreads/fd.c +++ b/lib/libpthread/pthreads/fd.c @@ -39,13 +39,25 @@ */ #ifndef lint -static const char rcsid[] = "$Id: fd.c,v 1.1.1.1 1995/10/18 08:43:04 deraadt Exp $ $provenid: fd.c,v 1.16 1994/02/07 02:18:39 proven Exp $"; +static const char rcsid[] = "$Id: fd.c,v 1.1.1.2 1998/07/21 13:19:53 peter Exp $"; #endif #include <pthread.h> +#include <stdlib.h> +#include <unistd.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/uio.h> +#include <sys/ioctl.h> +#include "config.h" +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> /* For ioctl */ +#endif +#if __STDC__ #include <stdarg.h> +#else +#include <varargs.h> +#endif #include <fcntl.h> #include <errno.h> #include <pthread/posix.h> @@ -55,8 +67,77 @@ static const char rcsid[] = "$Id: fd.c,v 1.1.1.1 1995/10/18 08:43:04 deraadt Exp * * I really should dynamically figure out what the table size is. */ -int dtablesize = 64; -static struct fd_table_entry fd_entry[64]; +static pthread_mutex_t fd_table_mutex = PTHREAD_MUTEX_INITIALIZER; +static const int dtablecount = 4096/sizeof(struct fd_table_entry); +int dtablesize; + +static int fd_get_pthread_fd_from_kernel_fd( int ); + +/* ========================================================================== + * Allocate dtablecount entries at once and populate the fd_table. + * + * fd_init_entry() + */ +int fd_init_entry(int entry) +{ + struct fd_table_entry *fd_entry; + int i, round; + + if (fd_table[entry] == NULL) { + round = entry - entry % dtablecount; + + if ((fd_entry = (struct fd_table_entry *)malloc( + sizeof(struct fd_table_entry) * dtablecount)) == NULL) { + return(NOTOK); + } + + for (i = 0; i < dtablecount && round+i < dtablesize; i++) { + fd_table[round + i] = &fd_entry[i]; + + fd_table[round + i]->ops = NULL; + fd_table[round + i]->type = FD_NT; + fd_table[round + i]->fd.i = NOTOK; + fd_table[round + i]->flags = 0; + fd_table[round + i]->count = 0; + + pthread_mutex_init(&(fd_table[round + i]->mutex), NULL); + pthread_queue_init(&(fd_table[round + i]->r_queue)); + pthread_queue_init(&(fd_table[round + i]->w_queue)); + fd_table[round + i]->r_owner = NULL; + fd_table[round + i]->w_owner = NULL; + fd_table[round + i]->r_lockcount= 0; + fd_table[round + i]->w_lockcount= 0; + + fd_table[round + i]->next = NULL; + } + } + return(OK); +} + +/* ========================================================================== + * fd_check_entry() + */ +int fd_check_entry(unsigned int entry) +{ + int ret = OK; + + pthread_mutex_lock(&fd_table_mutex); + + if (entry < dtablesize) { + if (fd_table[entry] == NULL) { + if (fd_init_entry(entry)) { + SET_ERRNO(EBADF); + ret = -EBADF; + } + } + } else { + SET_ERRNO(EBADF); + ret = -EBADF; + } + + pthread_mutex_unlock(&fd_table_mutex); + return(ret); +} /* ========================================================================== * fd_init() @@ -65,30 +146,32 @@ 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; + if ((dtablesize = machdep_sys_getdtablesize()) < 0) { + /* Can't figure out the table size. */ + PANIC(); } - /* 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"); + /* select() can only handle FD_SETSIZE descriptors, so our inner loop will + * break if dtablesize is higher than that. This should be removed if and + * when the inner loop is rewritten to use poll(). */ + if (dtablesize > FD_SETSIZE) { + dtablesize = FD_SETSIZE; + } + + if (fd_table = (struct fd_table_entry **)malloc( + sizeof(struct fd_table_entry) * dtablesize)) { + memset(fd_table, 0, sizeof(struct fd_table_entry) * dtablesize); + if (fd_check_entry(0) == OK) { + return; + } + } + + /* + * There isn't enough memory to allocate a fd table at init time. + * This is a problem. + */ + PANIC(); + } /* ========================================================================== @@ -96,116 +179,143 @@ void fd_init(void) */ int fd_allocate() { - semaphore *lock; + pthread_mutex_t * mutex; 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; */ + if (fd_check_entry(i) == OK) { + mutex = &(fd_table[i]->mutex); + if (pthread_mutex_trylock(mutex)) { + continue; + } + if (fd_table[i]->count || fd_table[i]->r_owner + || fd_table[i]->w_owner) { + pthread_mutex_unlock(mutex); + continue; + } + if (fd_table[i]->type == FD_NT) { + /* Test to see if the kernel version is in use */ + if ((machdep_sys_fcntl(i, F_GETFL, NULL)) >= OK) { + /* If so continue; */ + pthread_mutex_unlock(mutex); + continue; + } + } + fd_table[i]->count++; + pthread_mutex_unlock(mutex); + return(i); } - fd_table[i]->count++; - SEMAPHORE_RESET(lock); - return(i); } - pthread_run->error = ENFILE; + SET_ERRNO(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) +/*---------------------------------------------------------------------- + * Function: fd_get_pthread_fd_from_kernel_fd + * Purpose: get the fd_table index of a kernel fd + * Args: fd = kernel fd to convert + * Returns: fd_table index, -1 if not found + * Notes: + *----------------------------------------------------------------------*/ +static int +fd_get_pthread_fd_from_kernel_fd( int kfd ) { - struct fd_table_entry *fd_valid; - int ret; + int j; - 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; + /* This is *SICK*, but unless there is a faster way to + * turn a kernel fd into an fd_table index, this has to do. + */ + for( j=0; j < dtablesize; j++ ) { + if( fd_table[j] && + fd_table[j]->type != FD_NT && + fd_table[j]->type != FD_NIU && + fd_table[j]->fd.i == kfd ) { + return j; + } } - 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); + /* Not listed byfd, Check for kernel fd == pthread fd */ + if( fd_table[kfd] == NULL || fd_table[kfd]->type == FD_NT ) { + /* Assume that the kernel fd is the same */ + return kfd; + } + + return NOTOK; /* Not found */ } /* ========================================================================== - * fd_basic_unlock() - * + * fd_basic_basic_unlock() + * * The real work of unlock without the locking of fd_table[fd].lock. */ -void fd_basic_unlock(int fd, int lock_type) +void fd_basic_basic_unlock(struct fd_table_entry * entry, 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 (entry->r_owner == pthread_run) { + if ((entry->type == FD_HALF_DUPLEX) || + (entry->type == FD_TEST_HALF_DUPLEX) || + (lock_type == FD_READ) || (lock_type == FD_RDWR)) { + if (entry->r_lockcount == 0) { + if (pthread = pthread_queue_deq(&entry->r_queue)) { + pthread_sched_prevent(); + entry->r_owner = pthread; + if ((SET_PF_DONE_EVENT(pthread)) == OK) { + pthread_sched_other_resume(pthread); + } else { + pthread_sched_resume(); + } + } else { + entry->r_owner = NULL; + } + } else { + entry->r_lockcount--; + } + } } - 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; - } + if (entry->w_owner == pthread_run) { + if ((entry->type != FD_HALF_DUPLEX) && + (entry->type != FD_TEST_HALF_DUPLEX) && + ((lock_type == FD_WRITE) || (lock_type == FD_RDWR))) { + if (entry->w_lockcount == 0) { + if (pthread = pthread_queue_deq(&entry->w_queue)) { + pthread_sched_prevent(); + entry->w_owner = pthread; + if ((SET_PF_DONE_EVENT(pthread)) == OK) { + pthread_sched_other_resume(pthread); + } else { + pthread_sched_resume(); + } + } else { + entry->w_owner = NULL; + } + } else { + entry->w_lockcount--; + } + } } } /* ========================================================================== + * fd_basic_unlock() + */ +void fd_basic_unlock(int fd, int lock_type) +{ + fd_basic_basic_unlock(fd_table[fd], lock_type); +} + +/* ========================================================================== * 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; + pthread_mutex_t *mutex; - 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); - } + mutex = &(fd_table[fd]->mutex); + pthread_mutex_lock(mutex); + fd_basic_basic_unlock(fd_table[fd], lock_type); + pthread_mutex_unlock(mutex); } /* ========================================================================== @@ -214,64 +324,126 @@ void fd_unlock(int fd, int lock_type) * 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) +int fd_basic_lock(unsigned int fd, int lock_type, pthread_mutex_t * mutex, + struct timespec * timeout) { semaphore *plock; - /* If not in use return EBADF error */ - if (fd_table[fd]->type == FD_NIU) { + switch (fd_table[fd]->type) { + case FD_NIU: + /* If not in use return EBADF error */ + SET_ERRNO(EBADF); 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) { + break; + case FD_NT: + /* + * If not tested, test it and see if it is valid + * If not ok return EBADF error + */ + fd_kern_init(fd); + if (fd_table[fd]->type == FD_NIU) { + SET_ERRNO(EBADF); return(NOTOK); } + break; + case FD_TEST_HALF_DUPLEX: + case FD_TEST_FULL_DUPLEX: + /* If a parent process reset the fd to its proper state */ + if (!fork_lock) { + /* It had better be a kernel fd */ + fd_kern_reset(fd); + } + break; + default: + break; } + if ((fd_table[fd]->type == FD_HALF_DUPLEX) || - (lock_type & FD_READ)) { + (fd_table[fd]->type == FD_TEST_HALF_DUPLEX) || + (lock_type == FD_READ) || (lock_type == FD_RDWR)) { 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_sched_prevent(); pthread_queue_enq(&fd_table[fd]->r_queue, pthread_run); - SEMAPHORE_RESET(lock); - - /* Reschedule will unlock pthread_run */ - reschedule(PS_FDLR_WAIT); + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + /* Reschedule will unlock pthread_run */ + pthread_run->data.fd.fd = fd; + pthread_run->data.fd.branch = __LINE__; + pthread_resched_resume(PS_FDLR_WAIT); + pthread_mutex_lock(mutex); + + /* If we're the owner then we have to cancel the sleep */ + if (fd_table[fd]->r_owner != pthread_run) { + CLEAR_PF_DONE_EVENT(pthread_run); + SET_ERRNO(ETIMEDOUT); + return(NOTOK); + } + sleep_cancel(pthread_run); + } else { + /* Reschedule will unlock pthread_run */ + pthread_run->data.fd.fd = fd; + pthread_run->data.fd.branch = __LINE__; + pthread_resched_resume(PS_FDLR_WAIT); + pthread_mutex_lock(mutex); } + CLEAR_PF_DONE_EVENT(pthread_run); } else { - if (!fd_table[fd]->lockcount) { - PANIC(); - } + fd_table[fd]->r_lockcount++; } } fd_table[fd]->r_owner = pthread_run; } if ((fd_table[fd]->type != FD_HALF_DUPLEX) && - (lock_type & FD_WRITE)) { + (fd_table[fd]->type != FD_TEST_HALF_DUPLEX) && + ((lock_type == FD_WRITE) || (lock_type == FD_RDWR))) { 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_sched_prevent(); pthread_queue_enq(&fd_table[fd]->w_queue, pthread_run); - SEMAPHORE_RESET(lock); + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); - /* Reschedule will unlock pthread_run */ - reschedule(PS_FDLW_WAIT); + /* Reschedule will unlock pthread_run */ + pthread_run->data.fd.fd = fd; + pthread_run->data.fd.branch = __LINE__; + pthread_resched_resume(PS_FDLR_WAIT); + pthread_mutex_lock(mutex); - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); + /* If we're the owner then we have to cancel the sleep */ + if (fd_table[fd]->w_owner != pthread_run) { + if (lock_type == FD_RDWR) { + /* Unlock current thread */ + fd_basic_unlock(fd, FD_READ); + } + CLEAR_PF_DONE_EVENT(pthread_run); + SET_ERRNO(ETIMEDOUT); + return(NOTOK); + } + sleep_cancel(pthread_run); + } else { + /* Reschedule will unlock pthread_run */ + pthread_run->data.fd.fd = fd; + pthread_run->data.fd.branch = __LINE__; + pthread_resched_resume(PS_FDLR_WAIT); + pthread_mutex_lock(mutex); } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { + fd_table[fd]->w_lockcount++; } } fd_table[fd]->w_owner = pthread_run; @@ -283,24 +455,144 @@ int fd_basic_lock(unsigned int fd, int lock_type, semaphore * lock) return(OK); } +/*---------------------------------------------------------------------- + * Function: fd_unlock_for_cancel + * Purpose: Unlock all fd locks held prior to being cancelled + * Args: void + * Returns: + * OK or NOTOK + * Notes: + * Assumes the kernel is locked on entry + *----------------------------------------------------------------------*/ +int +fd_unlock_for_cancel( void ) +{ + int i, fd; + struct pthread_select_data *data; + int rdlk, wrlk, lktype; + int found; + + /* What we do depends on the previous state of the thread */ + switch( pthread_run->old_state ) { + case PS_RUNNING: + case PS_JOIN: + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: + case PS_SIGWAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_DEAD: + case PS_UNALLOCED: + break; /* Nothing to do */ + + case PS_COND_WAIT: + CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP ); + /* Must reaquire the mutex according to the standard */ + if( pthread_run->data.mutex == NULL ) { + PANIC(); + } + pthread_mutex_lock( pthread_run->data.mutex ); + break; + + case PS_FDR_WAIT: + CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); + /* Free the lock on the fd being used */ + fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd ); + if( fd == NOTOK ) { + PANIC(); /* Can't find fd */ + } + fd_unlock( fd, FD_READ ); + break; + + case PS_FDW_WAIT: /* Waiting on i/o */ + CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); + /* Free the lock on the fd being used */ + fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd ); + if( fd == NOTOK ) { + PANIC(); /* Can't find fd */ + } + fd_unlock( fd, FD_WRITE ); + break; + + case PS_SELECT_WAIT: + data = pthread_run->data.select_data; + + CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); + + for( i = 0; i < data->nfds; i++) { + rdlk =(FD_ISSET(i,&data->readfds) + || FD_ISSET(i,&data->exceptfds)); + wrlk = FD_ISSET(i, &data->writefds); + lktype = rdlk ? (wrlk ? FD_RDWR : FD_READ) : FD_WRITE; + + if( ! (rdlk || wrlk) ) + continue; /* No locks, no unlock */ + + if( (fd = fd_get_pthread_fd_from_kernel_fd( i )) == NOTOK ) { + PANIC(); /* Can't find fd */ + } + + fd_unlock( fd, lktype ); + } + break; + + case PS_MUTEX_WAIT: + PANIC(); /* Should never cancel a mutex wait */ + + default: + PANIC(); /* Unknown thread status */ + } +} + /* ========================================================================== * fd_lock() */ -int fd_lock(unsigned int fd, int lock_type) +#define pthread_mutex_lock_timedwait(a, b) pthread_mutex_lock(a) + +int fd_lock(unsigned int fd, int lock_type, struct timespec * timeout) { - semaphore *lock; + struct timespec current_time; + pthread_mutex_t *mutex; int error; - if (fd < dtablesize) { - lock = &(fd_table[fd]->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); + if ((error = fd_check_entry(fd)) == OK) { + mutex = &(fd_table[fd]->mutex); + if (pthread_mutex_lock_timedwait(mutex, timeout)) { + SET_ERRNO(ETIMEDOUT); + return(-ETIMEDOUT); } - error = fd_basic_lock(fd, lock_type, lock); - SEMAPHORE_RESET(lock); - return(error); + error = fd_basic_lock(fd, lock_type, mutex, timeout); + pthread_mutex_unlock(mutex); } - return(NOTOK); + return(error); +} + +/* ========================================================================== + * fd_free() + * + * Assumes fd is locked and owner by pthread_run + * Don't clear the queues, fd_unlock will do that. + */ +struct fd_table_entry * fd_free(int fd) +{ + struct fd_table_entry *fd_valid; + + fd_valid = NULL; + fd_table[fd]->r_lockcount = 0; + fd_table[fd]->w_lockcount = 0; + if (--fd_table[fd]->count) { + fd_valid = fd_table[fd]; + fd_table[fd] = fd_table[fd]->next; + fd_valid->next = fd_table[fd]->next; + /* Don't touch queues of fd_valid */ + } + + 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(fd_valid); } @@ -308,73 +600,111 @@ int fd_lock(unsigned int fd, int lock_type) * ======================================================================= */ /* ========================================================================== - * read() + * read_timedwait() */ -ssize_t read(int fd, void *buf, size_t nbytes) +ssize_t read_timedwait(int fd, void *buf, size_t nbytes, + struct timespec * timeout) { int ret; - if ((ret = fd_lock(fd, FD_READ)) == OK) { + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { ret = fd_table[fd]->ops->read(fd_table[fd]->fd, - fd_table[fd]->flags, buf, nbytes); + fd_table[fd]->flags, buf, nbytes, timeout); fd_unlock(fd, FD_READ); } return(ret); } /* ========================================================================== - * readv() + * read() */ -int readv(int fd, const struct iovec *iov, int iovcnt) +ssize_t read(int fd, void *buf, size_t nbytes) +{ + return(read_timedwait(fd, buf, nbytes, NULL)); +} + +/* ========================================================================== + * readv_timedwait() + */ +int readv_timedwait(int fd, const struct iovec *iov, int iovcnt, + struct timespec * timeout) { int ret; - if ((ret = fd_lock(fd, FD_READ)) == OK) { + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { ret = fd_table[fd]->ops->readv(fd_table[fd]->fd, - fd_table[fd]->flags, iov, iovcnt); + fd_table[fd]->flags, iov, iovcnt, timeout); fd_unlock(fd, FD_READ); } return(ret); } /* ========================================================================== + * readv() + */ +ssize_t readv(int fd, const struct iovec *iov, int iovcnt) +{ + return(readv_timedwait(fd, iov, iovcnt, NULL)); +} + +/* ========================================================================== * write() */ -ssize_t write(int fd, const void *buf, size_t nbytes) +ssize_t write_timedwait(int fd, const void *buf, size_t nbytes, + struct timespec * timeout) { - int ret; + 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); + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) + { + ret = fd_table[fd]->ops->write(fd_table[fd]->fd, + fd_table[fd]->flags, buf, nbytes, + timeout); + fd_unlock(fd, FD_WRITE); + } + return(ret); } /* ========================================================================== - * writev() + * write() + */ +ssize_t write(int fd, const void * buf, size_t nbytes) +{ + return(write_timedwait(fd, buf, nbytes, NULL)); +} + +/* ========================================================================== + * writev_timedwait() */ -int writev(int fd, const struct iovec *iov, int iovcnt) +int writev_timedwait(int fd, const struct iovec *iov, int iovcnt, + struct timespec * timeout) { int ret; - if ((ret = fd_lock(fd, FD_WRITE)) == OK) { + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) { ret = fd_table[fd]->ops->writev(fd_table[fd]->fd, - fd_table[fd]->flags, iov, iovcnt); + fd_table[fd]->flags, iov, iovcnt, timeout); fd_unlock(fd, FD_WRITE); } return(ret); } /* ========================================================================== + * writev() + */ +ssize_t writev(int fd, const struct iovec *iov, int iovcnt) +{ + return(writev_timedwait(fd, iov, iovcnt, NULL)); +} + +/* ========================================================================== * lseek() */ off_t lseek(int fd, off_t offset, int whence) { int ret; - if ((ret = fd_lock(fd, FD_RDWR)) == OK) { + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { ret = fd_table[fd]->ops->seek(fd_table[fd]->fd, fd_table[fd]->flags, offset, whence); fd_unlock(fd, FD_RDWR); @@ -393,66 +723,178 @@ off_t lseek(int fd, off_t offset, int whence) * 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... + * + * XXX close() is even uglier now. You may assume that the kernel fd is the + * same as fd if fd_table[fd] == NULL or if fd_table[fd]->type == FD_NT. + * This is true because before any fd_table[fd] is allocated the corresponding + * kernel fd must be checks to see if it's valid. */ int close(int fd) { - union fd_data realfd; - int ret, flags; + struct fd_table_entry * entry; + pthread_mutex_t *mutex; + 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); + if(fd < 0 || fd >= dtablesize) + { + SET_ERRNO(EBADF); + return -1; + } + /* Need to lock the newfd by hand */ + pthread_mutex_lock(&fd_table_mutex); + if (fd_table[fd]) { + pthread_mutex_unlock(&fd_table_mutex); + mutex = &(fd_table[fd]->mutex); + pthread_mutex_lock(mutex); + + /* + * XXX Gross hack ... because of fork(), any fd closed by the + * parent should not change the fd of the child, unless it owns it. + */ + switch(fd_table[fd]->type) { + case FD_NIU: + pthread_mutex_unlock(mutex); + ret = -EBADF; + break; + case FD_NT: + /* + * If it's not tested then the only valid possibility is it's + * kernel fd. + */ + ret = machdep_sys_close(fd); + fd_table[fd]->type = FD_NIU; + pthread_mutex_unlock(mutex); + break; + case FD_TEST_FULL_DUPLEX: + case FD_TEST_HALF_DUPLEX: + realfd = fd_table[fd]->fd; + flags = fd_table[fd]->flags; + if ((entry = fd_free(fd)) == NULL) { + ret = fd_table[fd]->ops->close(realfd, flags); + } else { + /* There can't be any others waiting for fd. */ + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ + mutex = &(fd_table[fd]->mutex); + } + pthread_mutex_unlock(mutex); + break; + default: + ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL); + if (ret == OK) { + realfd = fd_table[fd]->fd; + flags = fd_table[fd]->flags; + pthread_mutex_unlock(mutex); + if ((entry = fd_free(fd)) == NULL) { + ret = fd_table[fd]->ops->close(realfd, flags); + } else { + fd_basic_basic_unlock(entry, FD_RDWR); + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ } - return(ret); + fd_unlock(fd, FD_RDWR); + } else { + pthread_mutex_unlock(mutex); + } + break; + } + } else { + /* Don't bother creating a table entry */ + pthread_mutex_unlock(&fd_table_mutex); + ret = machdep_sys_close(fd); + } + if( ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return(ret); } /* ========================================================================== * fd_basic_dup() * - * Might need to do more than just what's below. + * + * This is a MAJOR guess!! I don't know if the mutext unlock is valid + * in the BIG picture. But it seems to be needed to avoid deadlocking + * with ourselves when we try to close the duped file descriptor. */ 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[newfd] = fd_table[fd]; fd_table[fd]->count++; + pthread_mutex_unlock(&fd_table[newfd]->next->mutex); + } /* ========================================================================== * 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. + * Note: Always lock the lower number fd first to avoid deadlocks. + * Note: Leave the newfd locked. It will be unlocked at close() time. + * Note: 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) { + struct fd_table_entry * entry; + pthread_mutex_t *mutex; union fd_data realfd; - semaphore *lock; int ret, flags; + if ((ret = fd_check_entry(newfd)) != OK) + return ret; + if (newfd < dtablesize) { if (fd < newfd) { - if ((ret = fd_lock(fd, FD_RDWR)) == OK) { + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { /* Need to lock the newfd by hand */ - lock = &(fd_table[newfd]->lock); - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + mutex = &(fd_table[newfd]->mutex); + pthread_mutex_lock(mutex); /* Is it inuse */ - if (fd_basic_lock(newfd, FD_RDWR, lock) == OK) { + if (fd_basic_lock(newfd, FD_RDWR, mutex, NULL) == OK) { + realfd = fd_table[newfd]->fd; + flags = fd_table[newfd]->flags; /* 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); + if ((entry = fd_free(newfd)) == NULL) { + entry = fd_table[newfd]; + entry->ops->close(realfd, flags); + if (entry->r_queue.q_next) { + if (fd_table[fd]->next) { + fd_table[fd]->r_queue.q_last->next = + entry->r_queue.q_next; + } else { + fd_table[fd]->r_queue.q_next = + entry->r_queue.q_next; + } + fd_table[fd]->r_queue.q_last = + entry->r_queue.q_last; + } + if (entry->w_queue.q_next) { + if (fd_table[fd]->next) { + fd_table[fd]->w_queue.q_last->next = + entry->w_queue.q_next; + } else { + fd_table[fd]->w_queue.q_next = + entry->w_queue.q_next; + } + fd_table[fd]->w_queue.q_last = + entry->w_queue.q_last; + } + entry->r_queue.q_next = NULL; + entry->w_queue.q_next = NULL; + entry->r_queue.q_last = NULL; + entry->w_queue.q_last = NULL; + entry->r_owner = NULL; + entry->w_owner = NULL; + ret = OK; } else { - /* Lots of work to do */ + fd_basic_basic_unlock(entry, FD_RDWR); + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ } } fd_basic_dup(fd, newfd); @@ -460,27 +902,56 @@ int dup2(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 */ - } + mutex = &(fd_table[newfd]->mutex); + pthread_mutex_lock(mutex); - fd_basic_dup(fd, newfd); + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + /* Is newfd inuse */ + if ((ret = fd_basic_lock(newfd, FD_RDWR, mutex, NULL)) == OK) { + realfd = fd_table[newfd]->fd; + flags = fd_table[newfd]->flags; + /* free it and check close status */ + if ((entry = fd_free(newfd)) == NULL) { + entry = fd_table[newfd]; + entry->ops->close(realfd, flags); + if (entry->r_queue.q_next) { + if (fd_table[fd]->next) { + fd_table[fd]->r_queue.q_last->next = + entry->r_queue.q_next; + } else { + fd_table[fd]->r_queue.q_next = + entry->r_queue.q_next; + } + fd_table[fd]->r_queue.q_last = + entry->r_queue.q_last; + } + if (entry->w_queue.q_next) { + if (fd_table[fd]->next) { + fd_table[fd]->w_queue.q_last->next = + entry->w_queue.q_next; + } else { + fd_table[fd]->w_queue.q_next = + entry->w_queue.q_next; + } + fd_table[fd]->w_queue.q_last = + entry->w_queue.q_last; + } + entry->r_queue.q_next = NULL; + entry->w_queue.q_next = NULL; + entry->r_queue.q_last = NULL; + entry->w_queue.q_last = NULL; + entry->r_owner = NULL; + entry->w_owner = NULL; + ret = OK; + } else { + fd_basic_basic_unlock(entry, FD_RDWR); + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ + } + fd_basic_dup(fd, newfd); + } fd_unlock(fd, FD_RDWR); } - SEMAPHORE_RESET(lock); } } else { ret = NOTOK; @@ -496,7 +967,7 @@ int dup(int fd) { int ret; - if ((ret = fd_lock(fd, FD_RDWR)) == OK) { + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { ret = fd_allocate(); fd_basic_dup(fd, ret); fd_unlock(fd, FD_RDWR); @@ -515,7 +986,7 @@ int fcntl(int fd, int cmd, ...) va_list ap; flags = 0; - if ((ret = fd_lock(fd, FD_RDWR)) == OK) { + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { va_start(ap, cmd); switch(cmd) { case F_DUPFD: @@ -523,10 +994,8 @@ int fcntl(int fd, int cmd, ...) fd_basic_dup(va_arg(ap, int), ret); break; case F_SETFD: - flags = va_arg(ap, int); + break; 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; @@ -560,3 +1029,54 @@ int fcntl(int fd, int cmd, ...) } return(ret); } + +/* ========================================================================== + * getdtablesize() + */ +int getdtablesize() +{ + return dtablesize; +} + +/* ========================================================================== + * ioctl() + * + * Really want to do a real implementation of this that parses the args ala + * fcntl(), above, but it will have to be a totally platform-specific, + * nightmare-on-elm-st-style sort of thing. Might even deserve its own file + * ala select()... --SNL + */ +#ifndef ioctl_request_type +#define ioctl_request_type unsigned long /* Dummy patch by Monty */ +#endif + +int +ioctl(int fd, ioctl_request_type request, ...) +{ + int ret; + pthread_va_list ap; + caddr_t arg; + + va_start( ap, request ); /* Get the arg */ + arg = va_arg(ap,caddr_t); + va_end( ap ); + + if (fd < 0 || fd >= dtablesize) + ret = NOTOK; + else if (fd_table[fd]->fd.i == NOTOK) + ret = machdep_sys_ioctl(fd, request, arg); + else if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + ret = machdep_sys_ioctl(fd_table[fd]->fd.i, request, arg); + if( ret == 0 && request == FIONBIO ) { + /* Properly set NONBLOCK flag */ + int v = *(int *)arg; + if( v ) + fd_table[fd]->flags |= __FD_NONBLOCK; + else + fd_table[fd]->flags &= ~__FD_NONBLOCK; + } + fd_unlock(fd, FD_RDWR); + } + return ret; +} + diff --git a/lib/libpthread/pthreads/fd_kern.c b/lib/libpthread/pthreads/fd_kern.c index a9eb69af9b7..42489569ab7 100644 --- a/lib/libpthread/pthreads/fd_kern.c +++ b/lib/libpthread/pthreads/fd_kern.c @@ -39,10 +39,12 @@ */ #ifndef lint -static const char rcsid[] = "$Id: fd_kern.c,v 1.1.1.1 1995/10/18 08:43:04 deraadt Exp $ $provenid: fd_kern.c,v 1.7 1994/02/07 02:18:49 proven Exp $"; +static const char rcsid[] = "$Id: fd_kern.c,v 1.1.1.2 1998/07/21 13:19:55 peter Exp $"; #endif #include <pthread.h> +#include <unistd.h> +#include <sys/compat.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> @@ -53,12 +55,229 @@ static const char rcsid[] = "$Id: fd_kern.c,v 1.1.1.1 1995/10/18 08:43:04 deraad #include <fcntl.h> #include <errno.h> #include <pthread/posix.h> +#include <string.h> + +#include "config.h" + +#if defined (HAVE_SYSCALL_SENDTO) && !defined (HAVE_SYSCALL_SEND) + +pthread_ssize_t machdep_sys_send (int fd, const void *msg, size_t len, + int flags) +{ + return machdep_sys_sendto (fd, msg, len, flags, + (const struct sockaddr *) 0, 0); +} + +#endif + +#if defined (HAVE_SYSCALL_RECVFROM) && !defined (HAVE_SYSCALL_RECV) + +pthread_ssize_t machdep_sys_recv (int fd, void *buf, size_t len, int flags) +{ + return machdep_sys_recvfrom (fd, buf, len, flags, + (struct sockaddr *) 0, (int *) 0); +} + +#endif + +/* ========================================================================== + * Check if there is any signal with must be handled. Added by Monty + * This could be somewhat system dependent but it should work. + */ + +static int fd_check_if_pending_signal(struct pthread *pthread) +{ + int i; + unsigned long *pending,*mask; + if (!pthread->sigcount) + return 0; + pending= (unsigned long*) &pthread->sigpending; + mask= (unsigned long*) &pthread->sigmask; + + for (i=0 ; i < sizeof(pthread->sigpending)/sizeof(unsigned long); i++) + { + if (*pending && (*mask ^ (unsigned) ~0L)) + return 1; + pending++; + mask++; + } + return 0; +} /* ========================================================================== * 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; +struct pthread_queue fd_wait_read = PTHREAD_QUEUE_INITIALIZER; +struct pthread_queue fd_wait_write = PTHREAD_QUEUE_INITIALIZER; +struct pthread_queue fd_wait_select = PTHREAD_QUEUE_INITIALIZER; + +static struct timeval __fd_kern_poll_timeout = { 0, 0 }; /* Moved by monty */ +extern struct timeval __fd_kern_wait_timeout; +extern volatile sig_atomic_t sig_to_process; + +/* + * ========================================================================== + * Do a select if there is someting to wait for. + * This is to a combination of the old fd_kern_poll() and fd_kern_wait() + * Return 1 if nothing to do. + */ + +static int fd_kern_select(struct timeval *timeout) +{ + fd_set fd_set_read, fd_set_write, fd_set_except; + struct pthread *pthread, *deq; + int count, i; + + if (!fd_wait_read.q_next && !fd_wait_write.q_next && !fd_wait_select.q_next) + return 1; /* Nothing to do */ + + FD_ZERO(&fd_set_read); + FD_ZERO(&fd_set_write); + FD_ZERO(&fd_set_except); + for (pthread = fd_wait_read.q_next; pthread; pthread = pthread->next) + FD_SET(pthread->data.fd.fd, &fd_set_read); + for (pthread = fd_wait_write.q_next; pthread; pthread = pthread->next) + FD_SET(pthread->data.fd.fd, &fd_set_write); + for (pthread = fd_wait_select.q_next; pthread; pthread = pthread->next) + { + for (i = 0; i < pthread->data.select_data->nfds; i++) { + if (FD_ISSET(i, &pthread->data.select_data->exceptfds)) + FD_SET(i, &fd_set_except); + if (FD_ISSET(i, &pthread->data.select_data->writefds)) + FD_SET(i, &fd_set_write); + if (FD_ISSET(i, &pthread->data.select_data->readfds)) + FD_SET(i, &fd_set_read); + } + } + + /* Turn off interrupts for real while we set the timer. */ + + if (timeout == &__fd_kern_wait_timeout) + { /* from fd_kern_wait() */ + sigset_t sig_to_block, oset; + sigfillset(&sig_to_block); + machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); + + machdep_unset_thread_timer(NULL); + __fd_kern_wait_timeout.tv_usec = 0; + __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600; + + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + } + /* + * 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, &fd_set_except, + timeout)) < OK) + { + if (count == -EINTR) + return 0; + PANIC(); + } + + for (pthread = fd_wait_read.q_next; pthread; ) { + if (count && FD_ISSET(pthread->data.fd.fd, &fd_set_read) || + fd_check_if_pending_signal(pthread)) + { + if (FD_ISSET(pthread->data.fd.fd, &fd_set_read)) + count--; + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_read, deq); + if (SET_PF_DONE_EVENT(deq) == OK) { + pthread_prio_queue_enq(pthread_current_prio_queue, deq); + deq->state = PS_RUNNING; + } + continue; + } + pthread = pthread->next; + } + + for (pthread = fd_wait_write.q_next; pthread; ) { + if (count && FD_ISSET(pthread->data.fd.fd, &fd_set_write) || + fd_check_if_pending_signal(pthread)) + { + if (FD_ISSET(pthread->data.fd.fd, &fd_set_read)) + count--; + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_write, deq); + if (SET_PF_DONE_EVENT(deq) == OK) { + pthread_prio_queue_enq(pthread_current_prio_queue, deq); + deq->state = PS_RUNNING; + } + continue; + } + pthread = pthread->next; + } + + for (pthread = fd_wait_select.q_next; pthread; ) + { + int found_one=0; /* Loop fixed by monty */ + if (count) + { + fd_set tmp_readfds, tmp_writefds, tmp_exceptfds; + memcpy(&tmp_readfds, &pthread->data.select_data->readfds, + sizeof(fd_set)); + memcpy(&tmp_writefds, &pthread->data.select_data->writefds, + sizeof(fd_set)); + memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds, + sizeof(fd_set)); + + for (i = 0; i < pthread->data.select_data->nfds; i++) { + if (FD_ISSET(i, &tmp_exceptfds)) + { + if (! FD_ISSET(i, &fd_set_except)) + FD_CLR(i, &tmp_exceptfds); + else + found_one=1; + } + if (FD_ISSET(i, &tmp_writefds)) + { + if (! FD_ISSET(i, &fd_set_write)) + FD_CLR(i, &tmp_writefds); + else + found_one=1; + } + if (FD_ISSET(i, &tmp_readfds)) + { + if (! FD_ISSET(i, &fd_set_read)) + FD_CLR(i, &tmp_readfds); + else + found_one=1; + } + } + if (found_one) + { + memcpy(&pthread->data.select_data->readfds, &tmp_readfds, + sizeof(fd_set)); + memcpy(&pthread->data.select_data->writefds, &tmp_writefds, + sizeof(fd_set)); + memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds, + sizeof(fd_set)); + } + } + if (found_one || fd_check_if_pending_signal(pthread)) + { + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_select, deq); + if (SET_PF_DONE_EVENT(deq) == OK) { + pthread_prio_queue_enq(pthread_current_prio_queue, deq); + deq->state = PS_RUNNING; + } + } else { + pthread = pthread->next; + } + } + return 0; +} + /* ========================================================================== * fd_kern_poll() @@ -67,152 +286,27 @@ static fd_set fd_set_read, fd_set_write; * * 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_select(&__fd_kern_poll_timeout); } + /* ========================================================================== * 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(); - } + if (fd_kern_select(&__fd_kern_wait_timeout)) + /* 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 @@ -221,143 +315,231 @@ void fd_kern_wait() /* ========================================================================== * read() */ -ssize_t __fd_kern_read(int fd, int flags, void *buf, size_t nbytes) +pthread_ssize_t __fd_kern_read(union fd_data fd_data, int flags, void *buf, + size_t nbytes, struct timespec * timeout) { - 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; - } + int fd = fd_data.i; + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + while ((ret = machdep_sys_read(fd, buf, nbytes)) < OK) { + if (!(flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd; + pthread_queue_enq(&fd_wait_read, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDR_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret= NOTOK; + break; } - return(ret); + pthread_sched_resume(); + } else { + SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDR_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } + } else { + SET_ERRNO(-ret); + ret = NOTOK; + break; + } + } + return(ret); } /* ========================================================================== * readv() */ -int __fd_kern_readv(int fd, int flags, struct iovec *iov, int iovcnt) +int __fd_kern_readv(union fd_data fd_data, int flags, const struct iovec *iov, + int iovcnt, struct timespec * timeout) { - 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; - } + int fd = fd_data.i; + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + while ((ret = machdep_sys_readv(fd, iov, iovcnt)) < OK) { + if (!(flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + pthread_run->data.fd.fd = fd; + SET_PF_WAIT_EVENT(pthread_run); + pthread_queue_enq(&fd_wait_read, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDW_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret = NOTOK; + break; } - return(ret); + pthread_sched_resume(); + } else { + SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDW_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } + } else { + SET_ERRNO(-ret); + ret = NOTOK; + break; + } + } + return(ret); } /* ========================================================================== * write() */ -ssize_t __fd_kern_write(int fd, int flags, const void *buf, size_t nbytes) +pthread_ssize_t __fd_kern_write(union fd_data fd_data, int flags, + const void *buf, size_t nbytes, struct timespec * timeout) { - 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; - } + int fd = fd_data.i; + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + while ((ret = machdep_sys_write(fd, buf, nbytes)) < OK) { + if (!(flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ + pthread_run->data.fd.fd = fd; + SET_PF_WAIT_EVENT(pthread_run); + pthread_queue_enq(&fd_wait_write, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret = NOTOK; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } + } else { + SET_ERRNO(-ret); + ret = NOTOK; + break; } - return(ret); + } + return(ret); } /* ========================================================================== * writev() */ -int __fd_kern_writev(int fd, int flags, struct iovec *iov, int iovcnt) +int __fd_kern_writev(union fd_data fd_data, int flags, const struct iovec *iov, + int iovcnt, struct timespec * timeout) { - semaphore *lock, *plock; + int fd = fd_data.i; int ret; + pthread_run->sighandled=0; /* Added by monty */ 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(); - } + if (!(flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); /* 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); + pthread_run->data.fd.fd = fd; + SET_PF_WAIT_EVENT(pthread_run); + pthread_queue_enq(&fd_wait_write, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret = NOTOK; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } } else { - pthread_run->error = ret; break; } } @@ -368,25 +550,38 @@ int __fd_kern_writev(int fd, int flags, struct iovec *iov, int iovcnt) * For blocking version we really should set an interrupt * fcntl() */ -int __fd_kern_fcntl(int fd, int flags, int cmd, int arg) +int __fd_kern_fcntl(union fd_data fd_data, int flags, int cmd, int arg) { + int fd = fd_data.i; + return(machdep_sys_fcntl(fd, cmd, arg)); } /* ========================================================================== * close() */ -int __fd_kern_close(int fd, int flags) +int __fd_kern_close(union fd_data fd_data, int flags) { + int fd = fd_data.i; + return(machdep_sys_close(fd)); } /* ========================================================================== * lseek() + * Assume that error number is in the range 0- 255 to get bigger + * range of seek. ; Monty */ -int __fd_kern_lseek(int fd, int flags, off_t offset, int whence) +off_t __fd_kern_lseek(union fd_data fd_data, int f, off_t offset, int whence) { - return(machdep_sys_lseek(fd, offset, whence)); + int fd = fd_data.i; + off_t ret=machdep_sys_lseek(fd, offset, whence); + if ((long) ret < 0L && (long) ret >= -255L) + { + SET_ERRNO(ret); + ret= NOTOK; + } + return ret; } /* @@ -397,7 +592,7 @@ 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 + __fd_kern_writev, __fd_kern_readv, __fd_kern_lseek, 1 }; /* NFS file opperations */ @@ -416,7 +611,7 @@ static struct fd_ops __fd_kern_ops = { * * This is not done yet * - * A reqular file on the local system needs no special treatment. + * A regular file on the local system needs no special treatment. */ int open(const char *path, int flags, ...) { @@ -440,8 +635,8 @@ int open(const char *path, int flags, ...) 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 (machdep_sys_fstat(fd_kern, &stat_buf)) { + PANIC(); } if (S_ISREG(stat_buf.st_mode)) { fd_table[fd]->ops = &(__fd_kern_ops); @@ -450,41 +645,421 @@ printf("error %d stating new fd %d\n", errno, fd); fd_table[fd]->ops = &(__fd_kern_ops); fd_table[fd]->type = FD_FULL_DUPLEX; } - fd_table[fd]->fd = fd_kern; + fd_table[fd]->fd.i = fd_kern; return(fd); } - pthread_run->error = - fd_kern; fd_table[fd]->count = 0; + SET_ERRNO(-fd_kern); } return(NOTOK); } /* ========================================================================== + * create() + */ +int create(const char *path, mode_t mode) +{ + return creat (path, mode); +} + +/* ========================================================================== + * creat() + */ +#undef creat + +int creat(const char *path, mode_t mode) +{ + return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode); +} + +/* ========================================================================== + * fchown() + */ +int fchown(int fd, uid_t owner, gid_t group) +{ + int ret; + + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) { + if ((ret = machdep_sys_fchown(fd_table[fd]->fd.i, owner, group)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_WRITE); + } + return(ret); +} + +/* ========================================================================== + * fchmod() + */ +int fchmod(int fd, mode_t mode) +{ + int ret; + + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) { + if ((ret = machdep_sys_fchmod(fd_table[fd]->fd.i, mode)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_WRITE); + } + return(ret); +} + +/* ========================================================================== + * ftruncate() + */ +int ftruncate(int fd, off_t length) +{ + int ret; + + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) { + if ((ret = machdep_sys_ftruncate(fd_table[fd]->fd.i, length)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_WRITE); + } + return(ret); +} + +#if defined (HAVE_SYSCALL_FLOCK) +/* ========================================================================== + * flock() + * + * Added (mevans) + */ +int flock(int fd, int operation) +{ + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_flock(fd_table[fd]->fd.i, + operation)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } + return(ret); +} +#endif + +/* ========================================================================== + * pipe() + */ +int pipe(int fds[2]) +{ + int kfds[2]; + int ret; + + if ((fds[0] = fd_allocate()) >= OK) { + if ((fds[1] = fd_allocate()) >= OK) { + if ((ret = machdep_sys_pipe(kfds)) >= OK) { + fd_table[fds[0]]->flags = machdep_sys_fcntl(kfds[0], F_GETFL, NULL); + machdep_sys_fcntl(kfds[0], F_SETFL, fd_table[fds[0]]->flags | __FD_NONBLOCK); + fd_table[fds[1]]->flags = machdep_sys_fcntl(kfds[1], F_GETFL, NULL); + machdep_sys_fcntl(kfds[1], F_SETFL, fd_table[fds[1]]->flags | __FD_NONBLOCK); + + fd_table[fds[0]]->ops = &(__fd_kern_ops); + fd_table[fds[1]]->ops = &(__fd_kern_ops); + + /* Not really full duplex but ... */ + fd_table[fds[0]]->type = FD_FULL_DUPLEX; + fd_table[fds[1]]->type = FD_FULL_DUPLEX; + + fd_table[fds[0]]->fd.i = kfds[0]; + fd_table[fds[1]]->fd.i = kfds[1]; + + return(OK); + } else { + SET_ERRNO(-ret); + } + fd_table[fds[1]]->count = 0; + } + fd_table[fds[0]]->count = 0; + } + return(NOTOK); +} + +/* ========================================================================== + * fd_kern_reset() + * Change the fcntl blocking flag back to NONBLOCKING. This should only + * be called after a fork. + */ +void fd_kern_reset(int fd) +{ + switch (fd_table[fd]->type) { + case FD_TEST_HALF_DUPLEX: + machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, + fd_table[fd]->flags | __FD_NONBLOCK); + fd_table[fd]->type = FD_HALF_DUPLEX; + break; + case FD_TEST_FULL_DUPLEX: + machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, + fd_table[fd]->flags | __FD_NONBLOCK); + fd_table[fd]->type = FD_FULL_DUPLEX; + break; + default: + break; + } +} + +/* ========================================================================== * 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. + * + * New added feature: If the fd in question is a tty then we open it again + * and close the original, this way we don't have to worry about the + * fd being NONBLOCKING to the outside world. */ -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) { + if (isatty_basic(fd)) { + int new_fd; + + if ((new_fd = machdep_sys_open(__ttyname_basic(fd), O_RDWR)) >= OK){ + if (machdep_sys_dup2(new_fd, fd) == OK) { + /* Should print a warning */ + + /* Should also set the flags to that of opened outside of + process */ + } + machdep_sys_close(new_fd); + } + } + /* We do these things regaurdless of the above results */ 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]->fd.i = fd; fd_table[fd]->count = 1; } } /* ========================================================================== + * fd_kern_gettableentry() + * + * Remember only return a a file descriptor that I will modify later. + * Don't return file descriptors that aren't owned by the child, or don't + * have kernel operations. + */ +static int fd_kern_gettableentry(const int child, int fd) +{ + int i; + + for (i = 0; i < dtablesize; i++) { + if (fd_table[i]) { + if (fd_table[i]->fd.i == fd) { + if (child) { + if ((fd_table[i]->type != FD_TEST_HALF_DUPLEX) && + (fd_table[i]->type != FD_TEST_FULL_DUPLEX)) { + continue; + } + } else { + if ((fd_table[i]->type == FD_NT) || + (fd_table[i]->type == FD_NIU)) { + continue; + } + } + /* Is it a kernel fd ? */ + if ((!fd_table[i]->ops) || + (fd_table[i]->ops->use_kfds != 1)) { + continue; + } + return(i); + } + } + } + return(NOTOK); +} + +/* ========================================================================== + * fd_kern_exec() + * + * Fixup the fd_table such that (fd == fd_table[fd]->fd.i) this way + * the new immage will be OK. + * + * Only touch those that won't be used by the parent if we're in a child + * otherwise fixup all. + * + * Returns: + * 0 no fixup necessary + * 1 fixup without problems + * 2 failed fixup on some descriptors, and clobbered them. + */ +int fd_kern_exec(const int child) +{ + int ret = 0; + int fd, i; + + for (fd = 0; fd < dtablesize; fd++) { + if (fd_table[fd] == NULL) { + continue; + } + /* Is the fd already in use ? */ + if (child) { + if ((fd_table[fd]->type != FD_TEST_HALF_DUPLEX) && + (fd_table[fd]->type != FD_TEST_FULL_DUPLEX)) { + continue; + } + } else { + if ((fd_table[fd]->type == FD_NT) || + (fd_table[fd]->type == FD_NIU)) { + continue; + } + } + /* Is it a kernel fd ? */ + if ((!fd_table[fd]->ops) || + (fd_table[fd]->ops->use_kfds != 1)) { + continue; + } + /* Does it match ? */ + if (fd_table[fd]->fd.i == fd) { + continue; + } + /* OK, fixup entry: Read comments before changing. This isn't obvious */ + + /* i is the real file descriptor fd currently represents */ + if (((i = fd_table[fd]->fd.i) >= dtablesize) || (i < 0)) { + /* This should never happen */ + PANIC(); + } + + /* + * if the real file descriptor with the same number as the fake file + * descriptor number fd is actually in use by the program, we have + * to move it out of the way + */ + if ((machdep_sys_fcntl(fd, F_GETFL, NULL)) >= OK) { + /* fd is busy */ + int j; + + /* + * j is the fake file descriptor that represents the real file + * descriptor that we want to move. This way the fake file + * descriptor fd can move its real file descriptor i such that + * fd == i. + */ + if ((j = fd_kern_gettableentry(child, fd)) >= OK) { + + /* + * Since j represents a fake file descriptor and fd represents + * a fake file descriptor. If j < fd then a previous pass + * should have set fd_table[j]->fd.i == j. + */ + if (fd < j) { + if ((fd_table[j]->fd.i = machdep_sys_dup(fd)) < OK) { + /* Close j, there is nothing else we can do */ + fd_table[j]->type = FD_NIU; + ret = 2; + } + } else { + /* This implies fd_table[j]->fd.i != j */ + PANIC(); + } + } + } + + /* + * Here the real file descriptor i is set to equel the fake file + * descriptor fd + */ + machdep_sys_dup2(i, fd); + + /* + * Now comes the really complicated part: UNDERSTAND before changing + * + * Here are the things this routine wants to do ... + * + * Case 1. The real file descriptor has only one fake file descriptor + * representing it. + * fd -> i, fd != i ===> fd -> fd, close(i) + * Example fd = 4, i = 2: then close(2), set fd -> i = 4 + * + * Case 2. The real file descriptor has more than one fake file + * descriptor representing it, and this is the first fake file + * descriptor representing the real file descriptor + * fd -> i, fd' -> i, fd != i ===> fd -> fd, fd' -> fd, close(i) + * + * The problem is achiving the above is very messy and difficult, + * but I should be able to take a short cut. If fd > i then there + * will be no need to ever move i, this is because the fake file + * descriptor foo that we would have wanted to represent the real + * file descriptor i has already been processed. If fd < i then by + * moving i to fd all subsequent fake file descriptors fd' should fall + * into the previous case and won't need aditional adjusting. + * + * Does this break the above fd < j check .... It shouldn't because j + * is a fake file descriptor and if j < fd then j has already moved + * its real file descriptor foo such that foo <= j therefore foo < fd + * and not foo == fd therefor j cannot represent the real + * filedescriptor that fd want to move to and be less than fd + */ + if (fd < i) { + fd_table[fd]->fd.i = fd; + machdep_sys_close(i); + } + if (ret < 1) { + ret = 1; + } + } +} + +/* ========================================================================== + * fd_kern_fork() + */ +void fd_kern_fork() +{ + pthread_mutex_t *mutex; + int fd; + + for (fd = 0; fd < dtablesize; fd++) { + if (fd_table[fd] == NULL) { + continue; + } + mutex = & (fd_table[fd]->mutex); + if (pthread_mutex_trylock(mutex)) { + continue; + } + if ((fd_table[fd]->r_owner) || (fd_table[fd]->w_owner)) { + pthread_mutex_unlock(mutex); + continue; + } + /* Is it a kernel fd ? */ + if ((!fd_table[fd]->ops) || (fd_table[fd]->ops->use_kfds != 1)) { + pthread_mutex_unlock(mutex); + continue; + } + switch (fd_table[fd]->type) { + case FD_HALF_DUPLEX: + machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags); + fd_table[fd]->type = FD_TEST_HALF_DUPLEX; + break; + case FD_FULL_DUPLEX: + machdep_sys_fcntl(fd_table[fd]->fd.i, F_SETFL, fd_table[fd]->flags); + fd_table[fd]->type = FD_TEST_FULL_DUPLEX; + break; + default: + break; + } + pthread_mutex_unlock(mutex); + } +} + +/* ========================================================================== * Here are the berkeley socket functions. These are not POSIX. * ======================================================================= */ +#if defined (HAVE_SYSCALL_SOCKET) || defined (HAVE_SYSCALL_SOCKETCALL) + /* ========================================================================== * socket() */ @@ -495,153 +1070,843 @@ int socket(int af, int type, int protocol) if (!((fd = fd_allocate()) < OK)) { if (!((fd_kern = machdep_sys_socket(af, type, protocol)) < OK)) { - machdep_sys_fcntl(fd_kern, F_SETFL, __FD_NONBLOCK); + int tmp_flags; + + tmp_flags = machdep_sys_fcntl(fd_kern, F_GETFL, 0); + machdep_sys_fcntl(fd_kern, F_SETFL, tmp_flags | __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; + fd_table[fd]->fd.i = fd_kern; + fd_table[fd]->flags = tmp_flags; return(fd); } - pthread_run->error = - fd_kern; fd_table[fd]->count = 0; + SET_ERRNO(-fd_kern); } return(NOTOK); } +#endif + +#if defined (HAVE_SYSCALL_BIND) || defined (HAVE_SYSCALL_SOCKETCALL) + /* ========================================================================== * 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; + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; } fd_unlock(fd, FD_RDWR); } return(ret); } +#endif + +#if defined (HAVE_SYSCALL_CONNECT) || defined (HAVE_SYSCALL_SOCKETCALL) + /* ========================================================================== * 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(); - } + struct sockaddr tmpname; + int ret, tmpnamelen; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) || + (ret == -EALREADY) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_write, pthread_run); + + pthread_resched_resume(PS_FDW_WAIT); + CLEAR_PF_DONE_EVENT(pthread_run); + + tmpnamelen = sizeof(tmpname); + /* OK now lets see if it really worked */ + if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, + &tmpname, &tmpnamelen)) < OK) && + (ret == -ENOTCONN)) + { + /* Get the error, this function should not fail */ + machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET, + SO_ERROR, &ret, &tmpnamelen); + SET_ERRNO(ret); /* ret is already positive (mevans) */ + ret = NOTOK; + } + } else { + if (ret < 0) + { + SET_ERRNO(-ret); + ret = NOTOK; + } + } + } + fd_unlock(fd, FD_RDWR); + } + return(ret); +} - /* Lock pthread */ - plock = &(pthread_run->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } +#endif - /* 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); +#if defined (HAVE_SYSCALL_ACCEPT) || defined (HAVE_SYSCALL_SOCKETCALL) - /* OK now lets see if it really worked */ - if (((ret = machdep_sys_getpeername(fd_table[fd]->fd, - &tmpname, &tmpnamelen)) < OK) && (ret == -ENOTCONN)) { +/* ========================================================================== + * accept() + */ +int accept(int fd, struct sockaddr *name, int *namelen) +{ + int ret, fd_kern; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + while ((fd_kern = machdep_sys_accept(fd_table[fd]->fd.i, name, namelen)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((fd_kern == -EWOULDBLOCK) || (fd_kern == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_read, pthread_run); + + pthread_resched_resume(PS_FDR_WAIT); + CLEAR_PF_DONE_EVENT(pthread_run); + } else { + fd_unlock(fd, FD_RDWR); + SET_ERRNO(-fd_kern); + return(NOTOK); + } + } + fd_unlock(fd, FD_RDWR); - /* 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; + 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.i = fd_kern; + + /* XXX Flags should be the same as those on the listening fd */ + fd_table[ret]->flags = fd_table[fd]->flags; + } + } + return(ret); +} + +#endif + +#if defined (HAVE_SYSCALL_LISTEN) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * listen() + */ +int listen(int fd, int backlog) +{ + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } + return(ret); +} + +#endif + +#if defined (HAVE_SYSCALL_SEND) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * send_timedwait() + */ +ssize_t send_timedwait(int fd, const void * msg, size_t len, int flags, + struct timespec * timeout) +{ + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) { + while ((ret = machdep_sys_send(fd_table[fd]->fd.i, + msg, len, flags)) < OK) + { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) + { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_write, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + ret= -EINTR; + break; + } + } else { + break; + } + } + fd_unlock(fd, FD_WRITE); + } + if (ret < 0) + { + SET_ERRNO(-ret); + return(NOTOK); + } + return ret; +} + +/* ========================================================================== + * send() + */ +ssize_t send(int fd, const void * msg, size_t len, int flags) +{ + return(send_timedwait(fd, msg, len, flags, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_SENDTO) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * sendto_timedwait() + */ +ssize_t sendto_timedwait(int fd, const void * msg, size_t len, + int flags, const struct sockaddr *to, int to_len, + struct timespec * timeout) +{ + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) { + while ((ret = machdep_sys_sendto(fd_table[fd]->fd.i, + msg, len, flags, to, to_len)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_write, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret= -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + ret= -EINTR; + break; + } + } + else + break; /* ret contains the errorcode */ + } + fd_unlock(fd, FD_WRITE); + } + if (ret < 0) + { + SET_ERRNO(-ret); + return(NOTOK); + } + return(ret); +} + +/* ========================================================================== + * sendto() + */ +ssize_t sendto(int fd, const void * msg, size_t len, int flags, + const struct sockaddr *to, int to_len) +{ + return(sendto_timedwait(fd, msg, len, flags, to, to_len, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_SENDMSG) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * sendmsg_timedwait() + */ +ssize_t sendmsg_timedwait(int fd, const struct msghdr *msg, int flags, + struct timespec * timeout) +{ + int passed_fd, ret, i; + + /* Handle getting the real file descriptor */ + for(i = 0; i < (((struct omsghdr *)msg)->msg_accrightslen/sizeof(i)); i++) { + passed_fd = *(((int *)((struct omsghdr *)msg)->msg_accrights) + i); + if ((ret = fd_lock(passed_fd, FD_RDWR, NULL)) == OK) { + *(((int *)((struct omsghdr *)msg)->msg_accrights) + i) + = fd_table[passed_fd]->fd.i; + machdep_sys_fcntl(fd_table[passed_fd]->fd.i, F_SETFL, + fd_table[passed_fd]->flags); + switch(fd_table[passed_fd]->type) { + case FD_TEST_FULL_DUPLEX: + case FD_TEST_HALF_DUPLEX: + break; + case FD_FULL_DUPLEX: + fd_table[passed_fd]->type = FD_TEST_FULL_DUPLEX; + break; + case FD_HALF_DUPLEX: + fd_table[passed_fd]->type = FD_TEST_HALF_DUPLEX; + break; + default: + PANIC(); + } + } else { + fd_unlock(fd, FD_RDWR); + SET_ERRNO(EBADF); + return(NOTOK); + } + fd_unlock(fd, FD_RDWR); + } + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_WRITE, timeout)) == OK) { + while((ret = machdep_sys_sendmsg(fd_table[fd]->fd.i, msg, flags)) < OK){ + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_write, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret = NOTOK; + break; + } + pthread_sched_resume(); + + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } + + } else { + SET_ERRNO(-ret); + ret = NOTOK; + break; + } + } + fd_unlock(fd, FD_WRITE); + } + return(ret); +} + +/* ========================================================================== + * sendmsg() + */ +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) +{ + return(sendmsg_timedwait(fd, msg, flags, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_RECV) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * recv_timedwait() + */ +ssize_t recv_timedwait(int fd, void * buf, size_t len, int flags, + struct timespec * timeout) +{ + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) { + while ((ret = machdep_sys_recv(fd_table[fd]->fd.i, + buf, len, flags)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_read, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDR_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDR_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + ret= -EINTR; + break; + } + + } else { + break; + } + } + fd_unlock(fd, FD_READ); + } + if (ret < 0) + { + SET_ERRNO(-ret); + return(NOTOK); + } + return(ret); +} + +/* ========================================================================== + * recv() + */ +ssize_t recv(int fd, void * buf, size_t len, int flags) +{ + return(recv_timedwait(fd, buf, len, flags, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_RECVFROM) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * recvfrom_timedwait() + */ +ssize_t recvfrom_timedwait(int fd, void * buf, size_t len, int flags, + struct sockaddr * from, int * from_len, + struct timespec * timeout) +{ + int ret; + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) { + while ((ret = machdep_sys_recvfrom(fd_table[fd]->fd.i, + buf, len, flags, from, from_len)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_read, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDR_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret= -ETIMEDOUT; + break; + } + pthread_sched_resume(); + + } else { + pthread_resched_resume(PS_FDR_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + ret= -EINTR; + break; + } + } else { + break; + } + } + fd_unlock(fd, FD_READ); + } + if (ret < 0) + { + SET_ERRNO(-ret); + return(NOTOK); + } + return(ret); +} + +/* ========================================================================== + * recvfrom() + */ +ssize_t recvfrom(int fd, void * buf, size_t len, int flags, + struct sockaddr * from, int * from_len) +{ + return(recvfrom_timedwait(fd, buf, len, flags, from, from_len, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_RECVMSG) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * recvmsg_timedwait() + */ +ssize_t recvmsg_timedwait(int fd, struct msghdr *msg, int flags, + struct timespec * timeout) +{ + struct stat stat_buf; + int passed_fd, ret, i; + + pthread_run->sighandled=0; /* Added by monty */ + if ((ret = fd_lock(fd, FD_READ, timeout)) == OK) { + while ((ret = machdep_sys_recvmsg(fd_table[fd]->fd.i, msg, flags)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && + ((ret == -EWOULDBLOCK) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDR_WAIT */ + SET_PF_WAIT_EVENT(pthread_run); + pthread_run->data.fd.fd = fd_table[fd]->fd.i; + pthread_queue_enq(&fd_wait_read, pthread_run); + + if (timeout) { + /* get current time */ + struct timespec current_time; + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDR_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); + ret = NOTOK; + break; + } + pthread_sched_resume(); + + } else { + pthread_resched_resume(PS_FDR_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + if (pthread_run->sighandled) /* Added by monty */ + { /* We where aborted */ + SET_ERRNO(EINTR); + ret= NOTOK; + break; + } + } else { + SET_ERRNO(-ret); + ret = NOTOK; + break; + } + } + fd_unlock(fd, FD_READ); + + /* Handle getting the real file descriptor */ + for (i = 0; i < (((struct omsghdr *)msg)->msg_accrightslen / sizeof(i)); + i++) { + passed_fd = *(((int *)((struct omsghdr *)msg)->msg_accrights) + i); + if (!((fd = fd_allocate()) < OK)) { + fd_table[fd]->flags = machdep_sys_fcntl(passed_fd, F_GETFL); + + if (!( fd_table[fd]->flags & __FD_NONBLOCK)) { + machdep_sys_fcntl(passed_fd, F_SETFL, + fd_table[fd]->flags | __FD_NONBLOCK); + } + + /* fstat the file to determine what type it is */ + machdep_sys_fstat(passed_fd, &stat_buf); + if (S_ISREG(stat_buf.st_mode)) { + fd_table[fd]->type = FD_HALF_DUPLEX; + } else { + fd_table[fd]->type = FD_FULL_DUPLEX; + } + *(((int *)((struct omsghdr *)msg)->msg_accrights) + i) = fd; + fd_table[fd]->ops = &(__fd_kern_ops); + fd_table[fd]->fd.i = passed_fd; + } else { + SET_ERRNO(EBADF); + return(NOTOK); + break; + } + } + } + return(ret); +} + +/* ========================================================================== + * recvmsg() + */ +ssize_t recvmsg(int fd, struct msghdr *msg, int flags) +{ + return(recvmsg_timedwait(fd, msg, flags, NULL)); +} + +#endif + +#if defined (HAVE_SYSCALL_SHUTDOWN) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * shutdown() + */ +int shutdown(int fd, int how) +{ + int ret; + + switch(how) { + case 0: /* Read */ + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; } + fd_unlock(fd, FD_READ); } - fd_unlock(fd, FD_RDWR); + case 1: /* Write */ + if ((ret = fd_lock(fd, FD_WRITE, NULL)) == OK) { + if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_WRITE); + } + case 2: /* Read-Write */ + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_shutdown(fd_table[fd]->fd.i, how)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } + default: + SET_ERRNO(EBADF); + ret = NOTOK; + break; } return(ret); } +#endif + +#if defined (HAVE_SYSCALL_SETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL) + /* ========================================================================== - * accept() + * setsockopt() */ -int accept(int fd, struct sockaddr *name, int *namelen) +int setsockopt(int fd, int level, int optname, const void * optval, int optlen) { - semaphore *lock, *plock; - int ret, fd_kern; + int ret; + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_setsockopt(fd_table[fd]->fd.i, level, + optname, optval, optlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } + return ret; +} +#endif - 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(); - } +#if defined (HAVE_SYSCALL_GETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL) - /* Lock pthread */ - plock = &(pthread_run->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } +/* ========================================================================== + * getsockopt() + */ +int getsockopt(int fd, int level, int optname, void * optval, int * optlen) +{ + int ret; - /* 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_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level, + optname, optval, optlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } + return ret; +} - if (!((ret = fd_allocate()) < OK)) { +#endif - /* This may be unnecessary */ - machdep_sys_fcntl(fd_kern, F_SETFL, __FD_NONBLOCK); +#if defined (HAVE_SYSCALL_GETSOCKOPT) || defined (HAVE_SYSCALL_SOCKETCALL) - /* 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; +/* ========================================================================== + * getsockname() + */ +int getsockname(int fd, struct sockaddr * name, int * naddrlen) +{ + int ret; + + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i, + name, naddrlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; } + fd_unlock(fd, FD_RDWR); } - return(ret); + return ret; } +#endif + +#if defined (HAVE_SYSCALL_GETPEERNAME) || defined (HAVE_SYSCALL_SOCKETCALL) + /* ========================================================================== - * listen() + * getpeername() */ -int listen(int fd, int backlog) +int getpeername(int fd, struct sockaddr * peer, int * paddrlen) { int ret; - if ((ret = fd_lock(fd, FD_RDWR)) == OK) { - ret = machdep_sys_listen(fd_table[fd]->fd, backlog); - fd_unlock(fd, FD_RDWR); + if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, + peer, paddrlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } + fd_unlock(fd, FD_READ); } - return(ret); + return ret; } + +#endif + +#if defined (HAVE_SYSCALL_SOCKETPAIR) || defined (HAVE_SYSCALL_SOCKETCALL) + +/* ========================================================================== + * socketpair() + */ +int socketpair(int af, int type, int protocol, int pair[2]) +{ + int ret, fd[2]; + + if (!((pair[0] = fd_allocate()) < OK)) { + if (!((pair[1] = fd_allocate()) < OK)) { + if (!((ret = machdep_sys_socketpair(af, type, protocol, fd)) < OK)){ + int tmp_flags; + + tmp_flags = machdep_sys_fcntl(fd[0], F_GETFL, 0); + machdep_sys_fcntl(fd[0], F_SETFL, tmp_flags | __FD_NONBLOCK); + fd_table[pair[0]]->ops = & __fd_kern_ops; + fd_table[pair[0]]->type = FD_FULL_DUPLEX; + fd_table[pair[0]]->flags = tmp_flags; + fd_table[pair[0]]->fd.i = fd[0]; + + tmp_flags = machdep_sys_fcntl(fd[1], F_GETFL, 0); + machdep_sys_fcntl(fd[1], F_SETFL, tmp_flags | __FD_NONBLOCK); + fd_table[pair[1]]->ops = & __fd_kern_ops; + fd_table[pair[1]]->type = FD_FULL_DUPLEX; + fd_table[pair[1]]->flags = tmp_flags; + fd_table[pair[1]]->fd.i = fd[1]; + + return(ret); + } + fd_table[pair[1]]->count = 0; + } + fd_table[pair[0]]->count = 0; + SET_ERRNO(-ret); + } + return(NOTOK); +} + +#endif diff --git a/lib/libpthread/pthreads/fd_pipe.c b/lib/libpthread/pthreads/fd_pipe.c index cfd18555c95..6e8a732640d 100644 --- a/lib/libpthread/pthreads/fd_pipe.c +++ b/lib/libpthread/pthreads/fd_pipe.c @@ -39,7 +39,7 @@ */ #ifndef lint -static const char rcsid[] = "$Id: fd_pipe.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: fd_pipe.c,v 1.16 1994/02/07 02:18:52 proven Exp $"; +static const char rcsid[] = "$Id: fd_pipe.c,v 1.1.1.2 1998/07/21 13:19:58 peter Exp $"; #endif #include <pthread.h> @@ -50,38 +50,39 @@ static const char rcsid[] = "$Id: fd_pipe.c,v 1.1.1.1 1995/10/18 08:43:05 deraad #include <fcntl.h> #include <errno.h> #include <pthread/posix.h> +#include <string.h> +#include <stdlib.h> + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif /* ========================================================================== * 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) +pthread_ssize_t __pipe_read(union fd_data fd_data, int flags, void *buf, + size_t nbytes, struct timespec * timeout) { - semaphore *lock, *plock; + struct __pipe *fd = (struct __pipe *)fd_data.ptr; + struct pthread * pthread; 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(); } + pthread_sched_prevent(); + /* queue pthread for a FDR_WAIT */ pthread_run->next = NULL; fd->wait = pthread_run; - SEMAPHORE_RESET(lock); - reschedule(PS_FDR_WAIT); + + pthread_resched_resume(PS_FDR_WAIT); ret = fd->size; } else { ret = MIN(nbytes, fd->count); @@ -90,17 +91,10 @@ ssize_t __pipe_read(struct __pipe *fd, int flags, void *buf, size_t nbytes) 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); + if (pthread = fd->wait) { + fd->wait = NULL; + pthread_sched_prevent(); + pthread_sched_other_resume(pthread); } } return(ret); @@ -116,23 +110,18 @@ ssize_t __pipe_read(struct __pipe *fd, int flags, void *buf, size_t nbytes) * 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; +pthread_ssize_t __pipe_write(union fd_data fd_data, int flags, const void *buf, + size_t nbytes, struct timespec * timeout) { + struct __pipe *fd = (struct __pipe *)fd_data.ptr; + struct pthread * pthread; 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(); - } + if (pthread = fd->wait) { + + pthread_sched_prevent(); /* Copy data directly into waiting pthreads buf */ fd->wait_size = MIN(nbytes, fd->wait_size); @@ -140,11 +129,10 @@ ssize_t __pipe_write(struct __pipe *fd, int flags, const void *buf, size_t nbyte buf = (const char *)buf + fd->wait_size; nbytes -= fd->wait_size; ret = fd->wait_size; + fd->wait = NULL; /* Wake up waiting pthread */ - fd->wait->state = PS_RUNNING; - SEMAPHORE_RESET(plock); - fd->wait = NULL; + pthread_sched_other_resume(pthread); } if (count = MIN(nbytes, fd->size - (fd->offset + fd->count))) { @@ -154,15 +142,9 @@ ssize_t __pipe_write(struct __pipe *fd, int flags, const void *buf, size_t nbyte ret += count; } if (nbytes) { - /* Lock pthread */ - plock = &(fd->wait->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } - + pthread_sched_prevent(); fd->wait = pthread_run; - SEMAPHORE_RESET(lock); - reschedule(PS_FDW_WAIT); + pthread_resched_resume(PS_FDW_WAIT); } else { return(ret); } @@ -184,29 +166,16 @@ ssize_t __pipe_write(struct __pipe *fd, int flags, const void *buf, size_t nbyte */ int __pipe_close(struct __pipe *fd, int flags) { - semaphore *lock, *plock; + struct pthread * pthread; - lock = &(fd->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } if (!(fd->flags)) { - if (fd->wait) { + if (pthread = 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; + fd->flags |= WR_CLOSED; + pthread_sched_prevent(); + pthread_resched_resume(pthread); } else { /* Should send a signal */ fd->flags |= RD_CLOSED; @@ -216,16 +185,37 @@ int __pipe_close(struct __pipe *fd, int flags) free(fd); return(OK); } - SEMAPHORE_RESET(lock); } /* ========================================================================== - * For those function that aren't implemented yet + * For fcntl() which isn't implemented yet * __pipe_enosys() */ static int __pipe_enosys() { - pthread_run->error = ENOSYS; + SET_ERRNO(ENOSYS); + return(NOTOK); +} + +/* ========================================================================== + * For writev() and readv() which aren't implemented yet + * __pipe_enosys_v() + */ +static int __pipe_enosys_v(union fd_data fd, int flags, + const struct iovec *vec, int nvec, + struct timespec *timeout) +{ + SET_ERRNO(ENOSYS); + return(NOTOK); +} + +/* ========================================================================== + * For lseek() which isn't implemented yet + * __pipe_enosys_o() + */ +static off_t __pipe_enosys_o() +{ + SET_ERRNO(ENOSYS); return(NOTOK); } @@ -233,9 +223,8 @@ static int __pipe_enosys() * File descriptor operations */ struct fd_ops fd_ops[] = { -{ NULL, NULL, }, /* Non operations */ -{ __pipe_write, __pipe_read, __pipe_close, __pipe_enosys, __pipe_enosys, - __pipe_enosys }, +{ __pipe_write, __pipe_read, __pipe_close, __pipe_enosys, + __pipe_enosys_v, __pipe_enosys_v, __pipe_enosys_o, 0 }, }; /* ========================================================================== diff --git a/lib/libpthread/pthreads/file.c b/lib/libpthread/pthreads/file.c index 0cdc462da52..f4b4150bb90 100644 --- a/lib/libpthread/pthreads/file.c +++ b/lib/libpthread/pthreads/file.c @@ -36,7 +36,7 @@ */ #ifndef lint -static const char rcsid[] = "$Id: file.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: file.c,v 1.16 1994/02/07 02:18:55 proven Exp $"; +static const char rcsid[] = "$Id: file.c,v 1.1.1.2 1998/07/21 13:20:00 peter Exp $"; #endif #include <pthread.h> @@ -47,21 +47,26 @@ static const char rcsid[] = "$Id: file.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt E */ void flockfile(FILE *fp) { - semaphore *lock; - int fd; + pthread_mutex_t *mutex; + int fd, flags; - fd = fileno(fp); - lock = &(fd_table[fd]->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + if ((fd = fileno(fp)) >= 0) { + pthread_mutex_lock(mutex = &(fd_table[fd]->mutex)); + + if (fp->_flags & __SRW) { + flags = FD_READ | FD_WRITE; + } else { + if (fp->_flags & __SWR) { + flags = FD_WRITE; + } else { + flags = FD_READ; + } + } - 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_basic_lock(fd, flags, mutex, NULL); + pthread_mutex_unlock(mutex); } - fd_table[fd]->lockcount++; - SEMAPHORE_RESET(lock); } /* ========================================================================== @@ -69,27 +74,31 @@ void flockfile(FILE *fp) */ int ftrylockfile(FILE *fp) { - semaphore *lock; - int fd; + pthread_mutex_t *mutex; + int fd, flags; - fd = fileno(fp); - lock = &(fd_table[fd]->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + if ((fd = fileno(fp)) >= 0) { + pthread_mutex_lock(mutex = &(fd_table[fd]->mutex)); - if (fd_table[fd]->r_owner != pthread_run) { + if (fp->_flags & __SRW) { + flags = FD_READ | FD_WRITE; + } else { + if (fp->_flags & __SWR) { + flags = FD_WRITE; + } else { + flags = FD_READ; + } + } if (!(fd_table[fd]->r_owner && fd_table[fd]->w_owner)) { - fd_basic_lock(fd, FD_RDWR, lock); + fd_basic_lock(fd, flags, mutex, NULL); fd = OK; } else { fd = NOTOK; } + pthread_mutex_unlock(mutex); } else { - fd_table[fd]->lockcount++; fd = OK; } - SEMAPHORE_RESET(lock); return(fd); } @@ -98,20 +107,23 @@ int ftrylockfile(FILE *fp) */ void funlockfile(FILE *fp) { - semaphore *lock; - int fd; + pthread_mutex_t *mutex; + int fd, flags; - fd = fileno(fp); - lock = &(fd_table[fd]->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + if ((fd = fileno(fp)) >= 0) { + pthread_mutex_lock(mutex = &(fd_table[fd]->mutex)); - if (fd_table[fd]->r_owner == pthread_run) { - if (--fd_table[fd]->lockcount == 0) { - fd_basic_unlock(fd, FD_RDWR); + if (fp->_flags & __SRW) { + flags = FD_READ | FD_WRITE; + } else { + if (fp->_flags & __SWR) { + flags = FD_WRITE; + } else { + flags = FD_READ; + } } - } - SEMAPHORE_RESET(lock); + fd_basic_unlock(fd, flags); + pthread_mutex_unlock(mutex); + } } diff --git a/lib/libpthread/pthreads/globals.c b/lib/libpthread/pthreads/globals.c index 6d68f58028d..48315ed12ec 100644 --- a/lib/libpthread/pthreads/globals.c +++ b/lib/libpthread/pthreads/globals.c @@ -36,32 +36,50 @@ */ #ifndef lint -static const char rcsid[] = "$Id: globals.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: globals.c,v 1.16 1994/02/07 02:18:57 proven Exp $"; +static const char rcsid[] = "$Id: globals.c,v 1.1.1.2 1998/07/21 13:20:02 peter Exp $"; #endif #include <pthread.h> /* - * Initial thread, running thread, and top of link list - * of all threads. + * 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; +struct pthread *pthread_run=NULL; +struct pthread *pthread_initial=NULL; +struct pthread *pthread_link_list=NULL; + +sigset_t * uthread_sigmask; /* Current process signal mask */ /* - * default thread attributes + * Dead thread queue, and threads elligible to be alloced queue. */ -pthread_attr_t pthread_default_attr = { SCHED_RR, NULL, PTHREAD_STACK_DEFAULT }; +struct pthread_queue pthread_dead_queue; +struct pthread_queue pthread_alloc_queue; /* * Queue for all threads elidgeable to run this scheduling round. */ -struct pthread_queue pthread_current_queue = PTHREAD_QUEUE_INITIALIZER; +struct pthread_prio_queue * pthread_current_prio_queue=NULL; + +/* + * default thread attributes + */ +pthread_attr_t pthread_attr_default = { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, + PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; /* * File table information */ -struct fd_table_entry *fd_table[64]; +struct fd_table_entry **fd_table=NULL; +/* + * A we a fork()ed process + */ +volatile int fork_lock = 0; +volatile int pthread_kernel_lock=0; + +/* + * The page size, as returned by getpagesize() + */ +size_t pthread_pagesize=0; diff --git a/lib/libpthread/pthreads/malloc.c b/lib/libpthread/pthreads/malloc.c index 02118537c9f..b071fd8f04f 100644 --- a/lib/libpthread/pthreads/malloc.c +++ b/lib/libpthread/pthreads/malloc.c @@ -46,7 +46,7 @@ */ #ifndef lint -static const char rcsid[] = "$Id: malloc.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: malloc.c,v 1.16 1994/02/07 02:19:00 proven Exp $"; +static const char rcsid[] = "$Id: malloc.c,v 1.1.1.2 1998/07/21 13:20:05 peter Exp $"; #endif #include <pthread.h> @@ -64,14 +64,20 @@ static const char rcsid[] = "$Id: malloc.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt * 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. */ +#ifdef __alpha +#define _MOST_RESTRICTIVE_ALIGNMENT_TYPE char* +#else +#define _MOST_RESTRICTIVE_ALIGNMENT_TYPE double +#endif /* __alpha */ union overhead { + _MOST_RESTRICTIVE_ALIGNMENT_TYPE __alignment_pad0; 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 */ + size_t ovu_size; /* actual block size */ #endif } ovu; #define ov_magic ovu.ovu_magic @@ -96,11 +102,13 @@ union overhead { */ #define NBUCKETS 30 static union overhead *nextf[NBUCKETS]; +#ifndef hpux extern char *sbrk(); +#endif -static int pagesz; /* page size */ +static size_t pagesz; /* page size */ static int pagebucket; /* page size bucket */ -static semaphore malloc_lock = SEMAPHORE_CLEAR; +static pthread_mutex_t malloc_mutex = PTHREAD_MUTEX_INITIALIZER; #if defined(DEBUG) || defined(RCHECK) #define ASSERT(p) if (!(p)) botch("p") @@ -125,15 +133,15 @@ botch(s) 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 */ + register size_t sz; /* size of desired block */ + size_t amt; /* amount to allocate */ + size_t 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); + sz = 1L << (bucket + 3); #ifdef DEBUG ASSERT(sz > 0); #else @@ -149,8 +157,8 @@ static inline void morecore(int bucket) } op = (union overhead *)sbrk(amt); /* no more room! */ - if ((int)op == -1) - return; + if (op == (union overhead *) -1) + return; /* * Add new memory allocated to that on * free list for this hash bucket. @@ -167,28 +175,32 @@ static inline void morecore(int bucket) */ void *malloc(size_t nbytes) { + pthread_mutex_t *mutex; union overhead *op; - unsigned int amt; - int bucket, n; - semaphore *lock; + size_t amt; + size_t bucket, n; - lock = &malloc_lock; - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + mutex = &malloc_mutex; + pthread_mutex_lock(mutex); /* * First time malloc is called, setup page size and * align break pointer so all data will be page aligned. */ if (pagesz == 0) { + size_t x; pagesz = n = getpagesize(); op = (union overhead *)sbrk(0); - n = n - sizeof (*op) - ((int)op & (n - 1)); - if (n < 0) - n += pagesz; + x = sizeof (*op) - ((long)op & (n - 1)); + if (n < x) + n = n + pagesz - x; + else + n = n - x; if (n) { - if (sbrk(n) == (char *)-1) - return (NULL); + if (sbrk(n) == (char *)-1) { + /* Unlock before returning (mevans) */ + pthread_mutex_unlock(mutex); + return (NULL); + } } bucket = 0; amt = 8; @@ -219,11 +231,12 @@ void *malloc(size_t nbytes) while (nbytes > amt + n) { amt <<= 1; if (amt == 0) { - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return (NULL); } bucket++; } + ASSERT (bucket < NBUCKETS); /* * If nothing in hash bucket right now, * request more memory from the system. @@ -231,7 +244,7 @@ void *malloc(size_t nbytes) if ((op = nextf[bucket]) == NULL) { morecore(bucket); if ((op = nextf[bucket]) == NULL) { - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return (NULL); } } @@ -248,7 +261,7 @@ void *malloc(size_t nbytes) op->ov_rmagic = RMAGIC; *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return ((char *)(op + 1)); } @@ -257,16 +270,14 @@ void *malloc(size_t nbytes) */ void free(void *cp) { + pthread_mutex_t *mutex; union overhead *op; - semaphore *lock; - int size; + int size; - lock = &malloc_lock; - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + mutex = &malloc_mutex; + pthread_mutex_lock(mutex); if (cp == NULL) { - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return; } op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); @@ -274,7 +285,7 @@ void free(void *cp) ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */ #else if (op->ov_magic != MAGIC) { - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return; /* sanity */ } #endif @@ -287,7 +298,7 @@ void free(void *cp) op->ov_next = nextf[size]; /* also clobbers ov_magic */ nextf[size] = op; - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); } /* ========================================================================== @@ -297,9 +308,9 @@ void free(void *cp) */ void *realloc(void *cp, size_t nbytes) { - u_int onb; - int i; - semaphore *lock; + pthread_mutex_t *mutex; + size_t onb; + size_t i; union overhead *op; char *res; @@ -319,11 +330,9 @@ void *realloc(void *cp, size_t nbytes) return(NULL); } - lock = &malloc_lock; - while(SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } - onb = 1 << (i + 3); + mutex = &malloc_mutex; + pthread_mutex_lock(mutex); + onb = 1L << (i + 3); if (onb < pagesz) onb -= sizeof (*op) + RSLOP; else @@ -331,7 +340,7 @@ void *realloc(void *cp, size_t nbytes) /* avoid the copy if same size block */ if (i) { - i = 1 << (i + 2); + i = 1L << (i + 2); if (i < pagesz) i -= sizeof (*op) + RSLOP; else @@ -343,19 +352,32 @@ void *realloc(void *cp, size_t nbytes) op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); return(cp); } - SEMAPHORE_RESET(lock); + pthread_mutex_unlock(mutex); if ((res = malloc(nbytes)) == NULL) { free(cp); return (NULL); } - bcopy(cp, res, (nbytes < onb) ? nbytes : onb); + memcpy(res, cp, (nbytes < onb) ? nbytes : onb); free(cp); return (res); } +/* ========================================================================== + * calloc() + * + * Added to ensure pthread's allocation is used (mevans). + */ +void *calloc(size_t nmemb, size_t size) +{ + void *p; + size *= nmemb; + p = malloc(size); + if (p) memset(p, 0, size); + return (p); +} diff --git a/lib/libpthread/pthreads/mutex.c b/lib/libpthread/pthreads/mutex.c index 339f9d922b9..9e53df5add3 100644 --- a/lib/libpthread/pthreads/mutex.c +++ b/lib/libpthread/pthreads/mutex.c @@ -1,4 +1,4 @@ -/* ==== mutex.c ============================================================ +/* ==== mutex.c ============================================================== * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu * All rights reserved. * @@ -36,22 +36,33 @@ */ #ifndef lint -static const char rcsid[] = "$Id: mutex.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: mutex.c,v 1.16 1994/02/07 02:19:03 proven Exp $"; +static const char rcsid[] = "$Id: mutex.c,v 1.1.1.2 1998/07/21 13:20:07 peter Exp $"; #endif #include <pthread.h> +#include <stdlib.h> #include <errno.h> -/* - * Basic mutex functionality - - * This is the basic lock order - * queue - * pthread - * global +/* ========================================================================== + * pthread_mutex_is_debug() * - * semaphore functionality is defined in machdep.h + * Check that mutex is a debug mutex and if so returns entry number into + * array of debug mutexes. */ +static int pthread_mutex_debug_count = 0; +static pthread_mutex_t ** pthread_mutex_debug_ptrs = NULL; + +static inline int pthread_mutex_is_debug(pthread_mutex_t * mutex) +{ + int i; + + for (i = 0; i < pthread_mutex_debug_count; i++) { + if (pthread_mutex_debug_ptrs[i] == mutex) { + return(i); + } + } + return(NOTOK); +} /* ========================================================================== * pthread_mutex_init() @@ -60,25 +71,62 @@ static const char rcsid[] = "$Id: mutex.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt * 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) +int pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr) { + enum pthread_mutextype type; + /* 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; + type = mutex_attr->m_type; } else { - mutex->m_type = MUTEX_TYPE_FAST; + type = MUTEX_TYPE_FAST; + } + mutex->m_flags = 0; + + pthread_sched_prevent(); + + switch(type) { + case MUTEX_TYPE_FAST: + break; + case MUTEX_TYPE_STATIC_FAST: + pthread_sched_resume(); + return(EINVAL); + break; + case MUTEX_TYPE_COUNTING_FAST: + mutex->m_data.m_count = 0; + break; + case MUTEX_TYPE_DEBUG: + if (pthread_mutex_is_debug(mutex) == NOTOK) { + pthread_mutex_t ** new; + + if ((new = (pthread_mutex_t **)realloc(pthread_mutex_debug_ptrs, + (pthread_mutex_debug_count + 1) * (sizeof(void *)))) == NULL) { + pthread_sched_resume(); + return(ENOMEM); + } + pthread_mutex_debug_ptrs = new; + pthread_mutex_debug_ptrs[pthread_mutex_debug_count++] = mutex; + } else { + pthread_sched_resume(); + return(EBUSY); + } + break; + default: + pthread_sched_resume(); + return(EINVAL); + break; } /* 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; + mutex->m_type = type; + + pthread_sched_resume(); return(OK); } @@ -87,22 +135,48 @@ int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *mutex_attr) */ int pthread_mutex_destroy(pthread_mutex_t *mutex) { + int i; + + pthread_sched_prevent(); + /* Only check if mutex is of type other than fast */ switch(mutex->m_type) { case MUTEX_TYPE_FAST: break; case MUTEX_TYPE_STATIC_FAST: + pthread_sched_resume(); + return(EINVAL); + break; + case MUTEX_TYPE_COUNTING_FAST: + mutex->m_data.m_count = 0; + break; + case MUTEX_TYPE_DEBUG: + if ((i = pthread_mutex_is_debug(mutex)) == NOTOK) { + pthread_sched_resume(); + return(EINVAL); + } + if (mutex->m_owner) { + pthread_sched_resume(); + return(EBUSY); + } + + /* Remove the mutex from the list of debug mutexes */ + pthread_mutex_debug_ptrs[i] = + pthread_mutex_debug_ptrs[--pthread_mutex_debug_count]; + pthread_mutex_debug_ptrs[pthread_mutex_debug_count] = NULL; + break; default: + pthread_sched_resume(); 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; + + pthread_sched_resume(); return(OK); } @@ -111,14 +185,9 @@ int pthread_mutex_destroy(pthread_mutex_t *mutex) */ int pthread_mutex_trylock(pthread_mutex_t *mutex) { - semaphore *lock; int rval; - lock = &(mutex->m_lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } - + pthread_sched_prevent(); switch (mutex->m_type) { /* * Fast mutexes do not check for any error conditions. @@ -132,11 +201,37 @@ int pthread_mutex_trylock(pthread_mutex_t *mutex) rval = EBUSY; } break; + case MUTEX_TYPE_COUNTING_FAST: + if (mutex->m_owner) { + if (mutex->m_owner == pthread_run) { + mutex->m_data.m_count++; + rval = OK; + } else { + rval = EBUSY; + } + } else { + mutex->m_owner = pthread_run; + rval = OK; + } + break; + case MUTEX_TYPE_DEBUG: + if (pthread_mutex_is_debug(mutex) != NOTOK) { + if (!mutex->m_owner) { + mutex->m_owner = pthread_run; + rval = OK; + } else { + rval = EBUSY; + } + } else { + rval = EINVAL; + } + break; default: rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + + pthread_sched_resume(); return(rval); } @@ -145,14 +240,9 @@ int pthread_mutex_trylock(pthread_mutex_t *mutex) */ 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(); - } - + pthread_sched_prevent(); switch (mutex->m_type) { /* * Fast mutexes do not check for any error conditions. @@ -160,25 +250,60 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) 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); + /* Reschedule will unlock scheduler */ + pthread_resched_resume(PS_MUTEX_WAIT); return(OK); } mutex->m_owner = pthread_run; rval = OK; break; + case MUTEX_TYPE_COUNTING_FAST: + if (mutex->m_owner) { + if (mutex->m_owner != pthread_run) { + pthread_queue_enq(&mutex->m_queue, pthread_run); + + /* Reschedule will unlock scheduler */ + pthread_resched_resume(PS_MUTEX_WAIT); + return(OK); + } else { + mutex->m_data.m_count++; + } + } else { + mutex->m_owner = pthread_run; + } + rval = OK; + break; + case MUTEX_TYPE_DEBUG: + if (pthread_mutex_is_debug(mutex) != NOTOK) { + if (mutex->m_owner) { + if (mutex->m_owner != pthread_run) { + pthread_queue_enq(&mutex->m_queue, pthread_run); + + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_MUTEX_WAIT); + + if (mutex->m_owner != pthread_run) { + PANIC(); + } + return(OK); + } + rval = EDEADLK; + break; + } + mutex->m_owner = pthread_run; + rval = OK; + break; + } + rval = EINVAL; + break; default: rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + + pthread_sched_resume(); return(rval); } @@ -188,40 +313,59 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) 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(); - } - + pthread_sched_prevent(); + 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; + if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) { - /* Reset pthread state */ - pthread_queue_deq(&mutex->m_queue); - pthread->state = PS_RUNNING; - SEMAPHORE_RESET(plock); - } else { - mutex->m_owner = NULL; + /* Reschedule will unlock scheduler */ + pthread_sched_other_resume(mutex->m_owner); + return(OK); + } + rval = OK; + break; + case MUTEX_TYPE_COUNTING_FAST: + if (mutex->m_data.m_count) { + mutex->m_data.m_count--; + rval = OK; + break; + } + if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) { + + /* Reschedule will unlock scheduler */ + pthread_sched_other_resume(mutex->m_owner); + return(OK); } rval = OK; break; + case MUTEX_TYPE_DEBUG: + if (pthread_mutex_is_debug(mutex) != NOTOK) { + if (mutex->m_owner == pthread_run) { + if (mutex->m_owner = pthread_queue_deq(&mutex->m_queue)) { + + /* Reschedule will unlock scheduler */ + pthread_sched_other_resume(mutex->m_owner); + return(OK); + } + rval = OK; + } else { + rval = EPERM; + } + } else { + rval = EINVAL; + } + break; default: rval = EINVAL; break; } - SEMAPHORE_RESET(lock); + pthread_sched_resume(); return(rval); } diff --git a/lib/libpthread/pthreads/pthread.c b/lib/libpthread/pthreads/pthread.c index 7bf9ad35897..0460b8e08f9 100644 --- a/lib/libpthread/pthreads/pthread.c +++ b/lib/libpthread/pthreads/pthread.c @@ -36,52 +36,23 @@ */ #ifndef lint -static const char rcsid[] = "$Id: pthread.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: pthread.c,v 1.16 1994/02/07 02:19:06 proven Exp $"; +static const char rcsid[] = "$Id: pthread.c,v 1.1.1.2 1998/07/21 13:20:09 peter Exp $"; #endif -#include "pthread.h" +#include <pthread.h> +#include <stdlib.h> #include <signal.h> #include <errno.h> - -/* - * These first functions really should not be called by the user. - */ +#include <string.h> +#include <sched.h> /* ========================================================================== - * 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. + * sched_yield() */ -void pthread_init(void) +int sched_yield() { - 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(); + sig_handler_fake(SIGVTALRM); + return(OK); } /* ========================================================================== @@ -92,7 +63,6 @@ void pthread_yield() sig_handler_fake(SIGVTALRM); } -/* ======================================================================= */ /* ========================================================================== * pthread_self() */ @@ -112,41 +82,141 @@ int pthread_equal(pthread_t t1, pthread_t t2) /* ========================================================================== * pthread_exit() */ +extern void pthread_cleanupspecific(void); + 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; + while (pthread_run->cleanup) { + pthread_cleanup_pop(1); + } + + /* Don't forget the cleanup attr */ + if (pthread_run->attr.cleanup_attr) { + pthread_run->attr.cleanup_attr(pthread_run->attr.arg_attr); + } - /* Thread will unlock itself in pthread_join() */ + /* Next run thread-specific data desctructors */ + if (pthread_run->specific_data) { + pthread_cleanupspecific(); + } + + pthread_sched_prevent(); + + if (!(pthread_run->attr.flags & PTHREAD_DETACHED)) { + /* + * Are there any threads joined to this one, + * if so wake them and let them detach this thread. + */ + while (pthread = pthread_queue_deq(&(pthread_run->join_queue))) { + pthread_prio_queue_enq(pthread_current_prio_queue, pthread); + pthread->state = PS_RUNNING; + } + pthread_queue_enq(&pthread_dead_queue, pthread_run); + pthread_resched_resume(PS_DEAD); + } else { + pthread_queue_enq(&pthread_alloc_queue, pthread_run); + pthread_resched_resume(PS_UNALLOCED); } /* This thread will never run again */ - reschedule(PS_DEAD); PANIC(); + +} + +/*---------------------------------------------------------------------- + * Function: __pthread_is_valid + * Purpose: Scan the list of threads to see if a specified thread exists + * Args: + * pthread = The thread to scan for + * Returns: + * int = 1 if found, 0 if not + * Notes: + * The kernel is assumed to be locked + *----------------------------------------------------------------------*/ +int +__pthread_is_valid( pthread_t pthread ) +{ + int rtn = 0; /* Assume not found */ + pthread_t t; + + for( t = pthread_link_list; t; t = t->pll ) { + if( t == pthread ) { + rtn = 1; /* Found it */ + break; + } + } + + return rtn; +} + +/* ========================================================================== + * __pthread_free() + */ +static inline void __pthread_free(pthread_t new_thread) +{ + pthread_sched_prevent(); + new_thread->state = PS_UNALLOCED; + new_thread->attr.stacksize_attr = 0; + new_thread->attr.stackaddr_attr = NULL; + pthread_queue_enq(&pthread_alloc_queue, new_thread); + pthread_sched_resume(); +} +/* ========================================================================== + * __pthread_alloc() + */ +/* static inline pthread_t __pthread_alloc(const pthread_attr_t *attr) */ +static pthread_t __pthread_alloc(const pthread_attr_t *attr) +{ + pthread_t thread; + void * stack; + void * old; + + pthread_sched_prevent(); + thread = pthread_queue_deq(&pthread_alloc_queue); + pthread_sched_resume(); + + if (thread) { + if (stack = attr->stackaddr_attr) { + __machdep_stack_repl(&(thread->machdep_data), stack); + } else { + if ((__machdep_stack_get(&(thread->machdep_data)) == NULL) + || (attr->stacksize_attr > thread->attr.stacksize_attr)) { + if (stack = __machdep_stack_alloc(attr->stacksize_attr)) { + __machdep_stack_repl(&(thread->machdep_data), stack); + } else { + __pthread_free(thread); + thread = NULL; + } + } + } + } else { + /* We should probable allocate several for efficiency */ + if (thread = (pthread_t)malloc(sizeof(struct pthread))) { + /* Link new thread into list of all threads */ + + pthread_sched_prevent(); + thread->state = PS_UNALLOCED; + thread->pll = pthread_link_list; + pthread_link_list = thread; + pthread_sched_resume(); + + if ((stack = attr->stackaddr_attr) || + (stack = __machdep_stack_alloc(attr->stacksize_attr))) { + __machdep_stack_set(&(thread->machdep_data), stack); + } else { + __machdep_stack_set(&(thread->machdep_data), NULL); + __pthread_free(thread); + thread = NULL; + } + } + } + return(thread); } /* ========================================================================== @@ -159,46 +229,65 @@ void pthread_exit(void *status) 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(); + pthread_t new_thread; + int nsec = 100000000; + int retval = OK; + + if (! attr) + attr = &pthread_attr_default; + + if (new_thread = __pthread_alloc(attr)) { + + __machdep_pthread_create(&(new_thread->machdep_data), + start_routine, arg, attr->stacksize_attr, nsec, 0); + + memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t)); + if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { + new_thread->pthread_priority = pthread_run->pthread_priority; + new_thread->attr.sched_priority = pthread_run->pthread_priority; + new_thread->attr.schedparam_policy = + pthread_run->attr.schedparam_policy; + } else { + new_thread->pthread_priority = new_thread->attr.sched_priority; + } - return(OK); + if (!(new_thread->attr.flags & PTHREAD_NOFLOAT)) { + machdep_save_float_state(new_thread); } - free((*thread)); + + /* Initialize signalmask */ + new_thread->sigmask = pthread_run->sigmask; + sigemptyset(&(new_thread->sigpending)); + new_thread->sigcount = 0; + + pthread_queue_init(&(new_thread->join_queue)); + new_thread->specific_data = NULL; + new_thread->specific_data_count = 0; + new_thread->cleanup = NULL; + new_thread->queue = NULL; + new_thread->next = NULL; + new_thread->flags = 0; + + /* PTHREADS spec says we start with cancellability on and deferred */ + SET_PF_CANCEL_STATE(new_thread, PTHREAD_CANCEL_ENABLE); + SET_PF_CANCEL_TYPE(new_thread, PTHREAD_CANCEL_DEFERRED); + + new_thread->error_p = NULL; + new_thread->sll = NULL; + + pthread_sched_prevent(); + + + pthread_sched_other_resume(new_thread); + /* + * Assignment must be outside of the locked pthread kernel incase + * thread is a bogus address resulting in a seg-fault. We want the + * original thread to be capable of handling the resulting signal. + * --proven + */ + (*thread) = new_thread; + } else { + retval = EAGAIN; } - return(ENOMEM); + return(retval); } - -/* ========================================================================== - * 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 index 8efdf32b4f6..397c1fe115c 100644 --- a/lib/libpthread/pthreads/pthread_attr.c +++ b/lib/libpthread/pthreads/pthread_attr.c @@ -36,11 +36,12 @@ */ #ifndef lint -static const char rcsid[] = "$Id: pthread_attr.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: pthread_attr.c,v 1.16 1994/02/07 02:19:14 proven Exp $"; +static const char rcsid[] = "$Id: pthread_attr.c,v 1.1.1.2 1998/07/21 13:20:12 peter Exp $"; #endif #include <pthread.h> #include <errno.h> +#include <string.h> /* Currently we do no locking, should we just to be safe? CAP */ /* ========================================================================== @@ -48,7 +49,7 @@ static const char rcsid[] = "$Id: pthread_attr.c,v 1.1.1.1 1995/10/18 08:43:05 d */ int pthread_attr_init(pthread_attr_t *attr) { - memcpy(attr, &pthread_default_attr, sizeof(pthread_attr_t)); + memcpy(attr, &pthread_attr_default, sizeof(pthread_attr_t)); return(OK); } @@ -98,3 +99,157 @@ int pthread_attr_setstackaddr(pthread_attr_t *attr, void * stackaddr) attr->stackaddr_attr = stackaddr; return(OK); } + +/* ========================================================================== + * pthread_attr_setcleanup() + */ +int pthread_attr_setcleanup(pthread_attr_t *attr, void (*routine)(void *), + void * arg) +{ + attr->cleanup_attr = routine; + attr->arg_attr = arg; + return(OK); +} + +/* ========================================================================== + * pthread_attr_getdetachstate() + */ +int pthread_attr_getdetachstate(pthread_attr_t *attr, int * detachstate) +{ + *detachstate = attr->flags & PTHREAD_DETACHED; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setdetachstate() + */ +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + attr->flags = (attr->flags & ~(PTHREAD_DETACHED)) | + (detachstate & PTHREAD_DETACHED); + return(OK); +} + +/* ========================================================================== + * pthread_attr_getfloatstate() + */ +int pthread_attr_getfloatstate(pthread_attr_t *attr, int * floatstate) +{ + *floatstate = attr->flags & PTHREAD_NOFLOAT; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setfloatstate() + */ +int pthread_attr_setfloatstate(pthread_attr_t *attr, int floatstate) +{ + attr->flags = (attr->flags & ~(PTHREAD_NOFLOAT)) | + (floatstate & PTHREAD_NOFLOAT); + return(OK); +} + +/* ========================================================================== + * pthread_attr_getscope() + */ +int pthread_attr_getscope(pthread_attr_t *attr, int * contentionscope) +{ + *contentionscope = attr->flags & PTHREAD_SCOPE_SYSTEM; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setscope() + */ +int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) +{ + int ret; + + switch (contentionscope) { + case PTHREAD_SCOPE_PROCESS: + attr->flags = (attr->flags & ~(PTHREAD_SCOPE_PROCESS)) + | PTHREAD_SCOPE_PROCESS; + ret = OK; + break; + case PTHREAD_SCOPE_SYSTEM: + ret = ENOSYS; + break; + default: + ret = EINVAL; + break; + } + + return(ret); +} + +/* ========================================================================== + * pthread_attr_getinheritsched() + */ +int pthread_attr_getinheritsched(pthread_attr_t *attr, int * inheritsched) +{ + *inheritsched = attr->flags & PTHREAD_INHERIT_SCHED; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setinheritsched() + */ +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) +{ + attr->flags = (attr->flags & ~(PTHREAD_INHERIT_SCHED)) | + (inheritsched & PTHREAD_INHERIT_SCHED); + return(OK); +} + +/* ========================================================================== + * pthread_attr_getschedpolicy() + */ +int pthread_attr_getschedpolicy(pthread_attr_t *attr, int * schedpolicy) +{ + *schedpolicy = (int)attr->schedparam_policy; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setschedpolicy() + */ +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int schedpolicy) +{ + int ret; + + switch(schedpolicy) { + case SCHED_FIFO: + case SCHED_IO: + case SCHED_RR: + attr->schedparam_policy = schedpolicy; + ret = OK; + break; + default: + ret = EINVAL; + break; + } + return(ret); +} + +/* ========================================================================== + * pthread_attr_getschedparam() + */ +int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param * param) +{ + param->sched_priority = attr->sched_priority; + return(OK); +} + +/* ========================================================================== + * pthread_attr_setschedparam() + */ +int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param * param) +{ + if ((param->sched_priority >= PTHREAD_MIN_PRIORITY) && + (param->sched_priority <= PTHREAD_MAX_PRIORITY)) { + attr->sched_priority = param->sched_priority; + return(OK); + } + return(EINVAL); +} + diff --git a/lib/libpthread/pthreads/pthread_detach.c b/lib/libpthread/pthreads/pthread_detach.c index 733fa45436e..1aa2656ac77 100644 --- a/lib/libpthread/pthreads/pthread_detach.c +++ b/lib/libpthread/pthreads/pthread_detach.c @@ -36,9 +36,10 @@ */ #ifndef lint -static const char rcsid[] = "$Id: pthread_detach.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: pthread_detach.c,v 1.16 1994/02/07 02:19:16 proven Exp $"; +static const char rcsid[] = "$Id: pthread_detach.c,v 1.1.1.2 1998/07/21 13:20:14 peter Exp $"; #endif +#include <errno.h> #include <pthread.h> /* ========================================================================== @@ -46,45 +47,46 @@ static const char rcsid[] = "$Id: pthread_detach.c,v 1.1.1.1 1995/10/18 08:43:05 */ int pthread_detach(pthread_t pthread) { - semaphore *plock; + struct pthread * next_thread, * high_thread, * low_thread; int ret; - plock = &(pthread->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } + pthread_sched_prevent(); /* Check that thread isn't detached already */ - if (!(pthread->flags & PF_DETACHED)) { - - pthread->flags |= PF_DETACHED; + if (!(pthread->attr.flags & PTHREAD_DETACHED)) { - /* Wakeup first threads waiting on a join */ - { - struct pthread * next_thread; - semaphore * next_lock; + pthread->attr.flags |= PTHREAD_DETACHED; - if (next_thread = pthread_queue_get(&(pthread->join_queue))) { - next_lock = &(next_thread->lock); - while (SEMAPHORE_TEST_AND_SET(next_lock)) { - pthread_yield(); + /* Wakeup all threads waiting on a join */ + if (next_thread = pthread_queue_deq(&(pthread->join_queue))) { + high_thread = next_thread; + + while (next_thread = pthread_queue_deq(&(pthread->join_queue))) { + if (high_thread->pthread_priority < next_thread->pthread_priority) { + low_thread = high_thread; + high_thread = next_thread; + } else { + low_thread = next_thread; } - 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); + pthread_prio_queue_enq(pthread_current_prio_queue, low_thread); + low_thread->state = PS_RUNNING; + } + /* If the thread is dead then move it to the alloc queue */ + if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) { + pthread_queue_enq(&pthread_alloc_queue, pthread); } + pthread_sched_other_resume(high_thread); + return(OK); + } + /* If the thread is dead then move it to the alloc queue */ + if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) { + pthread_queue_enq(&pthread_alloc_queue, pthread); + pthread->state = PS_UNALLOCED; } ret = OK; - } else { - SEMAPHORE_RESET(plock); ret = ESRCH; } + pthread_sched_resume(); return(ret); } diff --git a/lib/libpthread/pthreads/pthread_join.c b/lib/libpthread/pthreads/pthread_join.c index a1dbdefc1d4..f0e503510aa 100644 --- a/lib/libpthread/pthreads/pthread_join.c +++ b/lib/libpthread/pthreads/pthread_join.c @@ -36,78 +36,104 @@ */ #ifndef lint -static const char rcsid[] = "$Id: pthread_join.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: pthread_join.c,v 1.16 1994/02/07 02:19:19 proven Exp $"; +static const char rcsid[] = "$Id: pthread_join.c,v 1.1.1.2 1998/07/21 13:20:16 peter Exp $"; #endif #include <pthread.h> +#include <errno.h> + +static int testDeadlock( struct pthread_queue *queue, pthread_t target ); /* ========================================================================== * pthread_join() */ int pthread_join(pthread_t pthread, void **thread_return) { - semaphore *lock, *plock; int ret; + pthread_sched_prevent(); - plock = &(pthread->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } + /* Ensure they gave us a legal pthread pointer */ + if( ! __pthread_is_valid( pthread ) ) { + pthread_sched_resume(); + return(EINVAL); + } /* Check that thread isn't detached already */ - if (pthread->flags & PF_DETACHED) { - SEMAPHORE_RESET(plock); + if (pthread->attr.flags & PTHREAD_DETACHED) { + pthread_sched_resume(); return(ESRCH); } - lock = &(pthread_run->lock); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + /* + * Now check if other thread has exited + * Note: This must happen after checking detached state. + */ + if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) { - /* If OK then queue current thread. */ - pthread_queue(&(pthread->join_queue), pthread_run); + /* Before we pend on the join, ensure there is no dead lock */ - SEMAPHORE_RESET(plock); - reschedule(PS_JOIN); + if( testDeadlock( &pthread_run->join_queue, pthread ) == NOTOK ) { + ret = EDEADLK; + } else { + pthread_queue_enq(&(pthread->join_queue), pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_JOIN); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + pthread_sched_prevent(); - /* - * 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; + if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) { + pthread_queue_enq(&pthread_alloc_queue, pthread); + pthread->attr.flags |= PTHREAD_DETACHED; + pthread->state = PS_UNALLOCED; + if (thread_return) { + *thread_return = pthread->ret; + } + ret = OK; + } else { + ret = ESRCH; + } } - pthread->flags |= PF_DETACHED; + } else { + /* Just get the return value and detach the thread */ + pthread_queue_enq(&pthread_alloc_queue, pthread); + pthread->attr.flags |= PTHREAD_DETACHED; + pthread->state = PS_UNALLOCED; + if (thread_return) { + *thread_return = pthread->ret; + } ret = OK; - } else { - ret = ESRCH; } + pthread_sched_resume(); + return(ret); +} + +/*---------------------------------------------------------------------- + * Function: testDeadlock + * Purpose: recursive queue walk to check for deadlocks + * Args: + * queue = the queue to walk + * pthread = target to scan for + * Returns: + * OK = no deadlock, NOTOK = deadlock + * Notes: + *----------------------------------------------------------------------*/ +static int +testDeadlock( struct pthread_queue *queue, pthread_t target ) +{ + pthread_t t; - /* Cant do a cleanup until queue is cleared */ - { - struct pthread * next_thread; - semaphore * next_lock; + if( queue == NULL ) + return OK; /* Empty queue, obviously ok */ - 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); + for( t = queue->q_next; t; t = t->next ) { + if( t == target ) + return NOTOK; /* bang, your dead */ + + if( testDeadlock( &t->join_queue, target ) == NOTOK ) { + return NOTOK; } } - SEMAPHORE_RESET(plock); - return(ret); + return OK; /* No deadlock */ } diff --git a/lib/libpthread/pthreads/pthread_once.c b/lib/libpthread/pthreads/pthread_once.c index 0510635c66c..b654d221ee9 100644 --- a/lib/libpthread/pthreads/pthread_once.c +++ b/lib/libpthread/pthreads/pthread_once.c @@ -36,7 +36,7 @@ */ #ifndef lint -static const char rcsid[] = "$Id: pthread_once.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: pthread_once.c,v 1.4 1994/02/07 02:19:22 proven Exp $"; +static const char rcsid[] = "$Id: pthread_once.c,v 1.1.1.2 1998/07/21 13:20:18 peter Exp $"; #endif #include <pthread.h> @@ -44,18 +44,16 @@ static const char rcsid[] = "$Id: pthread_once.c,v 1.1.1.1 1995/10/18 08:43:05 d /* ========================================================================== * 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) { + if (once_control->state == PTHREAD_NEEDS_INIT) { + pthread_mutex_lock(&(once_control->mutex)); + if (once_control->state == PTHREAD_NEEDS_INIT) { init_routine(); - (*once_control)++; + once_control->state = PTHREAD_DONE_INIT; } - pthread_mutex_unlock(&__pthread_once_mutex); + pthread_mutex_unlock(&(once_control->mutex)); } return(OK); } diff --git a/lib/libpthread/pthreads/queue.c b/lib/libpthread/pthreads/queue.c index fb3b76f0346..80d7845c4d8 100644 --- a/lib/libpthread/pthreads/queue.c +++ b/lib/libpthread/pthreads/queue.c @@ -36,7 +36,7 @@ */ #ifndef lint -static const char rcsid[] = "$Id: queue.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: queue.c,v 1.16 1994/02/07 02:19:24 proven Exp $"; +static const char rcsid[] = "$Id: queue.c,v 1.1.1.2 1998/07/21 13:20:20 peter Exp $"; #endif #include <pthread.h> @@ -101,10 +101,11 @@ struct pthread *pthread_queue_deq(struct pthread_queue *queue) /* ========================================================================== * pthread_queue_remove() */ -void pthread_queue_remove(struct pthread_queue *queue, struct pthread *thread) +int pthread_queue_remove(struct pthread_queue *queue, struct pthread *thread) { struct pthread **current = &(queue->q_next); struct pthread *prev = NULL; + int ret = NOTOK; while (*current) { if (*current == thread) { @@ -114,10 +115,29 @@ void pthread_queue_remove(struct pthread_queue *queue, struct pthread *thread) queue->q_last = prev; *current = NULL; } + thread->queue = NULL; + thread->next = NULL; + ret = OK; + break; } prev = *current; current = &((*current)->next); } - thread->queue = NULL; - thread->next = NULL; + return(ret); } + +/* ========================================================================== + * pthread_llist_remove() + */ +int pthread_llist_remove(struct pthread **llist, struct pthread *thread) +{ + while (*llist) { + if (*llist == thread) { + *llist = thread->next; + return(OK); + } + llist = &(*llist)->next; + } + return(NOTOK); +} + diff --git a/lib/libpthread/pthreads/signal.c b/lib/libpthread/pthreads/signal.c index fb621b826f0..9f96607b4e7 100644 --- a/lib/libpthread/pthreads/signal.c +++ b/lib/libpthread/pthreads/signal.c @@ -36,11 +36,20 @@ */ #ifndef lint -static const char rcsid[] = "$Id: signal.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: signal.c,v 1.18 1994/02/07 02:19:28 proven Exp $"; +static const char rcsid[] = "$Id: signal.c,v 1.1.1.2 1998/07/21 13:20:22 peter Exp $"; #endif #include <pthread.h> #include <signal.h> +#include <config.h> + +/* This will force init.o to get dragged in; if you've got support for + C++ initialization, that'll cause pthread_init to be called at + program startup automatically, so the application won't need to + call it explicitly. */ + +extern char __pthread_init_hack; +char *__pthread_init_hack_2 = &__pthread_init_hack; /* * Time which select in fd_kern_wait() will sleep. @@ -54,13 +63,16 @@ 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 sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; +volatile sig_atomic_t sig_to_process = 0; + +/* static volatile sigset_t sig_to_process; */ static volatile int sig_count = 0; static void sig_handler(int signal); static void set_thread_timer(); +static void __cleanup_after_resume( void ); void sig_prevent(void); void sig_resume(void); @@ -75,99 +87,101 @@ void sig_resume(void); */ static void context_switch() { - struct pthread **current, *next, *last; - semaphore *lock; - int count; + struct pthread **current, *next, *last, **dead; + + if (pthread_run->state == PS_RUNNING) { + /* Put current thread back on the queue */ + pthread_prio_queue_enq(pthread_current_prio_queue, pthread_run); + } + /* save floating point registers if necessary */ + if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) { + machdep_save_float_state(pthread_run); + } /* 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 */ + /* Poll all 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 */ + if (pthread_run = pthread_prio_queue_deq(pthread_current_prio_queue)) { + /* restore floating point registers if necessary */ + if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) { + machdep_restore_float_state(); + } + uthread_sigmask = &(pthread_run->sigmask); + /* restore state of new current thread */ machdep_restore_state(); - return; - } + 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); + for (next = pthread_link_list; next; next = next->pll) { + if ((next->state != PS_UNALLOCED) && (next->state != PS_DEAD)) { + sigset_t sig_to_block, oset; + + sigfillset(&sig_to_block); + + /* + * Check sig_to_process before calling fd_kern_wait, to handle + * things like zero timeouts to select() which would register + * a signal with the sig_handler_fake() call. + * + * This case should ignore SIGVTALRM + */ + machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); + signum_to_process[SIGVTALRM] = 0; + if (sig_to_process) { + /* Process interrupts */ + /* + * XXX pthread_run should not be set! + * Places where it dumps core should be fixed to + * check for the existance of pthread_run --proven + */ + sig_handler(0); + } else { + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + /* + * Do a wait, timeout is set to a hour unless we get an + * intr. before the select in wich case it polls. + */ + fd_kern_wait(); + machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); + /* Check for interrupts, but ignore SIGVTALR */ + signum_to_process[SIGVTALRM] = 0; + if (sig_to_process) { + /* Process interrupts */ + sig_handler(0); + } + } + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + goto context_switch_reschedule; } - - goto context_switch_reschedule; - } + + /* There are no threads alive. */ + pthread_run = last; exit(0); } +#if !defined(HAVE_SYSCALL_SIGSUSPEND) && defined(HAVE_SYSCALL_SIGPAUSE) + +/* ========================================================================== + * machdep_sys_sigsuspend() + */ +int machdep_sys_sigsuspend(sigset_t * set) +{ + return(machdep_sys_sigpause(* set)); +} + +#endif + /* ========================================================================== * sig_handler_pause() * @@ -175,15 +189,16 @@ context_switch_reschedule:; */ void sig_handler_pause() { - sigset_t sig_to_block, sig_to_pause; + sigset_t sig_to_block, sig_to_pause, oset; sigfillset(&sig_to_block); sigemptyset(&sig_to_pause); - sigprocmask(SIG_BLOCK, &sig_to_block, NULL); + machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); +/* if (!(SIG_ANY(sig_to_process))) { */ if (!sig_to_process) { - sigsuspend(&sig_to_pause); + machdep_sys_sigsuspend(&sig_to_pause); } - sigprocmask(SIG_UNBLOCK, &sig_to_block, NULL); + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); } /* ========================================================================== @@ -198,7 +213,8 @@ void sig_handler_pause() */ void context_switch_done() { - sigdelset(&sig_to_process, SIGVTALRM); + /* sigdelset((sigset_t *)&sig_to_process, SIGVTALRM); */ + signum_to_process[SIGVTALRM] = 0; set_thread_timer(); } @@ -211,13 +227,13 @@ static void set_thread_timer() { static int last_sched_attr = SCHED_RR; - switch (pthread_run->attr.sched_attr) { + switch (pthread_run->attr.schedparam_policy) { 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(); + machdep_unset_thread_timer(NULL); } break; case SCHED_IO: @@ -229,90 +245,158 @@ static void set_thread_timer() machdep_set_thread_timer(&(pthread_run->machdep_data)); break; } - last_sched_attr = pthread_run->attr.sched_attr; + last_sched_attr = pthread_run->attr.schedparam_policy; } /* ========================================================================== - * sig_handler() - * - * Assumes the kernel is locked. + * sigvtalrm() */ -static void sig_handler(int sig) +static inline void sigvtalrm() { + if (sig_count) { + sigset_t sigall, oset; - /* - * 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); + sig_count = 0; + + /* Unblock all signals */ + sigemptyset(&sigall); + machdep_sys_sigprocmask(SIG_SETMASK, &sigall, &oset); + } + context_switch(); + context_switch_done(); +} + +/* ========================================================================== + * sigdefault() + */ +static inline void sigdefault(int sig) +{ + int ret; + + ret = pthread_sig_register(sig); + if (pthread_run && (ret > pthread_run->pthread_priority)) { + sigvtalrm(); + } +} + +/* ========================================================================== + * sig_handler_switch() + */ +static inline void sig_handler_switch(int sig) +{ + int ret; + + switch(sig) { + case 0: break; - case NOTOK: - /* Couldn't get appropriate locks, try again later */ + case SIGVTALRM: + sigvtalrm(); break; - } - } else { - PANIC(); + case SIGALRM: +/* sigdelset((sigset_t *)&sig_to_process, SIGALRM); */ + signum_to_process[SIGALRM] = 0; + switch (ret = sleep_wakeup()) { + default: + if (pthread_run && (ret > pthread_run->pthread_priority)) { + sigvtalrm(); + } + case 0: + break; + case NOTOK: + /* Do the registered action, no threads were sleeping */ + /* There is a timing window that gets + * here when no threads are on the + * sleep queue. This is a quick fix. + * The real problem is possibly related + * to heavy use of condition variables + * with time outs. + * (mevans) + *sigdefault(sig); + */ + break; + } + break; + case SIGCHLD: +/* sigdelset((sigset_t *)&sig_to_process, SIGCHLD); */ + signum_to_process[SIGCHLD] = 0; + switch (ret = wait_wakeup()) { + default: + if (pthread_run && (ret > pthread_run->pthread_priority)) { + sigvtalrm(); + } + case 0: + break; + case NOTOK: + /* Do the registered action, no threads were waiting */ + sigdefault(sig); + break; + } + break; + +#ifdef SIGINFO + case SIGINFO: + pthread_dump_info (); + /* Then fall through, invoking the application's + signal handler after printing our info out. + + I'm not convinced that this is right, but I'm not + 100% convinced that it is wrong, and this is how + Chris wants it done... */ +#endif + + default: + /* Do the registered action */ + if (!sigismember(uthread_sigmask, sig)) { + /* + * If the signal isn't masked by the last running thread and + * the signal behavior is default or ignore then we can + * execute it immediatly. --proven + */ + pthread_sig_default(sig); } + signum_to_process[sig] = 0; + sigdefault(sig); + break; } - - /* - * 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_handler() + * + * Process signal that just came in, plus any pending on the signal mask. + * All of these must be resolved. + * + * Assumes the kernel is locked. + */ +static void sig_handler(int sig) +{ + if (pthread_kernel_lock != 1) { + PANIC(); + } - sig_count = 0; + if (sig) { + sig_handler_switch(sig); + } - /* Unblock all signals */ - sigemptyset(&sigall); - sigprocmask(SIG_SETMASK, &sigall, NULL); + while (sig_to_process) { + for (sig_to_process = 0, sig = 1; sig <= SIGMAX; sig++) { + if (signum_to_process[sig]) { + sig_handler_switch(sig); + } } - 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 */ +/* + if (SIG_ANY(sig_to_process)) { + for (sig = 1; sig <= SIGMAX; sig++) { + if (sigismember((sigset_t *)&sig_to_process, sig)) { goto sig_handler_top; } } } +*/ } /* ========================================================================== @@ -323,15 +407,37 @@ sig_handler_top:; */ void sig_handler_real(int sig) { - if (kernel_lock) { + /* + * Get around systems with BROKEN signal handlers. + * + * Some systems will reissue SIGCHLD if the handler explicitly + * clear the signal pending by either doing a wait() or + * ignoring the signal. + */ +#if defined BROKEN_SIGNALS + if (sig == SIGCHLD) { + sigignore(SIGCHLD); + signal(SIGCHLD, sig_handler_real); + } +#endif + + if (pthread_kernel_lock) { + /* sigaddset((sigset_t *)&sig_to_process, sig); */ __fd_kern_wait_timeout.tv_sec = 0; - sigaddset(&sig_to_process, sig); + signum_to_process[sig] = 1; + sig_to_process = 1; return; } - sig_prevent(); + pthread_kernel_lock++; + sig_count++; sig_handler(sig); - sig_resume(); + + /* Handle any signals the current thread might have just gotten */ + if (pthread_run && pthread_run->sigcount) { + pthread_sig_process(); + } + pthread_kernel_lock--; } /* ========================================================================== @@ -339,73 +445,144 @@ void sig_handler_real(int sig) */ void sig_handler_fake(int sig) { - if (kernel_lock) { - /* Currently this should be impossible */ - PANIC(); + if (pthread_kernel_lock) { + /* sigaddset((sigset_t *)&sig_to_process, sig); */ + signum_to_process[sig] = 1; + sig_to_process = 1; + return; } - sig_prevent(); + pthread_kernel_lock++; sig_handler(sig); - sig_resume(); + while (!(--pthread_kernel_lock)) { + if (sig_to_process) { + /* if (SIG_ANY(sig_to_process)) { */ + pthread_kernel_lock++; + sig_handler(0); + } else { + break; + } + } } /* ========================================================================== - * reschedule() + * __pthread_signal_delete(int sig) * - * 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. + * Assumes the kernel is locked. */ -void reschedule(enum pthread_state state) +void __pthread_signal_delete(int sig) { - 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(); + signum_to_process[sig] = 0; } /* ========================================================================== - * sig_prevent() + * pthread_sched_other_resume() + * + * Check if thread to be resumed is of higher priority and if so + * stop current thread and start new thread. */ -void sig_prevent(void) +pthread_sched_other_resume(struct pthread * pthread) { - kernel_lock++; + pthread->state = PS_RUNNING; + pthread_prio_queue_enq(pthread_current_prio_queue, pthread); + + if (pthread->pthread_priority > pthread_run->pthread_priority) { + if (pthread_kernel_lock == 1) { + sig_handler(SIGVTALRM); + } + } + + __cleanup_after_resume(); } /* ========================================================================== - * sig_resume() + * pthread_resched_resume() + * + * This routine assumes that the caller is the current pthread, pthread_run + * and that it has a lock the kernel thread and it wants to reschedule itself. */ -void sig_resume() +void pthread_resched_resume(enum pthread_state state) { - kernel_lock--; + pthread_run->state = state; + + /* Since we are about to block this thread, lets see if we are + * at a cancel point and if we've been cancelled. + * Avoid cancelling dead or unalloced threads. + */ + if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && + TEST_PTHREAD_IS_CANCELLABLE(pthread_run) && + state != PS_DEAD && state != PS_UNALLOCED ) { + + /* Set this flag to avoid recursively calling pthread_exit */ + /* We have to set this flag here because we will unlock the + * kernel prior to calling pthread_cancel_internal. + */ + SET_PF_RUNNING_TO_CANCEL(pthread_run); + + pthread_run->old_state = state; /* unlock needs this data */ + pthread_sched_resume(); /* Unlock kernel before cancel */ + pthread_cancel_internal( 1 ); /* free locks and exit */ + } + + sig_handler(SIGVTALRM); + + __cleanup_after_resume(); } /* ========================================================================== - * sig_check_and_resume() + * pthread_sched_resume() */ -void sig_check_and_resume() +void pthread_sched_resume() { - /* Some routine name that is yet to be determined. */ - - /* Only bother if we are truely unlocking the kernel */ - while (!(--kernel_lock)) { + __cleanup_after_resume(); +} - /* Assume sigset_t is not a struct or union */ +/*---------------------------------------------------------------------- + * Function: __cleanup_after_resume + * Purpose: cleanup kernel locks after a resume + * Args: void + * Returns: void + * Notes: + *----------------------------------------------------------------------*/ +static void +__cleanup_after_resume( void ) +{ + /* Only bother if we are truely unlocking the kernel */ + while (!(--pthread_kernel_lock)) { + /* if (SIG_ANY(sig_to_process)) { */ if (sig_to_process) { - kernel_lock++; + pthread_kernel_lock++; sig_handler(0); - } else { - break; + continue; + } + if (pthread_run && pthread_run->sigcount) { + pthread_kernel_lock++; + pthread_sig_process(); + continue; } + break; + } + + if( pthread_run == NULL ) + return; /* Must be during init processing */ + + /* Test for cancel that should be handled now */ + + if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && + TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) { + /* Kernel is already unlocked */ + pthread_cancel_internal( 1 ); /* free locks and exit */ } } /* ========================================================================== + * pthread_sched_prevent() + */ +void pthread_sched_prevent(void) +{ + pthread_kernel_lock++; +} + +/* ========================================================================== * sig_init() * * SIGVTALRM (NOT POSIX) needed for thread timeslice timeouts. @@ -414,32 +591,63 @@ void sig_check_and_resume() * SIGALRM (IS POSIX) so some special handling will be * necessary to fake SIGALRM signals */ +#ifndef SIGINFO +#define SIGINFO 0 +#endif void sig_init(void) { - int sig_to_init[] = { SIGVTALRM, SIGALRM, 0 }; + static const int signum_to_initialize[] = + { SIGCHLD, SIGALRM, SIGVTALRM, SIGINFO, 0 }; + static const int signum_to_ignore[] = { SIGKILL, SIGSTOP, 0 }; + int i, j; -#if defined(SA_RESTART) +#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) struct sigaction act; -#endif - - int i; -#if defined(SA_RESTART) act.sa_handler = sig_handler_real; sigemptyset(&(act.sa_mask)); - act.sa_flags = SA_RESTART; + act.sa_flags = 0; #endif - /* Initialize only the necessary signals */ - for (i = 0; sig_to_init[i]; i++) { + /* Initialize the important signals */ + for (i = 0; signum_to_initialize[i]; i++) { -#if defined(SA_RESTART) - if (sigaction(sig_to_init[i], &act, NULL)) { +#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) + if (sigaction(signum_to_initialize[i], &act, NULL)) { #else - if (signal(sig_to_init[i], sig_handler_real)) { + if (signal(signum_to_initialize[i], sig_handler_real)) { #endif PANIC(); } } + + /* Initialize the rest of the signals */ + for (j = 1; j < SIGMAX; j++) { + for (i = 0; signum_to_initialize[i]; i++) { + if (signum_to_initialize[i] == j) { + goto sig_next; + } + } + /* Because Solaris 2.4 can't deal -- proven */ + for (i = 0; signum_to_ignore[i]; i++) { + if (signum_to_ignore[i] == j) { + goto sig_next; + } + } + pthread_signal(j, SIG_DFL); + +#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) + sigaction(j, &act, NULL); +#else + signal(j, sig_handler_real); +#endif + + sig_next:; + } + +#if defined BROKEN_SIGNALS + signal(SIGCHLD, sig_handler_real); +#endif + } diff --git a/lib/libpthread/pthreads/sleep.c b/lib/libpthread/pthreads/sleep.c index 865a8627516..0d18a8756c7 100644 --- a/lib/libpthread/pthreads/sleep.c +++ b/lib/libpthread/pthreads/sleep.c @@ -29,134 +29,265 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Description : Condition cariable functions. + * Description : All the appropriate sleep routines. * * 1.00 93/12/28 proven * -Started coding this file. + * + * 1.36 94/06/04 proven + * -Use new timer structure pthread_timer, that uses seconds + * -nano seconds. Rewrite all routines completely. + * + * 1.38 94/06/13 proven + * -switch pthread_timer to timespec */ #ifndef lint -static const char rcsid[] = "$Id: sleep.c,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ $provenid: sleep.c,v 1.18 1994/02/07 02:19:31 proven Exp $"; +static const char rcsid[] = "$Id: sleep.c,v 1.1.1.2 1998/07/21 13:20:24 peter Exp $"; #endif #include <pthread.h> +#include <sys/time.h> +#include <signal.h> #include <unistd.h> +#include <sys/compat.h> struct pthread * pthread_sleep = NULL; -semaphore sleep_semaphore = SEMAPHORE_CLEAR; - - -#include <sys/time.h> -#include <stdio.h> /* ========================================================================== - * machdep_start_timer() + * sleep_compare_time() */ -int machdep_start_timer(struct itimerval *start_time_val) +/* static inline int sleep_compare_time(struct timespec * time1, + struct timespec * time2) */ +static int sleep_compare_time(struct timespec * time1, struct timespec * time2) { - setitimer(ITIMER_REAL, start_time_val, NULL); - return(OK); + if ((time1->tv_sec < time2->tv_sec) || + ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec < time2->tv_nsec))) { + return(-1); + } + if ((time1->tv_sec == time2->tv_sec) && (time1->tv_nsec == time2->tv_nsec)){ + return(0); + } + return(1); } /* ========================================================================== * machdep_stop_timer() + * + * Returns the time left on the timer. + */ +static struct itimerval timestop = { { 0, 0 }, { 0, 0 } }; + +void machdep_stop_timer(struct timespec *current) +{ + struct itimerval timenow; + + setitimer(ITIMER_REAL, & timestop, & timenow); + __pthread_signal_delete(SIGALRM); + if (current) { + current->tv_nsec = timenow.it_value.tv_usec * 1000; + current->tv_sec = timenow.it_value.tv_sec; + } +} + +/* ========================================================================== + * machdep_start_timer() */ -struct itimerval stop_time_val = { { 0, 0 }, { 0, 0 } }; -int machdep_stop_timer(struct itimerval * current) +int machdep_start_timer(struct timespec *current, struct timespec *wakeup) { - setitimer(ITIMER_REAL, &stop_time_val, current); + struct itimerval timeout; + + timeout.it_value.tv_usec = (wakeup->tv_nsec - current->tv_nsec) / 1000; + timeout.it_value.tv_sec = wakeup->tv_sec - current->tv_sec; + timeout.it_interval.tv_usec = 0; + timeout.it_interval.tv_sec = 0; + if (timeout.it_value.tv_usec < 0) { + timeout.it_value.tv_usec += 1000000; + timeout.it_value.tv_sec--; + } + + if ((!(timeout.it_value.tv_sec < 0)) && + ((timeout.it_value.tv_usec) || (timeout.it_value.tv_sec))) { + if (setitimer(ITIMER_REAL, & timeout, NULL) < 0) + PANIC(); + } else { + /* + * There is no time on the timer. + * This shouldn't happen, + * but isn't fatal. + */ + sig_handler_fake(SIGALRM); + } return(OK); } /* ========================================================================== - * machdep_sub_timer() + * sleep_schedule() * - * formula is: new -= current; + * Assumes that the current thread is the thread to be scheduled + * and that the kthread is already locked. */ -static inline void machdep_sub_timer(struct itimerval * new, - struct itimerval * current) +void sleep_schedule(struct timespec *current_time, struct timespec *new_time) { - 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--; + struct pthread * pthread_sleep_current, * pthread_sleep_prev; + + /* Record the new time as the current thread's wakeup time. */ + pthread_run->wakeup_time = *new_time; + + /* any threads? */ + if (pthread_sleep_current = pthread_sleep) { + if (sleep_compare_time(&(pthread_sleep_current->wakeup_time), + new_time) <= 0) { + /* Don't need to restart timer */ + while (pthread_sleep_current->sll) { + + pthread_sleep_prev = pthread_sleep_current; + pthread_sleep_current = pthread_sleep_current->sll; + + if (sleep_compare_time(&(pthread_sleep_current->wakeup_time), + new_time) > 0) { + pthread_run->sll = pthread_sleep_current; + pthread_sleep_prev->sll = pthread_run; + return; + } + } + + /* 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(current_time, new_time); + pthread_run->sll = pthread_sleep_current; + pthread_sleep = pthread_run; + } + } else { + /* Start timer and enqueue thread */ + machdep_start_timer(current_time, new_time); + pthread_sleep = pthread_run; + pthread_run->sll = NULL; } - new->it_value.tv_sec -= current->it_value.tv_sec; } - /* ========================================================================== - * sleep_basic_wakeup() + * sleep_wakeup() * - * The real work of sleep_wakeup is done here. + * This routine is called by the interrupt handler, which has already + * locked the current kthread. Since all threads on this list are owned + * by the current kthread, rescheduling won't be a problem. */ -static inline int sleep_basic_wakeup() +int sleep_spurious_wakeup = 0; +int sleep_wakeup() { struct pthread *pthread_sleep_next; - struct itimerval current_time; - semaphore *plock; + struct timespec current_time; + int ret = 0; + + if (pthread_sleep == NULL) { + return(NOTOK); + } + + machdep_gettimeofday(¤t_time); + if (sleep_compare_time(&(pthread_sleep->wakeup_time), ¤t_time) > 0) { + machdep_start_timer(¤t_time, &(pthread_sleep->wakeup_time)); + sleep_spurious_wakeup++; + return(OK); + } - machdep_stop_timer(¤t_time); do { - plock = &(pthread_sleep->lock); - if (SEMAPHORE_TEST_AND_SET(plock)) { - return(NOTOK); + if (pthread_sleep->pthread_priority > ret) { + ret = pthread_sleep->pthread_priority; } - /* return remaining time */ - pthread_sleep->time_sec = current_time.it_value.tv_sec; - pthread_sleep->time_usec = current_time.it_value.tv_usec; + /* + * Clean up removed thread and start it running again. + * + * Note: It is VERY important to remove the thread form the + * current queue before putting it on the run queue. + * Both queues use pthread_sleep->next, and the thread that points + * to pthread_sleep should point to pthread_sleep->next then + * pthread_sleep should be put on the run queue. + */ + if ((SET_PF_DONE_EVENT(pthread_sleep)) == OK) { + if (pthread_sleep->queue) + pthread_queue_remove(pthread_sleep->queue, pthread_sleep); + pthread_prio_queue_enq(pthread_current_prio_queue, pthread_sleep); + pthread_sleep->state = PS_RUNNING; + } + + pthread_sleep_next = pthread_sleep->sll; + pthread_sleep->sll = NULL; - 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; + if ((pthread_sleep = pthread_sleep_next) == NULL) { + /* No more threads on sleep queue */ + return(ret); } + } while (sleep_compare_time(&(pthread_sleep->wakeup_time), &(current_time)) <= 0); + + /* Start timer for next time interval */ + machdep_start_timer(¤t_time, &(pthread_sleep->wakeup_time)); + return(ret); +} - /* 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; +/* ========================================================================== + * __sleep() + */ +void __sleep(struct timespec * time_to_sleep) +{ + struct pthread *pthread_sleep_prev; + struct timespec current_time, wakeup_time; - if (current_time.it_value.tv_sec || current_time.it_value.tv_usec) { - machdep_start_timer(¤t_time); - break; - } + pthread_sched_prevent(); - } while(pthread_sleep); - return(OK); + /* Get real time */ + machdep_gettimeofday(¤t_time); + wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec; + wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec; + + sleep_schedule(¤t_time, &wakeup_time); + + /* Reschedule thread */ + SET_PF_WAIT_EVENT(pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_SLEEP_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + /* Return actual time slept */ + time_to_sleep->tv_sec = pthread_run->wakeup_time.tv_sec; + time_to_sleep->tv_nsec = pthread_run->wakeup_time.tv_nsec; } /* ========================================================================== - * 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. + * pthread_nanosleep() */ -int sleep_wakeup() +unsigned int pthread_nanosleep(unsigned int nseconds) { - semaphore *lock, *plock; - int ret; + struct timespec time_to_sleep; - /* Lock sleep queue */ - lock = &(sleep_semaphore); - if (SEMAPHORE_TEST_AND_SET(lock)) { - return(NOTOK); + if (nseconds) { + time_to_sleep.tv_nsec = nseconds; + time_to_sleep.tv_sec = 0; + __sleep(&time_to_sleep); + nseconds = time_to_sleep.tv_nsec; } + return(nseconds); +} - if (pthread_sleep) { - ret = sleep_basic_wakeup(); - } else { - ret = NOTOK; - } +/* ========================================================================== + * usleep() + */ +void usleep(unsigned int useconds) +{ + struct timespec time_to_sleep; - SEMAPHORE_RESET(lock); - return(ret); + if (useconds) { + time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; + time_to_sleep.tv_sec = useconds / 1000000; + __sleep(&time_to_sleep); + } } /* ========================================================================== @@ -164,93 +295,61 @@ int sleep_wakeup() */ unsigned int sleep(unsigned int seconds) { - struct pthread *pthread_sleep_current, *pthread_sleep_prev; - struct itimerval current_time, new_time; - semaphore *lock, *plock; + struct timespec time_to_sleep; if (seconds) { - /* Lock current thread */ - plock = &(pthread_run->lock); - while (SEMAPHORE_TEST_AND_SET(plock)) { - pthread_yield(); - } + time_to_sleep.tv_sec = seconds; + time_to_sleep.tv_nsec = 0; + __sleep(&time_to_sleep); + seconds = time_to_sleep.tv_sec; + } + return(seconds); +} - /* Set new_time timer value */ - new_time.it_value.tv_usec = 0; - new_time.it_value.tv_sec = seconds; - new_time.it_interval.tv_usec = 0; - new_time.it_interval.tv_sec = 0; +/* ========================================================================== + * sleep_cancel() + * + * Cannot be called while kernel is locked. + * Does not wake sleeping thread up, just remove it from the sleep queue. + */ +int sleep_cancel(struct pthread * pthread) +{ + struct timespec current_time, delta_time; + struct pthread * pthread_last; + int rval = NOTOK; - /* Lock sleep queue */ - lock = &(sleep_semaphore); - while (SEMAPHORE_TEST_AND_SET(lock)) { - pthread_yield(); - } + /* Lock sleep queue, Note this may be on a different kthread queue */ + pthread_sched_prevent(); - /* 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); - machdep_sub_timer(¤t_time, &new_time); - pthread_run->sll = pthread_sleep_current; - pthread_sleep = pthread_run; + if (pthread_sleep) { + if (pthread == pthread_sleep) { + rval = OK; + machdep_stop_timer(&delta_time); + if (pthread_sleep = pthread_sleep->sll) { + current_time.tv_sec = delta_time.tv_sec; + current_time.tv_nsec = delta_time.tv_nsec; + current_time.tv_sec += pthread_sleep->wakeup_time.tv_sec; + current_time.tv_nsec += pthread_sleep->wakeup_time.tv_nsec; + while (current_time.tv_nsec > 1000000000) { + current_time.tv_nsec -= 1000000000; + current_time.tv_sec++; + } + machdep_start_timer(&(current_time), + &(pthread_sleep->wakeup_time)); } } else { - /* Start timer and enqueue thread */ - machdep_start_timer(&new_time); - pthread_sleep = pthread_run; - pthread_run->sll = NULL; + for (pthread_last = pthread_sleep; pthread_last; + pthread_last = pthread_last->sll) { + if (pthread_last->sll == pthread) { + pthread_last->sll = pthread->sll; + rval = OK; + break; + } + } } - - 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); -} + pthread_sched_resume(); + pthread->sll = NULL; + return(rval); +} diff --git a/lib/libpthread/stdio/Makefile.inc b/lib/libpthread/stdio/Makefile.inc index 0fefa85c6d8..7275e2d3ed7 100644 --- a/lib/libpthread/stdio/Makefile.inc +++ b/lib/libpthread/stdio/Makefile.inc @@ -1,18 +1,20 @@ + # from: @(#)Makefile.inc 5.7 (Berkeley) 6/27/91 -# $Id: Makefile.inc,v 1.1.1.1 1995/10/18 08:43:05 deraadt Exp $ +# $Id: Makefile.inc,v 1.1.1.2 1998/07/21 13:20:28 peter Exp $ # Thread safe stdio sources -.PATH: ${.CURDIR}/stdio +.PATH: ${srcdir}/stdio + +# SRCS+= tempnam.c tmpfile.c tmpnam.c SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \ fgetline.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \ fprintf.c fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \ fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \ - getc.c getchar.c gets.c getw.c makebuf.c perror.c printf.c putc.c \ + getc.c getchar.c gets.c getw.c makebuf.c perror.c putc.c \ putchar.c puts.c putw.c refill.c remove.c rewind.c rget.c scanf.c \ - setbuf.c setbuffer.c setvbuf.c snprintf.c sprintf.c sscanf.c \ - stdio.c tempnam.c tmpfile.c tmpnam.c ungetc.c vfprintf.c \ - vfscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c vsscanf.c \ + setbuf.c setbuffer.c setvbuf.c sscanf.c \ + stdio.c ungetc.c \ + vfscanf.c vscanf.c vsscanf.c \ wsetup.c putc_unlocked.c putchar_unlocked.c getc_unlocked.c \ - getchar_unlocked.c strerror.c wbuf.c - + getchar_unlocked.c strerror.c wbuf.c xprintf.c diff --git a/lib/libpthread/stdio/README b/lib/libpthread/stdio/README index 017f61f1b46..8e4c07909e9 100644 --- a/lib/libpthread/stdio/README +++ b/lib/libpthread/stdio/README @@ -1,4 +1,8 @@ +Copyright (c) 1993, 1994 Chris Provenzano. All rights reserved. + This is a threadsafe stdio based on the BSD stdio written by Chris Torek. +This product includes software developed by the Univeristy of California, +Berkeley and its contributors. INCLUDE FILES AND PORTING To continue to make this package portable, some basic rules on includes @@ -8,11 +12,11 @@ pthread.h should be included first (if it is to be included). stdio.h should be included. INTERNAL LOCKING -1. All functions that can be called by the user must have __flockfile at the - begining and a __funlockfile at the end. __Flockfile is a counting mutex, - The thread that owns the lock can call __flockfile as many times as - it wants, but must call an equal number of __funlockfile before the - lock will be released. +1. All functions that can be called by the user must have flockfile() at the + begining and a funlockfile() at the end. The routine flockfile() is a + counting mutex, The thread that owns the lock can call flockfile() as + many times as it wants, but must call an equal number of funlockfile() + before the lock will be released. 2. All functions starting with __ shouldn't need addtional locking. 3. Anything that writes the variable __sglue should lock __sfp_mutex, check __sfp_state, and do a condion wait if it is set. @@ -30,11 +34,8 @@ INTERNAL LOCKING tries to lock fp->_file and close it. 9. __sinit is done with a pthread_once routine. -Copyright (c) 1993 Chris Provenzano. All rights reserved. - -This product includes software developed by the Univeristy of California, -Berkeley and its contributors. Things to do. + Fix printf so it uses the ininf function. diff --git a/lib/libpthread/stdio/clrerr.c b/lib/libpthread/stdio/clrerr.c index 1b4e4122c85..ab7047effd5 100644 --- a/lib/libpthread/stdio/clrerr.c +++ b/lib/libpthread/stdio/clrerr.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clrerr.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: clrerr.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: clrerr.c,v 1.1.1.2 1998/07/21 13:20:32 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/fclose.c b/lib/libpthread/stdio/fclose.c index d242643b2cd..b163c9aa363 100644 --- a/lib/libpthread/stdio/fclose.c +++ b/lib/libpthread/stdio/fclose.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fclose.c 5.2 (Berkeley) 2/1/91";*/ -static char *rcsid = "$Id: fclose.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fclose.c,v 1.1.1.2 1998/07/21 13:20:34 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -54,16 +55,17 @@ fclose(fp) if (fp->_flags) { flockfile(fp); r = fp->_flags & __SWR ? __sflush(fp) : 0; - if (__sclose(fp) < 0) - r = EOF; if (fp->_flags & __SMBF) free((char *)fp->_bf._base); if (HASUB(fp)) FREEUB(fp); if (HASLB(fp)) FREELB(fp); + if (__sclose(fp) < 0) + r = EOF; +/* funlockfile(fp); Don't unlock. The close() already has. */ + fp->_file = -1; fp->_flags = 0; /* release this FILE for reuse, DO THIS LAST */ - funlockfile(fp); return(r); } errno = EBADF; diff --git a/lib/libpthread/stdio/fdopen.c b/lib/libpthread/stdio/fdopen.c index 9add139ac91..946db681a45 100644 --- a/lib/libpthread/stdio/fdopen.c +++ b/lib/libpthread/stdio/fdopen.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fdopen.c 5.6 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: fdopen.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fdopen.c,v 1.1.1.2 1998/07/21 13:20:36 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -68,7 +69,7 @@ FILE *fdopen(int fd, const char *mode) return (NULL); } - pthread_once(&__sdidinit, __sinit); + __sinit (); pthread_mutex_lock(&__sfp_mutex); while (__sfp_state) { pthread_cond_wait(&__sfp_cond, &__sfp_mutex); diff --git a/lib/libpthread/stdio/feof.c b/lib/libpthread/stdio/feof.c index e9fa87c3192..f850abc4c32 100644 --- a/lib/libpthread/stdio/feof.c +++ b/lib/libpthread/stdio/feof.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)feof.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: feof.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: feof.c,v 1.1.1.2 1998/07/21 13:20:38 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/ferror.c b/lib/libpthread/stdio/ferror.c index 6079b74ddd5..159210b2d3d 100644 --- a/lib/libpthread/stdio/ferror.c +++ b/lib/libpthread/stdio/ferror.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)ferror.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: ferror.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: ferror.c,v 1.1.1.2 1998/07/21 13:20:40 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/fflush.c b/lib/libpthread/stdio/fflush.c index b774fb3ff82..1d799dad7af 100644 --- a/lib/libpthread/stdio/fflush.c +++ b/lib/libpthread/stdio/fflush.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,11 +37,11 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fflush.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: fflush.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fflush.c,v 1.1.1.2 1998/07/21 13:20:42 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> -#include <sys/errno.h> +#include <errno.h> #include <stdio.h> #include "local.h" @@ -51,7 +52,7 @@ fflush(fp) int retval; if (fp == NULL) - return (__swalk_sflush); + return (__swalk_sflush()); flockfile(fp); if ((fp->_flags & (__SWR | __SRW)) == 0) { diff --git a/lib/libpthread/stdio/fgetc.c b/lib/libpthread/stdio/fgetc.c index 077f862fd36..a1c6da52f09 100644 --- a/lib/libpthread/stdio/fgetc.c +++ b/lib/libpthread/stdio/fgetc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fgetc.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: fgetc.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fgetc.c,v 1.1.1.2 1998/07/21 13:20:44 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -45,7 +46,20 @@ static char *rcsid = "$Id: fgetc.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; fgetc(fp) FILE *fp; { + int ret; + flockfile(fp); - return (__sgetc(fp)); + ret = __sgetc(fp); funlockfile(fp); + return(ret); } + +int __getc(FILE *_p) +{ + int ret; + flockfile(_p); + ret = __sgetc(_p); + funlockfile(_p); + return(ret); +} + diff --git a/lib/libpthread/stdio/fgetline.c b/lib/libpthread/stdio/fgetline.c index 36c087dffa2..6bd5bd1fae0 100644 --- a/lib/libpthread/stdio/fgetline.c +++ b/lib/libpthread/stdio/fgetline.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fgetline.c 5.2 (Berkeley) 5/4/91";*/ -static char *rcsid = "$Id: fgetline.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fgetline.c,v 1.1.1.2 1998/07/21 13:20:46 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -135,7 +136,7 @@ fgetline(fp, lenp) */ if (__slbexpand(fp, len + OPTIMISTIC)) goto error; - (void) bcopy((void *)fp->_p, (void *)(fp->_lb._base + off), + (void) memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, len - off); off = len; if (__srefill(fp)) @@ -149,7 +150,7 @@ fgetline(fp, lenp) len += diff; if (__slbexpand(fp, len)) goto error; - (void) bcopy((void *)fp->_p, (void *)(fp->_lb._base + off), diff); + (void) memcpy((void *)(fp->_lb._base + off), (void *)fp->_p, diff); fp->_r -= diff + 1; fp->_p = p + 1; break; diff --git a/lib/libpthread/stdio/fgetpos.c b/lib/libpthread/stdio/fgetpos.c index 499c24fdf75..7655928b2e6 100644 --- a/lib/libpthread/stdio/fgetpos.c +++ b/lib/libpthread/stdio/fgetpos.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,15 +37,49 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fgetpos.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: fgetpos.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fgetpos.c,v 1.1.1.2 1998/07/21 13:20:48 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <pthread.h> +#include <unistd.h> #include <stdio.h> +#include "local.h" -/* Don't bother locking, ftell does it */ fgetpos(fp, pos) FILE *fp; fpos_t *pos; { - return ((*pos = ftell(fp)) == (fpos_t)-1); + flockfile(fp); + + /* + * Find offset of underlying I/O object, then + * adjust for buffered bytes. + */ + if (fp->_flags & __SOFF) { + *pos = fp->_offset; + } else { + *pos = __sseek(fp, (off_t)0, SEEK_CUR); + } + + if (*pos != (fpos_t)-1) { + if (fp->_flags & __SRD) { + /* + * Reading. Any unread characters (including + * those from ungetc) cause the position to be + * smaller than that in the underlying object. + */ + *pos -= fp->_r; + if (HASUB(fp)) + *pos -= fp->_ur; + } else if (fp->_flags & __SWR && fp->_p != NULL) { + /* + * Writing. Any buffered characters cause the + * position to be greater than that in the + * underlying object. + */ + *pos += fp->_p - fp->_bf._base; + } + } + funlockfile(fp); + return ((*pos) == (fpos_t)-1); } diff --git a/lib/libpthread/stdio/fgets.c b/lib/libpthread/stdio/fgets.c index f8298ae3245..81e6db25db9 100644 --- a/lib/libpthread/stdio/fgets.c +++ b/lib/libpthread/stdio/fgets.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,11 +37,12 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fgets.c 5.4 (Berkeley) 5/4/91";*/ -static char *rcsid = "$Id: fgets.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fgets.c,v 1.1.1.2 1998/07/21 13:20:50 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> /* @@ -92,13 +94,13 @@ fgets(buf, n, fp) len = ++t - p; fp->_r -= len; fp->_p = t; - (void) bcopy((void *)p, (void *)s, len); + (void) memcpy((void *)s, (void *)p, len); s += len; break; } fp->_r -= len; fp->_p += len; - (void) bcopy((void *)p, (void *)s, len); + (void) memcpy((void *)s, (void *)p, len); s += len; } while ((n -= len) != 0); diff --git a/lib/libpthread/stdio/fileno.c b/lib/libpthread/stdio/fileno.c index 29e0de1306f..16eb04bd57b 100644 --- a/lib/libpthread/stdio/fileno.c +++ b/lib/libpthread/stdio/fileno.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fileno.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: fileno.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fileno.c,v 1.1.1.2 1998/07/21 13:20:52 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/findfp.c b/lib/libpthread/stdio/findfp.c index 2367a7bae4d..1a61ca44687 100644 --- a/lib/libpthread/stdio/findfp.c +++ b/lib/libpthread/stdio/findfp.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,14 +37,14 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)findfp.c 5.10 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: findfp.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: findfp.c,v 1.1.1.2 1998/07/21 13:20:53 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> +#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> -#include <posix.h> #include "local.h" #include "glue.h" @@ -64,10 +65,11 @@ FILE __sF[3] = { std(__SWR|__SNBF, 2) /* stderr */ }; struct glue __sglue = { &uglue, 3, __sF }; +FILE *__iob = __sF; +FILE *_iob = __sF; pthread_mutex_t __sfp_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t __sfp_cond = PTHREAD_COND_INITIALIZER; -pthread_once_t __sdidinit = PTHREAD_ONCE_INIT; /* * __sfp_state = 0, when free, > 0 when in _fwalk * This allows multiple readers in _fwalk, but only one writer __sfp, @@ -81,7 +83,7 @@ static struct glue *moreglue(register int n) register FILE *p; static FILE empty; - g = (struct glue *)malloc(sizeof(*g) + n * sizeof(FILE)); + g = (struct glue *)malloc(sizeof(struct glue) + n * sizeof(FILE)); if (g == NULL) return (NULL); p = (FILE *)(g + 1); @@ -137,15 +139,23 @@ __sfp_done:; */ void _cleanup() { - (void) __swalk_sflush; + (void) __swalk_sflush(); } /* * __sinit() is called whenever stdio's internal variables must be set up. + * Do the pthread_once stuff here to keep pthread_once_t out of the + * header files. No reason sprintf.c &c should need to include pthread.h... */ -void __sinit() +static void __s_real_init () { - /* make sure we clean up on exit */ - __cleanup = _cleanup; - __sdidinit = 1; + /* make sure we clean up on exit */ + __cleanup = _cleanup; +} + +static pthread_once_t sdidinit = PTHREAD_ONCE_INIT; + +void __sinit () +{ + pthread_once (&sdidinit, __s_real_init); } diff --git a/lib/libpthread/stdio/flags.c b/lib/libpthread/stdio/flags.c index dfcce47687e..9217f1abf6c 100644 --- a/lib/libpthread/stdio/flags.c +++ b/lib/libpthread/stdio/flags.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,13 +37,15 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)flags.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: flags.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: flags.c,v 1.1.1.2 1998/07/21 13:20:55 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <pthread.h> #include <sys/types.h> -#include <sys/file.h> #include <stdio.h> +#include <fcntl.h> #include <errno.h> +#include <unistd.h> /* * Return the (stdio) flags for a given mode. Store the flags diff --git a/lib/libpthread/stdio/floatio.h b/lib/libpthread/stdio/floatio.h index 13daa9b3a09..606146dc219 100644 --- a/lib/libpthread/stdio/floatio.h +++ b/lib/libpthread/stdio/floatio.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)floatio.h 5.1 (Berkeley) 1/20/91 - * $Id: floatio.h,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $ + * $Id: floatio.h,v 1.1.1.2 1998/07/21 13:20:56 peter Exp $ */ /* diff --git a/lib/libpthread/stdio/fopen.c b/lib/libpthread/stdio/fopen.c index 5e9f7274505..ace901a7e37 100644 --- a/lib/libpthread/stdio/fopen.c +++ b/lib/libpthread/stdio/fopen.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fopen.c 5.5 (Berkeley) 2/5/91";*/ -static char *rcsid = "$Id: fopen.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fopen.c,v 1.1.1.2 1998/07/21 13:20:57 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -63,7 +64,7 @@ FILE *fopen(const char *file, const char *mode) return (NULL); } - pthread_once(&__sdidinit, __sinit); + __sinit (); pthread_mutex_lock(&__sfp_mutex); while (__sfp_state) { pthread_cond_wait(&__sfp_cond, &__sfp_mutex); @@ -82,7 +83,7 @@ FILE *fopen(const char *file, const char *mode) * fseek and ftell.) */ if (oflags & O_APPEND) - (void) __sseek((void *)fp, (fpos_t)0, SEEK_END); + (void) __sseek((void *)fp, (off_t)0, SEEK_END); } pthread_mutex_unlock(&__sfp_mutex); return (fp); diff --git a/lib/libpthread/stdio/fpurge.c b/lib/libpthread/stdio/fpurge.c index 0b77e42156f..fb8901be7a4 100644 --- a/lib/libpthread/stdio/fpurge.c +++ b/lib/libpthread/stdio/fpurge.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fpurge.c 5.2 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: fpurge.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fpurge.c,v 1.1.1.2 1998/07/21 13:21:00 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/fputc.c b/lib/libpthread/stdio/fputc.c index 9807ea95b8c..2f0a68bba59 100644 --- a/lib/libpthread/stdio/fputc.c +++ b/lib/libpthread/stdio/fputc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fputc.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: fputc.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fputc.c,v 1.1.1.2 1998/07/21 13:21:02 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -52,3 +53,21 @@ fputc(c, fp) funlockfile(fp); return(ret); } + +int __putc(int _c, FILE *_p) +{ + int ret; + flockfile(_p); + ret = __sputc(_c, _p); + funlockfile(_p); + return(ret); +} + +int __sputc(int _c, FILE *_p) +{ + if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) + return (*_p->_p++ = _c); + else + return (__swbuf(_c, _p)); +} + diff --git a/lib/libpthread/stdio/fputs.c b/lib/libpthread/stdio/fputs.c index 7833ed12238..c18ae25cb75 100644 --- a/lib/libpthread/stdio/fputs.c +++ b/lib/libpthread/stdio/fputs.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fputs.c 5.6 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: fputs.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fputs.c,v 1.1.1.2 1998/07/21 13:21:03 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/fread.c b/lib/libpthread/stdio/fread.c index f6515ccc048..fa7c3aa3c56 100644 --- a/lib/libpthread/stdio/fread.c +++ b/lib/libpthread/stdio/fread.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fread.c 5.4 (Berkeley) 5/4/91";*/ -static char *rcsid = "$Id: fread.c,v 1.1.1.1 1995/10/18 08:43:06 deraadt Exp $"; +static char *rcsid = "$Id: fread.c,v 1.1.1.2 1998/07/21 13:21:04 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -63,7 +64,7 @@ fread(buf, size, count, fp) total = resid; p = buf; while (resid > (r = fp->_r)) { - (void) bcopy((void *)fp->_p, (void *)p, (size_t)r); + (void) memcpy((void *)p, (void *)fp->_p, (size_t)r); fp->_p += r; /* fp->_r = 0 ... done in __srefill */ p += r; @@ -74,7 +75,7 @@ fread(buf, size, count, fp) goto done_fread; } } - (void) bcopy((void *)fp->_p, (void *)p, resid); + (void) memcpy((void *)p, (void *)fp->_p, resid); fp->_r -= resid; fp->_p += resid; done_fread:; diff --git a/lib/libpthread/stdio/freopen.c b/lib/libpthread/stdio/freopen.c index a7f98535f8b..d743c657c75 100644 --- a/lib/libpthread/stdio/freopen.c +++ b/lib/libpthread/stdio/freopen.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)freopen.c 5.6 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: freopen.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: freopen.c,v 1.1.1.2 1998/07/21 13:21:06 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -71,7 +72,7 @@ freopen(file, mode, fp) return (NULL); } - pthread_once(&__sdidinit, __sinit); + __sinit (); /* * There are actually programs that depend on being able to "freopen" @@ -118,7 +119,8 @@ freopen(file, mode, fp) /* * If reopening something that was open before on a real file, try * to maintain the descriptor. Various C library routines (perror) - * assume stderr is always fd STDERR_FILENO, even if being freopen'd. + * assume stderr is always fd STDERR_FILENO, even if being + * freopen'd. */ /* Testing f == fp->_file may no longer be necessary */ if (fp->_file >= 0 && f != fp->_file) { @@ -130,13 +132,14 @@ freopen(file, mode, fp) fp->_flags = flags; fp->_file = f; ret = fp; - break; } else { /* unlock __sfp_mutex, and try again later */ pthread_mutex_unlock(&__sfp_mutex); pthread_yield(); continue; } + /* @@ Yo, Chris! Between the "break" and "continue" statements + above, the program will never get here. What gives? */ pthread_mutex_unlock(&__sfp_mutex); funlockfile(fp); return(ret); diff --git a/lib/libpthread/stdio/fsetpos.c b/lib/libpthread/stdio/fsetpos.c index 68866bfb345..df04aebed38 100644 --- a/lib/libpthread/stdio/fsetpos.c +++ b/lib/libpthread/stdio/fsetpos.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fsetpos.c 5.2 (Berkeley) 2/5/91";*/ -static char *rcsid = "$Id: fsetpos.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: fsetpos.c,v 1.1.1.2 1998/07/21 13:21:10 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/fvwrite.c b/lib/libpthread/stdio/fvwrite.c index a1a7a9f4a62..4e475d672bf 100644 --- a/lib/libpthread/stdio/fvwrite.c +++ b/lib/libpthread/stdio/fvwrite.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,12 +37,13 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fvwrite.c 5.3 (Berkeley) 5/4/91";*/ -static char *rcsid = "$Id: fvwrite.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: fvwrite.c,v 1.1.1.2 1998/07/21 13:21:14 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> -#include <string.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include "local.h" #include "fvwrite.h" @@ -69,7 +71,7 @@ __sfvwrite(fp, uio) return (EOF); #define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define COPY(n) (void) bcopy((void *)p, (void *)fp->_p, (size_t)(n)); +#define COPY(n) (void) memcpy((void *)fp->_p, (void *)p, (size_t)(n)); iov = uio->uio_iov; p = iov->iov_base; diff --git a/lib/libpthread/stdio/fvwrite.h b/lib/libpthread/stdio/fvwrite.h index 3ee8c474465..33dc4bd72d5 100644 --- a/lib/libpthread/stdio/fvwrite.h +++ b/lib/libpthread/stdio/fvwrite.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)fvwrite.h 5.1 (Berkeley) 1/20/91 - * $Id: fvwrite.h,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $ + * $Id: fvwrite.h,v 1.1.1.2 1998/07/21 13:21:15 peter Exp $ */ /* @@ -51,4 +51,4 @@ struct __suio { int uio_resid; }; -extern int __sfvwrite __P(( FILE *, struct __suio *)); +extern int __sfvwrite __P_(( FILE *, struct __suio *)); diff --git a/lib/libpthread/stdio/fwalk.c b/lib/libpthread/stdio/fwalk.c index 317f817a60f..45372f8d8f2 100644 --- a/lib/libpthread/stdio/fwalk.c +++ b/lib/libpthread/stdio/fwalk.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fwalk.c 5.2 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: fwalk.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: fwalk.c,v 1.1.1.2 1998/07/21 13:21:17 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -91,13 +92,15 @@ int __swalk_sflush() /* Is there anything to flush? */ if (fp->_bf._base && (fp->_bf._base - fp->_p)) { if (ftrylockfile(fp)) { /* Can we flush it */ - if (!saven) { /* No, save first fp we can't flush */ - saven; + if (!saven) { /* No, save first fp we can't flush */ + saven = n; saveg = g; savefp = fp; continue; } + } else { ret |= __sflush(fp); + funlockfile(fp); } } } @@ -109,11 +112,9 @@ int __swalk_sflush() if (fp->_flags != 0) { /* Anything to flush */ while (fp->_bf._base && (fp->_bf._base - fp->_p)) { - if (ftrylockfile(fp)) { /* Can we flush it */ - pthread_yield(); - continue; - } + flockfile(fp); ret |= __sflush(fp); + funlockfile(fp); } } } diff --git a/lib/libpthread/stdio/fwrite.c b/lib/libpthread/stdio/fwrite.c index 69e691599de..4f621d04b86 100644 --- a/lib/libpthread/stdio/fwrite.c +++ b/lib/libpthread/stdio/fwrite.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)fwrite.c 5.5 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: fwrite.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: fwrite.c,v 1.1.1.2 1998/07/21 13:21:18 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -62,6 +63,8 @@ fwrite(buf, size, count, fp) uio.uio_resid = iov.iov_len = n = count * size; uio.uio_iov = &iov; uio.uio_iovcnt = 1; + if (! n) + return(0); flockfile(fp); diff --git a/lib/libpthread/stdio/getc.c b/lib/libpthread/stdio/getc.c index d14d2f19318..bb3a8306e6c 100644 --- a/lib/libpthread/stdio/getc.c +++ b/lib/libpthread/stdio/getc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)getc.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: getc.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: getc.c,v 1.1.1.2 1998/07/21 13:21:19 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/getc_unlocked.c b/lib/libpthread/stdio/getc_unlocked.c index f55100aa98d..a10120b7672 100644 --- a/lib/libpthread/stdio/getc_unlocked.c +++ b/lib/libpthread/stdio/getc_unlocked.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)getc.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: getc_unlocked.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: getc_unlocked.c,v 1.1.1.2 1998/07/21 13:21:21 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/getchar.c b/lib/libpthread/stdio/getchar.c index b75de451c6a..1d5d66530e1 100644 --- a/lib/libpthread/stdio/getchar.c +++ b/lib/libpthread/stdio/getchar.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)getchar.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: getchar.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: getchar.c,v 1.1.1.2 1998/07/21 13:21:22 peter Exp $"; #endif /* LIBC_SCCS and not lint */ /* diff --git a/lib/libpthread/stdio/getchar_unlocked.c b/lib/libpthread/stdio/getchar_unlocked.c index 552ba1c9c46..e66b20f0e9c 100644 --- a/lib/libpthread/stdio/getchar_unlocked.c +++ b/lib/libpthread/stdio/getchar_unlocked.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)getchar.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: getchar_unlocked.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: getchar_unlocked.c,v 1.1.1.2 1998/07/21 13:21:24 peter Exp $"; #endif /* LIBC_SCCS and not lint */ /* diff --git a/lib/libpthread/stdio/gets.c b/lib/libpthread/stdio/gets.c index dc04f6176d4..7130b029c69 100644 --- a/lib/libpthread/stdio/gets.c +++ b/lib/libpthread/stdio/gets.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,9 +37,10 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)gets.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: gets.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: gets.c,v 1.1.1.2 1998/07/21 13:21:25 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <pthread.h> #include <unistd.h> #include <stdio.h> diff --git a/lib/libpthread/stdio/getw.c b/lib/libpthread/stdio/getw.c index 3315135244e..3f9d4962e6a 100644 --- a/lib/libpthread/stdio/getw.c +++ b/lib/libpthread/stdio/getw.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)getw.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: getw.c,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $"; +static char *rcsid = "$Id: getw.c,v 1.1.1.2 1998/07/21 13:21:26 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/glue.h b/lib/libpthread/stdio/glue.h index 32564499028..7f153a4f30d 100644 --- a/lib/libpthread/stdio/glue.h +++ b/lib/libpthread/stdio/glue.h @@ -34,15 +34,16 @@ * SUCH DAMAGE. * * from: @(#)glue.h 5.1 (Berkeley) 1/20/91 - * $Id: glue.h,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $ + * $Id: glue.h,v 1.1.1.2 1998/07/21 13:21:28 peter Exp $ */ /* * The first few FILEs are statically allocated; others are dynamically * allocated and linked in via this glue structure. */ -struct glue { +typedef struct glue { struct glue *next; int niobs; FILE *iobs; -} __sglue; +} __sglue_type; +extern struct glue __sglue; diff --git a/lib/libpthread/stdio/local.h b/lib/libpthread/stdio/local.h index cdcab1c32fe..f8621727e21 100644 --- a/lib/libpthread/stdio/local.h +++ b/lib/libpthread/stdio/local.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)local.h 5.3 (Berkeley) 5/6/93 - * $Id: local.h,v 1.1.1.1 1995/10/18 08:43:07 deraadt Exp $ + * $Id: local.h,v 1.1.1.2 1998/07/21 13:21:29 peter Exp $ */ /* @@ -42,23 +42,25 @@ * in particular, macros and private variables. */ -FILE *__sfp __P((void)); -int __sflush __P((FILE *)); -int __srefill __P((FILE *)); -int __swrite __P((FILE *, const char *, int)); -int __sread __P((FILE *, char *, int)); -fpos_t __sseek __P((FILE *, fpos_t, int)); -int __sclose __P((FILE *)); -void __sinit __P((void)); -void _cleanup __P((void)); -void (*__cleanup) __P((void)); -void __smakebuf __P((FILE *)); -int __swhatbuf __P((FILE *, size_t *, int *)); -int __swalk_sflush __P(()); -int __swsetup __P((FILE *)); -int __sflags __P((const char *, int *)); +#include <sys/types.h> +#include <stddef.h> -extern int __sdidinit; +extern FILE *__sfp __P_((void)); +extern int __sflush __P_((FILE *)); +extern int __srefill __P_((FILE *)); +extern int __swrite __P_((FILE *, const char *, int)); +extern int __sread __P_((FILE *, char *, int)); +extern fpos_t __sseek __P_((FILE *, off_t, int)); +extern int __sclose __P_((FILE *)); +extern void __sinit __P_((void)); +extern void _cleanup __P_((void)); +extern void __smakebuf __P_((FILE *)); +extern int __swhatbuf __P_((FILE *, size_t *, int *)); +extern int __swalk_sflush __P_(()); +extern int __swsetup __P_((FILE *)); +extern int __sflags __P_((const char *, int *)); + +extern void (*__cleanup) __P_((void)); /* * Return true iff the given FILE cannot be written now. diff --git a/lib/libpthread/stdio/makebuf.c b/lib/libpthread/stdio/makebuf.c index df132e23dfe..e748084d130 100644 --- a/lib/libpthread/stdio/makebuf.c +++ b/lib/libpthread/stdio/makebuf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)makebuf.c 5.3 (Berkeley) 5/6/93";*/ -static char *rcsid = "$Id: makebuf.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: makebuf.c,v 1.1.1.2 1998/07/21 13:21:30 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -47,6 +48,8 @@ static char *rcsid = "$Id: makebuf.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $ #include <stdlib.h> #include "local.h" +void (*__cleanup) __P_((void)); + /* * Allocate a file buffer, or switch to unbuffered I/O. * Per the ANSI C standard, ALL tty devices default to line buffered. diff --git a/lib/libpthread/stdio/mktemp.c b/lib/libpthread/stdio/mktemp.c index 616a094bc6a..be193109adc 100644 --- a/lib/libpthread/stdio/mktemp.c +++ b/lib/libpthread/stdio/mktemp.c @@ -33,7 +33,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)mktemp.c 5.10 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: mktemp.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: mktemp.c,v 1.1.1.2 1998/07/21 13:21:32 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <sys/types.h> diff --git a/lib/libpthread/stdio/perror.c b/lib/libpthread/stdio/perror.c index c4cb0154da2..19fe52f5010 100644 --- a/lib/libpthread/stdio/perror.c +++ b/lib/libpthread/stdio/perror.c @@ -1,5 +1,6 @@ /* * Copyright (c) 1988 Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano proven@mit.edu * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,33 +36,32 @@ static char sccsid[] = "@(#)perror.c 5.11 (Berkeley) 2/24/91"; #endif /* LIBC_SCCS and not lint */ -#include <sys/types.h> -#include <sys/uio.h> +#include <pthread.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <string.h> +char *strerror(int); /* For systems that don't prototype it in string.h */ + void perror(s) const char *s; { - register struct iovec *v; - struct iovec iov[4]; + char * e; - v = iov; - if (s && *s) { - v->iov_base = (char *)s; - v->iov_len = strlen(s); - v++; - v->iov_base = ": "; - v->iov_len = 2; - v++; + if (fd_lock(STDERR_FILENO, FD_WRITE, NULL) == OK) { + if (s && *s) { + fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd, + fd_table[STDERR_FILENO]->flags, s, strlen(s), NULL); + fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd, + fd_table[STDERR_FILENO]->flags, ": ", 2, NULL); + } + e = strerror(errno); + fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd, + fd_table[STDERR_FILENO]->flags, e, strlen(e), NULL); + fd_table[STDERR_FILENO]->ops->write(fd_table[STDERR_FILENO]->fd, + fd_table[STDERR_FILENO]->flags, "\n", 1, NULL); + fd_unlock(STDERR_FILENO, FD_WRITE); } - v->iov_base = strerror(errno); - v->iov_len = strlen(v->iov_base); - v++; - v->iov_base = "\n"; - v->iov_len = 1; - (void)writev(STDERR_FILENO, iov, (v - iov) + 1); } diff --git a/lib/libpthread/stdio/printf.c b/lib/libpthread/stdio/printf.c index 741121f1192..b9ca52e3510 100644 --- a/lib/libpthread/stdio/printf.c +++ b/lib/libpthread/stdio/printf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,9 +37,10 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)printf.c 5.6 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: printf.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: printf.c,v 1.1.1.2 1998/07/21 13:21:35 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <stdarg.h> #include <pthread.h> #include <stdio.h> diff --git a/lib/libpthread/stdio/putc.c b/lib/libpthread/stdio/putc.c index 38e1f4df148..e7a1bcaf8c4 100644 --- a/lib/libpthread/stdio/putc.c +++ b/lib/libpthread/stdio/putc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)putc.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: putc.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: putc.c,v 1.1.1.2 1998/07/21 13:21:36 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/putc_unlocked.c b/lib/libpthread/stdio/putc_unlocked.c index a443ffc1d04..b73518af6d4 100644 --- a/lib/libpthread/stdio/putc_unlocked.c +++ b/lib/libpthread/stdio/putc_unlocked.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)putc.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: putc_unlocked.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: putc_unlocked.c,v 1.1.1.2 1998/07/21 13:21:37 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/putchar.c b/lib/libpthread/stdio/putchar.c index 097ded6e840..da2d16dc2bc 100644 --- a/lib/libpthread/stdio/putchar.c +++ b/lib/libpthread/stdio/putchar.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)putchar.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: putchar.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: putchar.c,v 1.1.1.2 1998/07/21 13:21:39 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/putchar_unlocked.c b/lib/libpthread/stdio/putchar_unlocked.c index a0a3b50e690..9fa08418a76 100644 --- a/lib/libpthread/stdio/putchar_unlocked.c +++ b/lib/libpthread/stdio/putchar_unlocked.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)putchar.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: putchar_unlocked.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: putchar_unlocked.c,v 1.1.1.2 1998/07/21 13:21:40 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/puts.c b/lib/libpthread/stdio/puts.c index c1df5f95190..ac4cbc359a9 100644 --- a/lib/libpthread/stdio/puts.c +++ b/lib/libpthread/stdio/puts.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)puts.c 5.6 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: puts.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: puts.c,v 1.1.1.2 1998/07/21 13:21:41 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/putw.c b/lib/libpthread/stdio/putw.c index 949df43036b..775afed1020 100644 --- a/lib/libpthread/stdio/putw.c +++ b/lib/libpthread/stdio/putw.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)putw.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: putw.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: putw.c,v 1.1.1.2 1998/07/21 13:21:43 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> diff --git a/lib/libpthread/stdio/refill.c b/lib/libpthread/stdio/refill.c index b0db1bbc203..8cea23e51d8 100644 --- a/lib/libpthread/stdio/refill.c +++ b/lib/libpthread/stdio/refill.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)refill.c 5.3 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: refill.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: refill.c,v 1.1.1.2 1998/07/21 13:21:44 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -68,17 +69,19 @@ static void __swalk_lflush() savefp = NULL; for (g = &__sglue; g != NULL; g = g->next) { for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) { - if ((fp->_flags & (__SLBF|__SWR)) == __SLBF|__SWR) { + if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) { /* Is there anything to flush? */ if (fp->_bf._base && (fp->_bf._base - fp->_p)) { if (ftrylockfile(fp)) { /* Can we flush it */ if (!saven) { /* No, save first fp we can't flush */ - saven; + saven = n; saveg = g; savefp = fp; continue; } + } else { (void) __sflush(fp); + funlockfile(fp); } } } @@ -87,14 +90,12 @@ static void __swalk_lflush() if (savefp) { for (g = saveg; g != NULL; g = g->next) { for (fp = savefp, n = saven + 1; --n >= 0; fp++) { - if ((fp->_flags & (__SLBF|__SWR)) == __SLBF|__SWR) { + if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) { /* Anything to flush */ while (fp->_bf._base && (fp->_bf._base - fp->_p)) { - if (ftrylockfile(fp)) { /* Can we flush it */ - pthread_yield(); - continue; - } - (void) __sflush(fp); + flockfile(fp); + (void) __sflush(fp); + funlockfile(fp); } } } @@ -118,7 +119,7 @@ __srefill(fp) { /* make sure stdio is set up */ - pthread_once(&__sdidinit, __sinit); + __sinit (); fp->_r = 0; /* largely a convenience for callers */ @@ -157,6 +158,11 @@ __srefill(fp) } } + if (fp->_file == -1) { + fp->_flags |= __SEOF; + return(EOF); + } + if (fp->_bf._base == NULL) __smakebuf(fp); diff --git a/lib/libpthread/stdio/remove.c b/lib/libpthread/stdio/remove.c index 0c41b0dd9b6..c41c4f3b370 100644 --- a/lib/libpthread/stdio/remove.c +++ b/lib/libpthread/stdio/remove.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,9 +37,10 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)remove.c 5.3 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: remove.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: remove.c,v 1.1.1.2 1998/07/21 13:21:45 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <pthread.h> #include <unistd.h> remove(file) diff --git a/lib/libpthread/stdio/rewind.c b/lib/libpthread/stdio/rewind.c index 05f85c3a423..9464f9f7eaf 100644 --- a/lib/libpthread/stdio/rewind.c +++ b/lib/libpthread/stdio/rewind.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)rewind.c 5.6 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: rewind.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: rewind.c,v 1.1.1.2 1998/07/21 13:21:47 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <errno.h> diff --git a/lib/libpthread/stdio/rget.c b/lib/libpthread/stdio/rget.c index 6145e753e28..d84cb7d8c77 100644 --- a/lib/libpthread/stdio/rget.c +++ b/lib/libpthread/stdio/rget.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)rget.c 5.1 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: rget.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: rget.c,v 1.1.1.2 1998/07/21 13:21:48 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/setbuf.c b/lib/libpthread/stdio/setbuf.c index c334dbebd51..4313a8481de 100644 --- a/lib/libpthread/stdio/setbuf.c +++ b/lib/libpthread/stdio/setbuf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)setbuf.c 5.3 (Berkeley) 1/20/91";*/ -static char *rcsid = "$Id: setbuf.c,v 1.1.1.1 1995/10/18 08:43:08 deraadt Exp $"; +static char *rcsid = "$Id: setbuf.c,v 1.1.1.2 1998/07/21 13:21:51 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/setbuffer.c b/lib/libpthread/stdio/setbuffer.c index 58c35ca9642..bd7db6a6ac4 100644 --- a/lib/libpthread/stdio/setbuffer.c +++ b/lib/libpthread/stdio/setbuffer.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)setbuffer.c 5.5 (Berkeley) 3/18/91";*/ -static char *rcsid = "$Id: setbuffer.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: setbuffer.c,v 1.1.1.2 1998/07/21 13:21:52 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> diff --git a/lib/libpthread/stdio/setvbuf.c b/lib/libpthread/stdio/setvbuf.c index 4bf9324419a..b2df334f3b3 100644 --- a/lib/libpthread/stdio/setvbuf.c +++ b/lib/libpthread/stdio/setvbuf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)setvbuf.c 5.5 (Berkeley) 5/6/93";*/ -static char *rcsid = "$Id: setvbuf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: setvbuf.c,v 1.1.1.2 1998/07/21 13:21:54 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -141,7 +142,7 @@ nbf: flags |= __SLBF; if (flags & __SRW) flags &= ~(__SRD | __SWR); - fp->_w = 0; + fp->_w = size; /* Was 0 (mevans) */ fp->_flags = flags; fp->_bf._base = fp->_p = (unsigned char *)buf; fp->_bf._size = size; diff --git a/lib/libpthread/stdio/stdio.c b/lib/libpthread/stdio/stdio.c index f5825298262..c27531b3674 100644 --- a/lib/libpthread/stdio/stdio.c +++ b/lib/libpthread/stdio/stdio.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)stdio.c 5.3 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: stdio.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: stdio.c,v 1.1.1.2 1998/07/21 13:21:59 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -54,8 +55,14 @@ int __sread(FILE *fp, char *buf, int n) register int ret; /* if the read succeeded, update the current offset */ - if ((ret = fd_table[fp->_file]->ops->read(fd_table[fp->_file]->fd, - fd_table[fp->_file]->flags, buf, n)) >= 0) { + if (fd_table[fp->_file]->ops->use_kfds < 2) { + ret = fd_table[fp->_file]->ops->read(fd_table[fp->_file]->fd, + fd_table[fp->_file]->flags, buf, n, NULL); + } else { + pthread_ssize_t (*readfn)() = fd_table[fp->_file]->ops->read; + ret = readfn(fd_table[fp->_file]->fd, buf, n); + } + if (ret >= 0) { fp->_offset += ret; } else { fp->_flags &= ~__SOFF; /* paranoia */ @@ -68,15 +75,20 @@ int __swrite(FILE *fp, const char *buf, int n) if (fp->_flags & __SAPP) (void) lseek(fp->_file, (off_t)0, SEEK_END); fp->_flags &= ~__SOFF; /* in case FAPPEND mode is set */ - return(fd_table[fp->_file]->ops->write(fd_table[fp->_file]->fd, - fd_table[fp->_file]->flags, buf, n)); + if (fd_table[fp->_file]->ops->use_kfds < 2) { + return(fd_table[fp->_file]->ops->write(fd_table[fp->_file]->fd, + fd_table[fp->_file]->flags, buf, n, NULL)); + } else { + pthread_ssize_t (*writefn)() = fd_table[fp->_file]->ops->write; + return(writefn(fd_table[fp->_file]->fd,buf,n)); + } } -fpos_t __sseek(FILE *fp, fpos_t offset, int whence) +fpos_t __sseek(FILE *fp, off_t offset, int whence) { - register off_t ret; + register fpos_t ret; - ret = lseek(fp->_file, (off_t)offset, whence); + ret = (fpos_t)lseek(fp->_file, offset, whence); if (ret == -1L) fp->_flags &= ~__SOFF; else { diff --git a/lib/libpthread/stdio/tmpfile.c b/lib/libpthread/stdio/tmpfile.c index f8a7eefbc76..f76c68fcad7 100644 --- a/lib/libpthread/stdio/tmpfile.c +++ b/lib/libpthread/stdio/tmpfile.c @@ -36,7 +36,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)tmpfile.c 5.4 (Berkeley) 5/27/91";*/ -static char *rcsid = "$Id: tmpfile.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: tmpfile.c,v 1.1.1.2 1998/07/21 13:22:02 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <sys/types.h> @@ -55,8 +55,8 @@ tmpfile() #define TRAILER "tmp.XXXXXX" char buf[sizeof(_PATH_TMP) + sizeof(TRAILER)]; - bcopy(_PATH_TMP, buf, sizeof(_PATH_TMP) - 1); - bcopy(TRAILER, buf + sizeof(_PATH_TMP) - 1, sizeof(TRAILER)); + memcpy(buf, _PATH_TMP, sizeof(_PATH_TMP) - 1); + memcpy( buf + sizeof(_PATH_TMP) - 1, TRAILER, sizeof(TRAILER)); sigfillset(&set); (void)sigprocmask(SIG_BLOCK, &set, &oset); diff --git a/lib/libpthread/stdio/tmpnam.c b/lib/libpthread/stdio/tmpnam.c index 75fa267963f..ca6e6a2efbe 100644 --- a/lib/libpthread/stdio/tmpnam.c +++ b/lib/libpthread/stdio/tmpnam.c @@ -36,7 +36,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)tmpnam.c 5.3 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: tmpnam.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: tmpnam.c,v 1.1.1.2 1998/07/21 13:22:03 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <unistd.h> diff --git a/lib/libpthread/stdio/ungetc.c b/lib/libpthread/stdio/ungetc.c index 3497011767b..0da73f30c15 100644 --- a/lib/libpthread/stdio/ungetc.c +++ b/lib/libpthread/stdio/ungetc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)ungetc.c 5.6 (Berkeley) 5/4/91";*/ -static char *rcsid = "$Id: ungetc.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: ungetc.c,v 1.1.1.2 1998/07/21 13:22:05 peter Exp $"; #endif /* LIBC_SCCS and not lint */ #include <pthread.h> @@ -76,7 +77,7 @@ __submore(fp) p = realloc(fp->_ub._base, i << 1); if (p == NULL) return (EOF); - (void) bcopy((void *)p, (void *)(p + i), (size_t)i); + (void) memcpy((void *)(p + i), (void *)p, (size_t)i); fp->_p = p + i; fp->_ub._base = p; fp->_ub._size = i << 1; @@ -89,7 +90,7 @@ ungetc(c, fp) { if (c == EOF) return (EOF); - pthread_once(&__sdidinit, __sinit); + __sinit (); flockfile(fp); if ((fp->_flags & __SRD) == 0) { diff --git a/lib/libpthread/stdio/vfprintf.c b/lib/libpthread/stdio/vfprintf.c index 23662e945a1..a612a1f9bef 100644 --- a/lib/libpthread/stdio/vfprintf.c +++ b/lib/libpthread/stdio/vfprintf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,7 +37,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/ -static char *rcsid = "$Id: vfprintf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vfprintf.c,v 1.1.1.2 1998/07/21 13:22:06 peter Exp $"; #endif /* LIBC_SCCS and not lint */ /* @@ -49,6 +50,7 @@ static char *rcsid = "$Id: vfprintf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp #include <sys/types.h> #include <stdio.h> +#include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -88,7 +90,7 @@ static int __sbprintf(fp, fmt, ap) FILE *fp; const char *fmt; - va_list ap; + pthread_va_list ap; { unsigned char buf[BUFSIZ]; FILE fake; @@ -121,8 +123,8 @@ __sbprintf(fp, fmt, ap) #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ #define DEFPREC 6 -static char *cvt __P((double, int, int, char *, int *, int, int *)); -static int exponent __P((char *, int, int)); +static char *cvt __P_((double, int, int, char *, int *, int, int *)); +static int exponent __P_((char *, int, int)); #else /* no FLOATING_POINT */ @@ -154,7 +156,7 @@ int vfprintf(fp, fmt0, ap) FILE *fp; const char *fmt0; - va_list ap; + pthread_va_list ap; { register char *fmt; /* format string */ register int ch; /* character from fmt */ @@ -175,7 +177,10 @@ vfprintf(fp, fmt0, ap) char expstr[7]; /* buffer for exponent string */ #endif -#ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */ +#if defined (__alpha) && !defined(_GNUC_) +#define quad_t long +#define u_quad_t unsigned long +#else /* gcc has builtin quad type (long long) SOS */ #define quad_t long long #define u_quad_t unsigned long long #endif @@ -473,7 +478,7 @@ reswitch: switch (ch) { * -- ANSI X3J11 */ /* NOSTRICT */ - _uquad = (u_quad_t)va_arg(ap, void *); + _uquad = (u_quad_t)(size_t)va_arg(ap, void *); base = HEX; xdigs = "0123456789abcdef"; flags |= HEXPREFIX; @@ -695,7 +700,7 @@ error: #ifdef FLOATING_POINT -extern char *__dtoa __P((double, int, int, int *, int *, char **)); +extern char *__dtoa __P_((double, int, int, int *, int *, char **)); static char * cvt(value, ndigits, flags, sign, decpt, ch, length) @@ -724,7 +729,16 @@ cvt(value, ndigits, flags, sign, decpt, ch, length) *sign = '-'; } else *sign = '\000'; +/* #if !defined(__alpha__) && !defined(hpux) */ +#ifndef THIS_IS_NEVER_DEFINED digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); +#else + { char *ecvt(double,int,int*,int*); + + digits = ecvt(value, ndigits, decpt, &dsgn); + rve = (digits + (int)strlen(digits)); + } +#endif if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ bp = digits + ndigits; if (ch == 'f') { diff --git a/lib/libpthread/stdio/vprintf.c b/lib/libpthread/stdio/vprintf.c index d919b19b33d..4462d7ece6c 100644 --- a/lib/libpthread/stdio/vprintf.c +++ b/lib/libpthread/stdio/vprintf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,14 +37,15 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vprintf.c 5.6 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: vprintf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vprintf.c,v 1.1.1.2 1998/07/21 13:22:09 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <stdarg.h> #include <stdio.h> vprintf(fmt, ap) char const *fmt; - va_list ap; + pthread_va_list ap; { return (vfprintf(stdout, fmt, ap)); } diff --git a/lib/libpthread/stdio/vscanf.c b/lib/libpthread/stdio/vscanf.c index 009dce24948..7a0b6f2129d 100644 --- a/lib/libpthread/stdio/vscanf.c +++ b/lib/libpthread/stdio/vscanf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,14 +37,15 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vscanf.c 5.1 (Berkeley) 4/15/91";*/ -static char *rcsid = "$Id: vscanf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vscanf.c,v 1.1.1.2 1998/07/21 13:22:10 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <stdarg.h> #include <stdio.h> vscanf(fmt, ap) const char *fmt; - va_list ap; + pthread_va_list ap; { int r; flockfile(stdin); diff --git a/lib/libpthread/stdio/vsnprintf.c b/lib/libpthread/stdio/vsnprintf.c index 1d16123a3c2..1796ae1ad9c 100644 --- a/lib/libpthread/stdio/vsnprintf.c +++ b/lib/libpthread/stdio/vsnprintf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,22 +37,25 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vsnprintf.c 5.2 (Berkeley) 2/5/91";*/ -static char *rcsid = "$Id: vsnprintf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vsnprintf.c,v 1.1.1.2 1998/07/21 13:22:12 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <stdarg.h> +#include <stddef.h> #include <stdio.h> vsnprintf(str, n, fmt, ap) char *str; size_t n; const char *fmt; - va_list ap; + pthread_va_list ap; { int ret; FILE f; if ((int)n < 1) return (EOF); + f._file = -1; f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n - 1; diff --git a/lib/libpthread/stdio/vsprintf.c b/lib/libpthread/stdio/vsprintf.c index 88a50f90c6a..e66a383d195 100644 --- a/lib/libpthread/stdio/vsprintf.c +++ b/lib/libpthread/stdio/vsprintf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,20 +37,22 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vsprintf.c 5.5 (Berkeley) 2/5/91";*/ -static char *rcsid = "$Id: vsprintf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vsprintf.c,v 1.1.1.2 1998/07/21 13:22:13 peter Exp $"; #endif /* LIBC_SCCS and not lint */ -#include <stdio.h> +#include <stdarg.h> #include <limits.h> +#include <stdio.h> vsprintf(str, fmt, ap) char *str; const char *fmt; - va_list ap; + pthread_va_list ap; { int ret; FILE f; + f._file = -1; f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = INT_MAX; diff --git a/lib/libpthread/stdio/vsscanf.c b/lib/libpthread/stdio/vsscanf.c index 66859145bab..ca3845506cb 100644 --- a/lib/libpthread/stdio/vsscanf.c +++ b/lib/libpthread/stdio/vsscanf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,16 +37,17 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)vsscanf.c 5.1 (Berkeley) 4/15/91";*/ -static char *rcsid = "$Id: vsscanf.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: vsscanf.c,v 1.1.1.2 1998/07/21 13:22:14 peter Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <stdarg.h> #include <stdio.h> #include <string.h> vsscanf(str, fmt, ap) const char *str; const char *fmt; - va_list ap; + pthread_va_list ap; { int ret; FILE f; diff --git a/lib/libpthread/stdio/wbuf.c b/lib/libpthread/stdio/wbuf.c index 63d8f9e3648..58cb9ad058e 100644 --- a/lib/libpthread/stdio/wbuf.c +++ b/lib/libpthread/stdio/wbuf.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by diff --git a/lib/libpthread/stdio/wsetup.c b/lib/libpthread/stdio/wsetup.c index 3ec1e786ecb..71616b1c8c9 100644 --- a/lib/libpthread/stdio/wsetup.c +++ b/lib/libpthread/stdio/wsetup.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1993, 1994 Chris Provenzano. * All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -36,10 +37,9 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)wsetup.c 5.2 (Berkeley) 2/24/91";*/ -static char *rcsid = "$Id: wsetup.c,v 1.1.1.1 1995/10/18 08:43:09 deraadt Exp $"; +static char *rcsid = "$Id: wsetup.c,v 1.1.1.2 1998/07/21 13:22:17 peter Exp $"; #endif /* LIBC_SCCS and not lint */ -#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include "local.h" @@ -53,8 +53,7 @@ __swsetup(fp) register FILE *fp; { /* make sure stdio is set up */ - if (!__sdidinit) - __sinit(); + __sinit (); /* * If we are not writing, we had better be reading and writing. |