diff options
Diffstat (limited to 'lib/libc_r')
77 files changed, 2648 insertions, 397 deletions
diff --git a/lib/libc_r/Makefile b/lib/libc_r/Makefile index f3f5b76049d..c7b3ee47d5b 100644 --- a/lib/libc_r/Makefile +++ b/lib/libc_r/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.1 1998/08/27 09:00:32 d Exp $ +# $OpenBSD: Makefile,v 1.2 1998/11/09 03:12:53 d Exp $ # # All library objects contain sccsid strings by default; they may be # excluded as a space-saving measure. To produce a library that does @@ -15,8 +15,6 @@ .include <bsd.own.mk> -NOPIC= pic seems to be busted at the moment - LIB= c_r LINTFLAGS= -z CFLAGS+= -DPTHREAD_KERNEL -D_POSIX_THREADS -D_THREAD_SAFE @@ -40,7 +38,7 @@ HIDDEN_SYSCALLS= accept.o bind.o close.o connect.o dup.o dup2.o \ recvmsg.o sched_yield.o select.o sendmsg.o sendto.o \ setsockopt.o shutdown.o sigaction.o sigaltstack.o \ signanosleep.o socket.o socketpair.o wait4.o write.o writev.o \ - _exit.o + _exit.o getlogin.o .include "${.CURDIR}/../libc/Makefile.inc" # let manual pages be built/installed from libc diff --git a/lib/libc_r/TODO b/lib/libc_r/TODO index 72921df1f8e..ab6650e1db3 100644 --- a/lib/libc_r/TODO +++ b/lib/libc_r/TODO @@ -1,6 +1,8 @@ This is a list of things that still need to be done: +* Fix the totally bogus _atomic_lock in arch/mips + * Add thread stuff to the other archs in libc/arch/; ie change some usages of ENTRY to SYSENTRY in some .S files and add the new macros to their SYS.h. Only the i386 arch is working. @@ -20,14 +22,6 @@ This is a list of things that still need to be done: fails because of its use of signals. still dumps /tmp/uthread.dump though - needs debugging. -* gethostbyname_r is not standard ... but is important - decide what to - do about this. The POSIX 'system databases' style of extra parameters is - probably the best way to go. - -* Modify gcc (or configure it) so that it understands a -thread option - and uses -lc_r automatically. I think the _PTHREADS flag is wrong, - and need to check the posix draft. - * Test the objective-C compiler to see if it can use threads. * Find all the static buffers in libc and make them per-thread. This @@ -39,8 +33,6 @@ This is a list of things that still need to be done: * Look into how asynchronous I/O can help us. In particular, the (unimplemented) aio*() functions. -* Write manual pages for all the pthread functions. - * Update the libc manual pages to describe the posix re-entrant functions. Although this is actually trivial to do, I have to decide on a consistent way of adding them - maybe `.Sh THREAD-SAFE FUNCTIONS' ? @@ -48,9 +40,4 @@ This is a list of things that still need to be done: May also need to document "This is not thread-safe" for some library functions (yet to be identified). -* Talk to Birrell about what he wants to do with the _np extensions, - since the SUSv2 mentions extra standards to support things like - scheduling policy and so forth. - -$OpenBSD: TODO,v 1.1 1998/08/27 09:00:32 d Exp $ - +$OpenBSD: TODO,v 1.2 1998/11/09 03:12:54 d Exp $ diff --git a/lib/libc_r/arch/i386/uthread_machdep.h b/lib/libc_r/arch/i386/uthread_machdep.h index 2a296d3ae25..088ff200509 100644 --- a/lib/libc_r/arch/i386/uthread_machdep.h +++ b/lib/libc_r/arch/i386/uthread_machdep.h @@ -1,7 +1,7 @@ /* * OpenBSD/i386 machine-dependent thread macros * - * $OpenBSD: uthread_machdep.h,v 1.1 1998/08/28 01:54:58 d Exp $ + * $OpenBSD: uthread_machdep.h,v 1.2 1998/11/09 03:13:13 d Exp $ */ /* save the floating point state of a thread */ @@ -29,6 +29,9 @@ - sizeof(double); \ } +#define _thread_machdep_longjmp(a,v) longjmp(a,v) +#define _thread_machdep_setjmp(a) setjmp(a) + struct _machdep_struct { char saved_fp[108]; }; diff --git a/lib/libc_r/arch/mips/_atomic_lock.S b/lib/libc_r/arch/mips/_atomic_lock.S new file mode 100644 index 00000000000..169852b9c75 --- /dev/null +++ b/lib/libc_r/arch/mips/_atomic_lock.S @@ -0,0 +1,35 @@ +/* + * $OpenBSD: _atomic_lock.S,v 1.1 1998/11/09 03:13:14 d Exp $ + */ + +#include "SYS.h" + +/* + * Atomicly lock a location with an identifier provided the location + * is not currently locked. + * + * long _atomic_lock(long *a0); + * v0 will contain the return value (zero if lock obtained). + */ + +/* + * XXXXXX THIS IS LOCK FUNCTION IS TOTALLY BOGUS XXXXXXXXX + * pefo@ says that for R4000 processors, there is a way to do this + * atomically, but for R3000 you will need to context switch. + * Specifically he says the 'll' and 'sc' instructions can be used for mips2. + */ +LEAF(_atomic_lock) + .set noreorder + .set nomacro + + /* Get the existing lock value and lock memory: */ + ori t0,zero,1 + lw v0,0(a0) + sw t0,0(a0) + j ra + nop + + .set macro + .set reorder +END(_atomic_lock) + diff --git a/lib/libc_r/arch/mips/uthread_machdep.h b/lib/libc_r/arch/mips/uthread_machdep.h new file mode 100644 index 00000000000..605b900f8a7 --- /dev/null +++ b/lib/libc_r/arch/mips/uthread_machdep.h @@ -0,0 +1,36 @@ +/* + * OpenBSD/mips machine-dependent thread macros + * + * $OpenBSD: uthread_machdep.h,v 1.1 1998/11/09 03:13:14 d Exp $ + */ + +#include <machine/regnum.h> +#include <machine/signal.h> + +/* floating point state is saved by setjmp/longjmp */ + +#define _thread_machdep_save_float_state(thr) /* no need */ +#define _thread_machdep_restore_float_state(thr) /* no need */ + +/* initialise the jmpbuf stack frame so it continues from entry */ +#define _thread_machdep_thread_create(thr, entry, pattr) \ + { \ + struct sigcontext *j = &(thr)->saved_jmp_buf; \ + \ + /* initialise to sane values */ \ + _thread_machdep_setjmp(j); \ + /* entry */ \ + j->sc_regs[RA] = j->sc_pc; /* for gdb */ \ + j->sc_pc = (int)entry; \ + /* stack */ \ + j->sc_regs[SP] = (int) (thr)->stack \ + + (pattr)->stacksize_attr \ + - sizeof(double); \ + } + +#define _thread_machdep_longjmp(a,v) longjmp(a,v) +#define _thread_machdep_setjmp(a) setjmp(a) + +struct _machdep_struct { + /* nothing needed */ +}; diff --git a/lib/libc_r/include/pthread.h b/lib/libc_r/include/pthread.h index aabf39fb335..4c8d0f2a173 100644 --- a/lib/libc_r/include/pthread.h +++ b/lib/libc_r/include/pthread.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: pthread.h,v 1.1 1998/09/05 07:40:47 d Exp $ + * $OpenBSD: pthread.h,v 1.2 1998/11/09 03:13:14 d Exp $ * */ #ifndef _PTHREAD_H_ @@ -85,6 +85,12 @@ #define PTHREAD_EXPLICIT_SCHED 0 /* + * Flags for read/write lock attributes + */ +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + +/* * Forward structure definitions. * * These are mostly opaque to the user. @@ -96,6 +102,8 @@ struct pthread_cond_attr; struct pthread_mutex; struct pthread_mutex_attr; struct pthread_once; +struct pthread_rwlock; +struct pthread_rwlockattr; struct sched_param; /* @@ -113,6 +121,8 @@ typedef struct pthread_cond *pthread_cond_t; typedef struct pthread_cond_attr *pthread_condattr_t; typedef int pthread_key_t; typedef struct pthread_once pthread_once_t; +typedef struct pthread_rwlock *pthread_rwlock_t; +typedef struct pthread_rwlockattr *pthread_rwlockattr_t; /* * Additional type definitions: @@ -147,6 +157,7 @@ struct pthread_once { */ #define PTHREAD_MUTEX_INITIALIZER NULL #define PTHREAD_COND_INITIALIZER NULL +#define PTHREAD_RWLOCK_INITIALIZER NULL /* * Default attribute arguments (draft 4, deprecated). @@ -237,6 +248,20 @@ int pthread_mutex_trylock __P((pthread_mutex_t *)); int pthread_mutex_unlock __P((pthread_mutex_t *)); int pthread_once __P((pthread_once_t *, void (*init_routine) (void))); +int pthread_rwlock_destroy __P((pthread_rwlock_t *)); +int pthread_rwlock_init __P((pthread_rwlock_t *, + const pthread_rwlockattr_t *)); +int pthread_rwlock_rdlock __P((pthread_rwlock_t *)); +int pthread_rwlock_tryrdlock __P((pthread_rwlock_t *)); +int pthread_rwlock_trywrlock __P((pthread_rwlock_t *)); +int pthread_rwlock_unlock __P((pthread_rwlock_t *)); +int pthread_rwlock_wrlock __P((pthread_rwlock_t *)); +int pthread_rwlockattr_init __P((pthread_rwlockattr_t *)); +int pthread_rwlockattr_getpshared __P((const pthread_rwlockattr_t *, + int *)); +int pthread_rwlockattr_setpshared __P((pthread_rwlockattr_t *, + int *)); +int pthread_rwlockattr_destroy __P((pthread_rwlockattr_t *)); pthread_t pthread_self __P((void)); int pthread_setcancelstate __P((int, int *)); int pthread_setcanceltype __P((int, int *)); @@ -277,10 +302,6 @@ int pthread_attr_setcleanup __P((pthread_attr_t *, #define PTHREAD_PRIO_PROTECT #define PTHREAD_PROCESS_SHARED #define PTHREAD_PROCESS_PRIVATE -#define PTHREAD_RWLOCK_INITIALIZER - -typedef void *pthread_rwlock_t; -typedef void *pthread_rwlockattr_t; int pthread_attr_getguardsize __P((const pthread_attr_t *, size_t *)); @@ -291,20 +312,6 @@ int pthread_mutexattr_gettype __P((const pthread_mutexattr_t *, int *)); int pthread_mutexattr_settype __P((const pthread_mutexattr_t *, int)); -int pthread_rwlock_destroy __P((pthread_rwlock_t *)); -int pthread_rwlock_init __P((pthread_rwlock_t *, - const pthread_rwlockattr_t *)); -int pthread_rwlock_rdlock __P((pthread_rwlock_t *)); -int pthread_rwlock_tryrdlock __P((pthread_rwlock_t *)); -int pthread_rwlock_trywrlock __P((pthread_rwlock_t *)); -int pthread_rwlock_unlock __P((pthread_rwlock_t *)); -int pthread_rwlock_wrlock __P((pthread_rwlock_t *)); -int pthread_rwlockattr_destroy __P((pthread_rwlockattr_t *)); -int pthread_rwlockattr_getpshared __P((const pthread_rwlockattr_t *, - int *)); -int pthread_rwlockattr_init __P((pthread_rwlockattr_t *)); -int pthread_rwlockattr_setpshared __P((pthread_rwlockattr_t *, - int)); int pthread_setconcurrency __P((int)); #endif /* susv2 */ diff --git a/lib/libc_r/man/Makefile.inc b/lib/libc_r/man/Makefile.inc index 2cae3f76800..8fbdb1c9ccc 100644 --- a/lib/libc_r/man/Makefile.inc +++ b/lib/libc_r/man/Makefile.inc @@ -1,5 +1,5 @@ -# $Id: Makefile.inc,v 1.1 1998/08/27 09:00:33 d Exp $ -# $OpenBSD: Makefile.inc,v 1.1 1998/08/27 09:00:33 d Exp $ +# $Id: Makefile.inc,v 1.2 1998/11/09 03:13:14 d Exp $ +# $OpenBSD: Makefile.inc,v 1.2 1998/11/09 03:13:14 d Exp $ # POSIX thread man files @@ -27,6 +27,15 @@ MAN+= pthread_cleanup_pop.3 \ pthread_mutex_trylock.3 \ pthread_mutex_unlock.3 \ pthread_once.3 \ + pthread_rwlock_destroy.3 \ + pthread_rwlock_init.3 \ + pthread_rwlock_rdlock.3 \ + pthread_rwlock_unlock.3 \ + pthread_rwlock_wrlock.3 \ + pthread_rwlockattr_destroy.3 \ + pthread_rwlockattr_getpshared.3 \ + pthread_rwlockattr_init.3 \ + pthread_rwlockattr_setpshared.3 \ pthread_self.3 \ pthread_setspecific.3 diff --git a/lib/libc_r/man/pread.3 b/lib/libc_r/man/pread.3 new file mode 100644 index 00000000000..c21f88ae4c2 --- /dev/null +++ b/lib/libc_r/man/pread.3 @@ -0,0 +1,36 @@ +.\" $OpenBSD: pread.3,v 1.1 1998/11/09 03:13:14 d Exp $ +.Dd September 7, 1998 +.Os Ox +.Dt PREAD 3 +.Sh NAME +.Nm pread +.Nd atomic seek and read +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft ssize_t +.Fn pread "int filedes" "void *buf" "size_t nbytes" "off_t offset" +.Sh DESCRIPTION +The +.Fn pread +function reads +.Fa nbyte +bytes from offset +.Fa offset +in the file opened on file descriptor +.Fa filedes. +.Pp +This function is provided for use in a threaded, parallel I/O +environment, where race conditions may exist between two threads +non-atomically seeking and reading from the same file descriptor. +.Sh RETURN VALUES +The +.Fn pread +function returns values identical to +.Xr read 3 . +.Sh SEE ALSO +.Xr pthreads 3 , +.Xr read 3 , +.Xr pwrite 3 +.Sh STANDARDS +.Fn pread +conforms to TOG SUSv2 . diff --git a/lib/libc_r/man/pthread_cleanup_pop.3 b/lib/libc_r/man/pthread_cleanup_pop.3 index a244f9441e1..eefe4f335ae 100644 --- a/lib/libc_r/man/pthread_cleanup_pop.3 +++ b/lib/libc_r/man/pthread_cleanup_pop.3 @@ -51,7 +51,6 @@ does not return any value. .Sh ERRORS None .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_cleanup_push 3 , .Xr pthread_exit 3 .Sh STANDARDS diff --git a/lib/libc_r/man/pthread_cleanup_push.3 b/lib/libc_r/man/pthread_cleanup_push.3 index 4a4b876ee4f..9bb3f400b64 100644 --- a/lib/libc_r/man/pthread_cleanup_push.3 +++ b/lib/libc_r/man/pthread_cleanup_push.3 @@ -54,7 +54,6 @@ does not return any value. .Sh ERRORS None .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_cleanup_pop 3 , .Xr pthread_exit 3 .Sh STANDARDS diff --git a/lib/libc_r/man/pthread_cond_broadcast.3 b/lib/libc_r/man/pthread_cond_broadcast.3 index 25f00950db0..3b39287046d 100644 --- a/lib/libc_r/man/pthread_cond_broadcast.3 +++ b/lib/libc_r/man/pthread_cond_broadcast.3 @@ -56,12 +56,11 @@ is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_cond_init 3 , .Xr pthread_cond_destroy 3 , -.Xr pthread_cond_wait 3 , +.Xr pthread_cond_init 3 , +.Xr pthread_cond_signal 3 , .Xr pthread_cond_timedwait 3 , -.Xr pthread_cond_signal 3 +.Xr pthread_cond_wait 3 .Sh STANDARDS .Fn pthread_cond_broadcast conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_cond_destroy.3 b/lib/libc_r/man/pthread_cond_destroy.3 index 94f2b4210f5..22921b49a5e 100644 --- a/lib/libc_r/man/pthread_cond_destroy.3 +++ b/lib/libc_r/man/pthread_cond_destroy.3 @@ -60,12 +60,11 @@ is locked by another thread. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , +.Xr pthread_cond_broadcast 3 , .Xr pthread_cond_init 3 , -.Xr pthread_cond_wait 3 , -.Xr pthread_cond_timedwait 3 , .Xr pthread_cond_signal 3 , -.Xr pthread_cond_broadcast 3 +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 .Sh STANDARDS .Fn pthread_cond_destroy conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_cond_init.3 b/lib/libc_r/man/pthread_cond_init.3 index f8c16f49b21..00f669d51be 100644 --- a/lib/libc_r/man/pthread_cond_init.3 +++ b/lib/libc_r/man/pthread_cond_init.3 @@ -65,12 +65,11 @@ The temporarily lacks the resources to create another condition variable. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , +.Xr pthread_cond_broadcast 3 , .Xr pthread_cond_destroy 3 , -.Xr pthread_cond_wait 3 , -.Xr pthread_cond_timedwait 3 , .Xr pthread_cond_signal 3 , -.Xr pthread_cond_broadcast 3 +.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_wait 3 .Sh STANDARDS .Fn pthread_cond_init conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_cond_signal.3 b/lib/libc_r/man/pthread_cond_signal.3 index ebfd6561f4c..679e46fb2ed 100644 --- a/lib/libc_r/man/pthread_cond_signal.3 +++ b/lib/libc_r/man/pthread_cond_signal.3 @@ -56,12 +56,11 @@ is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_cond_init 3 , +.Xr pthread_cond_broadcast 3 , .Xr pthread_cond_destroy 3 , -.Xr pthread_cond_wait 3 , +.Xr pthread_cond_init 3 , .Xr pthread_cond_timedwait 3 , -.Xr pthread_cond_broadcast 3 +.Xr pthread_cond_wait 3 .Sh STANDARDS .Fn pthread_cond_signal conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_cond_timedwait.3 b/lib/libc_r/man/pthread_cond_timedwait.3 index 111a3fb117a..ab0184a7c58 100644 --- a/lib/libc_r/man/pthread_cond_timedwait.3 +++ b/lib/libc_r/man/pthread_cond_timedwait.3 @@ -73,12 +73,11 @@ The system time has reached or exceeded the time specified in .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_cond_init 3 , +.Xr pthread_cond_broadcast 3 , .Xr pthread_cond_destroy 3 , -.Xr pthread_cond_wait 3 , +.Xr pthread_cond_init 3 , .Xr pthread_cond_signal 3 , -.Xr pthread_cond_broadcast 3 +.Xr pthread_cond_wait 3 .Sh STANDARDS .Fn pthread_cond_timedwait conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_cond_wait.3 b/lib/libc_r/man/pthread_cond_wait.3 index 69d9257cadf..7f70b591f03 100644 --- a/lib/libc_r/man/pthread_cond_wait.3 +++ b/lib/libc_r/man/pthread_cond_wait.3 @@ -67,12 +67,11 @@ is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_cond_init 3 , +.Xr pthread_cond_broadcast 3 , .Xr pthread_cond_destroy 3 , -.Xr pthread_cond_timedwait 3 , +.Xr pthread_cond_init 3 , .Xr pthread_cond_signal 3 , -.Xr pthread_cond_broadcast 3 +.Xr pthread_cond_timedwait 3 .Sh STANDARDS .Fn pthread_cond_wait conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_create.3 b/lib/libc_r/man/pthread_create.3 index 7f94ffa0183..6966b56398a 100644 --- a/lib/libc_r/man/pthread_create.3 +++ b/lib/libc_r/man/pthread_create.3 @@ -100,11 +100,10 @@ is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr fork 2 , -.Xr pthread_exit 3 , -.Xr pthread_cleanup_push 3 , .Xr pthread_cleanup_pop 3 , +.Xr pthread_cleanup_push 3 , +.Xr pthread_exit 3 , .Xr pthread_join 3 .Sh STANDARDS .Fn pthread_create diff --git a/lib/libc_r/man/pthread_detach.3 b/lib/libc_r/man/pthread_detach.3 index a917d632e24..a7f0490ae0d 100644 --- a/lib/libc_r/man/pthread_detach.3 +++ b/lib/libc_r/man/pthread_detach.3 @@ -73,7 +73,6 @@ thread ID, .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_join 3 .Sh STANDARDS .Fn pthread_detach diff --git a/lib/libc_r/man/pthread_equal.3 b/lib/libc_r/man/pthread_equal.3 index 976d2881602..74a588279b9 100644 --- a/lib/libc_r/man/pthread_equal.3 +++ b/lib/libc_r/man/pthread_equal.3 @@ -57,7 +57,6 @@ correspond to the same thread, otherwise it will return zero. None. .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_create 3 , .Xr pthread_exit 3 .Sh STANDARDS diff --git a/lib/libc_r/man/pthread_exit.3 b/lib/libc_r/man/pthread_exit.3 index b2fa8f2119b..0e0f1765ee8 100644 --- a/lib/libc_r/man/pthread_exit.3 +++ b/lib/libc_r/man/pthread_exit.3 @@ -88,7 +88,6 @@ function cannot return to its caller. None. .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr _exit 2 , .Xr exit 2 , .Xr pthread_create 3 , diff --git a/lib/libc_r/man/pthread_getspecific.3 b/lib/libc_r/man/pthread_getspecific.3 index 73490ae1d5b..acffbfaac2e 100644 --- a/lib/libc_r/man/pthread_getspecific.3 +++ b/lib/libc_r/man/pthread_getspecific.3 @@ -28,8 +28,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: pthread_getspecific.3,v 1.1 1998/08/27 09:00:42 d Exp $ -.\" $OpenBSD: pthread_getspecific.3,v 1.1 1998/08/27 09:00:42 d Exp $ +.\" $FreeBSD: pthread_getspecific.3,v 1.5 1998/08/03 00:58:36 alex Exp $ +.\" $OpenBSD: pthread_getspecific.3,v 1.2 1998/11/09 03:13:15 d Exp $ .\" .Dd April 4, 1996 .Dt PTHREAD_GETSPECIFIC 3 @@ -73,7 +73,6 @@ then the value NULL is returned. .Sh ERRORS None. .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_key_create 3 , .Xr pthread_key_delete 3 , .Xr pthread_setspecific 3 diff --git a/lib/libc_r/man/pthread_join.3 b/lib/libc_r/man/pthread_join.3 index a89878c33f2..d7a28a13053 100644 --- a/lib/libc_r/man/pthread_join.3 +++ b/lib/libc_r/man/pthread_join.3 @@ -91,7 +91,6 @@ specifies the calling thread. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr wait 2 , .Xr pthread_create 3 .Sh STANDARDS diff --git a/lib/libc_r/man/pthread_key_create.3 b/lib/libc_r/man/pthread_key_create.3 index 2d29d10128b..c7c15fd0cef 100644 --- a/lib/libc_r/man/pthread_key_create.3 +++ b/lib/libc_r/man/pthread_key_create.3 @@ -88,7 +88,6 @@ Insufficient memory exists to create the key. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_getspecific 3 , .Xr pthread_key_delete 3 , .Xr pthread_setspecific 3 diff --git a/lib/libc_r/man/pthread_key_delete.3 b/lib/libc_r/man/pthread_key_delete.3 index 6ef3aef9b0b..cf1ad12ae99 100644 --- a/lib/libc_r/man/pthread_key_delete.3 +++ b/lib/libc_r/man/pthread_key_delete.3 @@ -82,7 +82,6 @@ value is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_getspecific 3 , .Xr pthread_key_create 3 , .Xr pthread_setspecific 3 diff --git a/lib/libc_r/man/pthread_mutex_destroy.3 b/lib/libc_r/man/pthread_mutex_destroy.3 index aa9837c4732..e9fb9c11d04 100644 --- a/lib/libc_r/man/pthread_mutex_destroy.3 +++ b/lib/libc_r/man/pthread_mutex_destroy.3 @@ -59,11 +59,10 @@ is locked by another thread. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_mutex_init 3 , .Xr pthread_mutex_lock 3 , -.Xr pthread_mutex_unlock 3 , -.Xr pthread_mutex_trylock 3 +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 .Sh STANDARDS .Fn pthread_mutex_destroy conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_mutex_init.3 b/lib/libc_r/man/pthread_mutex_init.3 index 9966e16f6be..d5292ff8e10 100644 --- a/lib/libc_r/man/pthread_mutex_init.3 +++ b/lib/libc_r/man/pthread_mutex_init.3 @@ -64,11 +64,10 @@ The temporarily lacks the resources to create another mutex. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_mutex_destroy 3 , .Xr pthread_mutex_lock 3 , -.Xr pthread_mutex_unlock 3 , -.Xr pthread_mutex_trylock 3 +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 .Sh STANDARDS .Fn pthread_mutex_init conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_mutex_lock.3 b/lib/libc_r/man/pthread_mutex_lock.3 index d8cbe96314a..a0aa07d76d6 100644 --- a/lib/libc_r/man/pthread_mutex_lock.3 +++ b/lib/libc_r/man/pthread_mutex_lock.3 @@ -61,11 +61,10 @@ A deadlock would occur if the thread blocked waiting for .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_mutex_unlock 3 , -.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_destroy 3 , .Xr pthread_mutex_init 3 , -.Xr pthread_mutex_destroy 3 +.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_unlock 3 .Sh STANDARDS .Fn pthread_mutex_lock conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_mutex_trylock.3 b/lib/libc_r/man/pthread_mutex_trylock.3 index 81d2a4dc7e5..9f283801e54 100644 --- a/lib/libc_r/man/pthread_mutex_trylock.3 +++ b/lib/libc_r/man/pthread_mutex_trylock.3 @@ -62,11 +62,10 @@ is already locked. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_mutex_lock 3 , -.Xr pthread_mutex_unlock 3 , +.Xr pthread_mutex_destroy 3 , .Xr pthread_mutex_init 3 , -.Xr pthread_mutex_destroy 3 +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_unlock 3 .Sh STANDARDS .Fn pthread_mutex_trylock conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_mutex_unlock.3 b/lib/libc_r/man/pthread_mutex_unlock.3 index 04fb06832d4..95ba7e68511 100644 --- a/lib/libc_r/man/pthread_mutex_unlock.3 +++ b/lib/libc_r/man/pthread_mutex_unlock.3 @@ -61,11 +61,10 @@ The current thread does not hold a lock on .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , -.Xr pthread_mutex_lock 3 , -.Xr pthread_mutex_trylock 3 , +.Xr pthread_mutex_destroy 3 , .Xr pthread_mutex_init 3 , -.Xr pthread_mutex_destroy 3 +.Xr pthread_mutex_lock 3 , +.Xr pthread_mutex_trylock 3 .Sh STANDARDS .Fn pthread_mutex_unlock conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_once.3 b/lib/libc_r/man/pthread_once.3 index c5d0235b41f..fc50d56bf25 100644 --- a/lib/libc_r/man/pthread_once.3 +++ b/lib/libc_r/man/pthread_once.3 @@ -93,8 +93,6 @@ indicate the error. .Sh ERRORS None. .Pp -.Sh SEE ALSO -.Xr pthreads 3 .Sh STANDARDS .Fn pthread_once conforms to ISO/IEC 9945-1 ANSI/IEEE diff --git a/lib/libc_r/man/pthread_rwlock_destroy.3 b/lib/libc_r/man/pthread_rwlock_destroy.3 new file mode 100644 index 00000000000..4e1538a0e5e --- /dev/null +++ b/lib/libc_r/man/pthread_rwlock_destroy.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlock_destroy.3,v 1.1 1998/11/09 03:13:15 d Exp $ +.\" $OpenBSD: pthread_rwlock_destroy.3,v 1.1 1998/11/09 03:13:15 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_DESTROY 3 +.Os +.Sh NAME +.Nm pthread_rwlock_destroy +.Nd destroy a read/write lock +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_destroy "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_destroy +function is used to destroy a read/write lock previously created with +.Fn pthread_rwlock_init . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_destroy +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Sh STANDARDS +The +.Fn pthread_rwlock_destroy +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_destroy +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The caller does not have the privilege to perform the operation. +.El +.Pp +The +.Fn pthread_rwlock_destroy +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The system has detected an attempt to destroy the object referenced by +.Fa lock +while it is locked. +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_destroy +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlock_init.3 b/lib/libc_r/man/pthread_rwlock_init.3 new file mode 100644 index 00000000000..6011fe09463 --- /dev/null +++ b/lib/libc_r/man/pthread_rwlock_init.3 @@ -0,0 +1,100 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlock_init.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlock_init.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_INIT 3 +.Os +.Sh NAME +.Nm pthread_rwlock_init +.Nd initialize a read/write lock +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_init "pthread_rwlock_t *lock" "const pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_init +function is used to initialize a read/write lock, with attributes +specified by +.Fa attr . +If +.Fa attr +is NULL, the default read/write lock attributes are used. +.Pp +The results of calling +.Fn pthread_rwlock_init +with an already initialized lock are undefined. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_init +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_destroy 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_init +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_init +function will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The system lacked the necessary resources (other than memory) to +initialize the lock. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock. +.It Bq Er EPERM +The caller does not have sufficient privilege to perform the +operation. +.El +.Pp +The +.Fn pthread_rwlock_init +function may fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The system has detected an attempt to re-initialize the object +referenced by +.Fa lock , +a previously initialized but not yet destroyed read/write lock. +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_init +function first appeared in +.Fx 3.0 . +.Sh BUGS +The PTHREAD_PROCESS_SHARED attribute is not supported. diff --git a/lib/libc_r/man/pthread_rwlock_rdlock.3 b/lib/libc_r/man/pthread_rwlock_rdlock.3 new file mode 100644 index 00000000000..6bfd3f9ce74 --- /dev/null +++ b/lib/libc_r/man/pthread_rwlock_rdlock.3 @@ -0,0 +1,123 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlock_rdlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlock_rdlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_RDLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_rdlock , +.Nm pthread_rwlock_tryrdlock +.Nd acquire a read/write lock for reading +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_rdlock "pthread_rwlock_t *lock" +.Ft int +.Fn pthread_rwlock_tryrdlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_rdlock +function acquires a read lock on +.Fa lock +provided that +.Fa lock +is not presently held for writing and no writer threads are +presently blocked on the lock. If the read lock cannot be +immediately acquired, the calling thread blocks until it can +acquire the lock. +.Pp +The +.Fn pthread_rwlock_tryrdlock +function performs the same action, but does not block if the lock +cannot be immediately obtained (i.e. the lock is held for writing +or there are waiting writers). +.Pp +A thread may hold multiple concurrent read locks. If so, +.Fn pthread_rwlock_unlock +must be called once for each lock obtained. +.Pp +The results of acquiring a read lock while the calling thread holds +a write lock are undefined. +.Sh IMPLEMENTATION NOTES +To prevent writer starvation, writers are favored over readers. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlock_trywrlock 3 , +.Xr pthread_rwlock_unlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions are expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_tryrdlock +function will fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The lock could not be acquired because a writer holds the lock or +was blocked on it. +.El +.Pp +The +.Fn pthread_rwlock_rdlock +and +.Fn pthread_rwlock_tryrdlock +functions may fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The lock could not be acquired because the maximum number of read locks +against +.Fa lock +has been exceeded. +.It Bq Er EDEADLK +The current thread already owns +.Fa lock +for writing. +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock (applies to +statically initialized locks only). +.El +.Sh HISTORY +The +.Fn pthread_rwlock_rdlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlock_unlock.3 b/lib/libc_r/man/pthread_rwlock_unlock.3 new file mode 100644 index 00000000000..1932429a103 --- /dev/null +++ b/lib/libc_r/man/pthread_rwlock_unlock.3 @@ -0,0 +1,80 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlock_unlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlock_unlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_UNLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_unlock +.Nd release a read/write lock +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_unlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_unlock +function is used to release the read/write lock previously obtained by +.Fn pthread_rwlock_rdlock , +.Fn pthread_rwlock_wrlock , +.Fn pthread_rwlock_tryrdlock , +or +.Fn pthread_rwlock_trywrlock . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_unlock +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Pp +The results are undefined if +.Fa lock +is not held by the calling thread. +.Sh SEE ALSO +.Xr pthread_rwlock_rdlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_unlock +function is expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_unlock +function may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EPERM +The current thread does not own the read/write lock. +.El +.Sh HISTORY +The +.Fn pthread_rwlock_unlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlock_wrlock.3 b/lib/libc_r/man/pthread_rwlock_wrlock.3 new file mode 100644 index 00000000000..881e00c856d --- /dev/null +++ b/lib/libc_r/man/pthread_rwlock_wrlock.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlock_wrlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlock_wrlock.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCK_WRLOCK 3 +.Os +.Sh NAME +.Nm pthread_rwlock_wrlock , +.Nm pthread_rwlock_trywrlock +.Nd acquire a read/write lock for writing +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlock_wrlock "pthread_rwlock_t *lock" +.Ft int +.Fn pthread_rwlock_trywrlock "pthread_rwlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_rwlock_wrlock +function blocks until a write lock can be acquired against +.Fa lock . +The +.Fn pthread_rwlock_trywrlock +function performs the same action, but does not block if the lock +cannot be immediately obtained. +.Pp +The results are undefined if the calling thread already holds the +lock at the time the call is made. +.Sh IMPLEMENTATION NOTES +To prevent writer starvation, writers are favored over readers. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_trywrlock 3 , +.Xr pthread_rwlock_unlock 3 , +.Xr pthread_rwlock_wrlock 3 +.Sh STANDARDS +The +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions are expected to conform to +.St -susv2 . +.Sh ERRORS +The +.Fn pthread_rwlock_trywrlock +function will fail if: +.Bl -tag -width Er +.It Bq Er EBUSY +The calling thread is not able to acquire the lock without blocking. +.El +.Pp +The +.Fn pthread_rwlock_wrlock +and +.Fn pthread_rwlock_trywrlock +functions may fail if: +.Bl -tag -width Er +.It Bq Er EDEADLK +The calling thread already owns the read/write lock (for reading +or writing). +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er ENOMEM +Insufficient memory exists to initialize the lock (applies to +statically initialized locks only). +.El +.Sh HISTORY +The +.Fn pthread_rwlock_wrlock +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlockattr_destroy.3 b/lib/libc_r/man/pthread_rwlockattr_destroy.3 new file mode 100644 index 00000000000..8deab9d214c --- /dev/null +++ b/lib/libc_r/man/pthread_rwlockattr_destroy.3 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlockattr_destroy.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlockattr_destroy.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_DESTROY 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_destroy +.Nd destroy a read/write lock +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_destroy "pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_destroy +function is used to destroy a read/write lock attribute object +previously created with +.Fn pthread_rwlockattr_init . +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_destroy +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlockattr_init 3 , +.Sh STANDARDS +The +.Fn pthread_rwlockattr_destroy +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_destroy +may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_destroy +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlockattr_getpshared.3 b/lib/libc_r/man/pthread_rwlockattr_getpshared.3 new file mode 100644 index 00000000000..de98aab2f5f --- /dev/null +++ b/lib/libc_r/man/pthread_rwlockattr_getpshared.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlockattr_getpshared.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlockattr_getpshared.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_GETPSHARED 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_getpshared +.Nd set the process shared attribute +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_getpshared "pthread_rwlockattr_t *attr" "int *pshared" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_getpshared +function is used to get the process shared setting of a read/write +lock attribute object. The setting is returned via +.Fa pshared , +and may be one of two values: +.Bl -hang -offset flag -width 123456789012345678901234 +.It Ar PTHREAD_PROCESS_SHARED +Any thread of any process that has access to the memory where the +read/write lock resides can manipulate the lock. +.It Ar PTHREAD_PROCESS_PRIVATE +Only threads created within the same process as the thread that +initialized the read/write lock can manipulate the lock. This is +the default value. +.El +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_getpshared +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_getpshared +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_getpshared +may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_getpshared +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlockattr_init.3 b/lib/libc_r/man/pthread_rwlockattr_init.3 new file mode 100644 index 00000000000..ff03334d5e5 --- /dev/null +++ b/lib/libc_r/man/pthread_rwlockattr_init.3 @@ -0,0 +1,68 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlockattr_init.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlockattr_init.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_INIT 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_init +.Nd initialize a read/write lock +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_init "pthread_rwlockattr_t *attr" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_init +function is used to initialize a read/write lock attributes object. +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_init +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_destroy 3 , +.Xr pthread_rwlockattr_getpshared 3 +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_init +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_init +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory exists to initialize the attribute object. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_init +function first appeared in +.Fx 3.0 . diff --git a/lib/libc_r/man/pthread_rwlockattr_setpshared.3 b/lib/libc_r/man/pthread_rwlockattr_setpshared.3 new file mode 100644 index 00000000000..b6b42ca38f8 --- /dev/null +++ b/lib/libc_r/man/pthread_rwlockattr_setpshared.3 @@ -0,0 +1,87 @@ +.\" Copyright (c) 1998 Alex Nash +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: pthread_rwlockattr_setpshared.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" $OpenBSD: pthread_rwlockattr_setpshared.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.\" +.Dd August 4, 1998 +.Dt PTHREAD_RWLOCKATTR_SETPSHARED 3 +.Os +.Sh NAME +.Nm pthread_rwlockattr_setpshared +.Nd set the process shared attribute +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_rwlockattr_setpshared "pthread_rwlockattr_t *attr" "int *pshared" +.Sh DESCRIPTION +The +.Fn pthread_rwlockattr_setpshared +function sets the process shared attribute of +.Fa attr +to the value referenced by +.Fa pshared . +.Fa pshared +may be one of two values: +.Bl -hang -offset flag -width 123456789012345678901234 +.It Ar PTHREAD_PROCESS_SHARED +Any thread of any process that has access to the memory where the +read/write lock resides can manipulate the lock. +.It Ar PTHREAD_PROCESS_PRIVATE +Only threads created within the same process as the thread that +initialized the read/write lock can manipulate the lock. This is +the default value. +.El +.Sh RETURN VALUES +If successful, the +.Fn pthread_rwlockattr_setpshared +function will return zero. Otherwise an error number will be returned +to indicate the error. +.Sh SEE ALSO +.Xr pthread_rwlock_init 3 , +.Xr pthread_rwlockattr_init 3 , +.Xr pthread_rwlockattr_setpshared 3 +.Sh STANDARDS +The +.Fn pthread_rwlockattr_setpshared +function is expected to conform to +.St -susv2 . +.Sh ERRORS +.Fn pthread_rwlockattr_setpshared +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa attr +or +.Fa pshared +is invalid. +.El +.Sh HISTORY +The +.Fn pthread_rwlockattr_setpshared +function first appeared in +.Fx 3.0 . +.Sh BUGS +The PTHREAD_PROCESS_SHARED attribute is not supported. diff --git a/lib/libc_r/man/pthread_self.3 b/lib/libc_r/man/pthread_self.3 index 63cf2dfdafb..46c118af09f 100644 --- a/lib/libc_r/man/pthread_self.3 +++ b/lib/libc_r/man/pthread_self.3 @@ -50,7 +50,6 @@ function returns the thread ID of the calling thread. None. .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_create 3 , .Xr pthread_equal 3 .Sh STANDARDS diff --git a/lib/libc_r/man/pthread_setspecific.3 b/lib/libc_r/man/pthread_setspecific.3 index 448e1872f58..e28cf568213 100644 --- a/lib/libc_r/man/pthread_setspecific.3 +++ b/lib/libc_r/man/pthread_setspecific.3 @@ -81,7 +81,6 @@ value is invalid. .El .Pp .Sh SEE ALSO -.Xr pthreads 3 , .Xr pthread_getspecific 3 , .Xr pthread_key_create 3 , .Xr pthread_key_delete 3 diff --git a/lib/libc_r/man/pwrite.3 b/lib/libc_r/man/pwrite.3 new file mode 100644 index 00000000000..d8e56f9327b --- /dev/null +++ b/lib/libc_r/man/pwrite.3 @@ -0,0 +1,36 @@ +.\" $OpenBSD: pwrite.3,v 1.1 1998/11/09 03:13:16 d Exp $ +.Dd September 7, 1998 +.Os Ox +.Dt PWRITE 3 +.Sh NAME +.Nm pwrite +.Nd atomic seek and write +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft ssize_t +.Fn pwrite "int filedes" "void *buf" "size_t nbytes" "off_t offset" +.Sh DESCRIPTION +The +.Fn pwrite +function writes +.Fa nbyte +bytes from offset +.Fa offset +in the file opened on file descriptor +.Fa filedes. +.Pp +This function is provided for use in a threaded, parallel I/O +environment, where race conditions may exist between two threads +non-atomically seeking and writing to the same file descriptor. +.Sh RETURN VALUES +The +.Fn pread +function returns values identical to +.Xr write 3 . +.Sh SEE ALSO +.Xr pthreads 3 , +.Xr write 3 , +.Xr pread 3 +.Sh STANDARDS +.Fn pread +conforms to TOG SUSv2 . diff --git a/lib/libc_r/test/Makefile b/lib/libc_r/test/Makefile new file mode 100644 index 00000000000..e5962f61357 --- /dev/null +++ b/lib/libc_r/test/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.1 1998/11/09 03:13:17 d Exp $ +# +# Tests for libc_r functionality. +# + +SUBDIR= sigsuspend sigwait + +.include <bsd.subdir.mk> diff --git a/lib/libc_r/test/sigsuspend/Makefile b/lib/libc_r/test/sigsuspend/Makefile new file mode 100644 index 00000000000..796ffdf97e1 --- /dev/null +++ b/lib/libc_r/test/sigsuspend/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.1 1998/11/09 03:13:17 d Exp $ + +PROG= sigsuspend +SRCS= sigsuspend.c +NOMAN= 1 +LDFLAGS= -pthread + +.include <bsd.prog.mk> diff --git a/lib/libc_r/test/sigsuspend/sigsuspend.c b/lib/libc_r/test/sigsuspend/sigsuspend.c new file mode 100644 index 00000000000..894b0926333 --- /dev/null +++ b/lib/libc_r/test/sigsuspend/sigsuspend.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel M. Eischen. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#if defined(__FreeBSD__) +#include <pthread_np.h> +#endif + +static int sigcounts[NSIG + 1]; +static int sigfifo[NSIG + 1]; +static int fifo_depth = 0; +static sigset_t suspender_mask; +static pthread_t suspender_tid; + + +static void * +sigsuspender (void *arg) +{ + int save_count, status, i; + sigset_t run_mask; + + /* Run with all signals blocked. */ + sigfillset (&run_mask); + sigprocmask (SIG_SETMASK, &run_mask, NULL); + + /* Allow these signals to wake us up during a sigsuspend. */ + sigfillset (&suspender_mask); /* Default action */ + sigdelset (&suspender_mask, SIGINT); /* terminate */ + sigdelset (&suspender_mask, SIGHUP); /* terminate */ + sigdelset (&suspender_mask, SIGQUIT); /* create core image */ + sigdelset (&suspender_mask, SIGURG); /* ignore */ + sigdelset (&suspender_mask, SIGIO); /* ignore */ + sigdelset (&suspender_mask, SIGUSR2); /* terminate */ + + while (sigcounts[SIGINT] == 0) { + save_count = sigcounts[SIGUSR2]; + + status = sigsuspend (&suspender_mask); + if ((status == 0) || (errno != EINTR)) { + printf ("Unable to suspend for signals, " + "errno %d, return value %d\n", + errno, status); + exit (1); + } + for (i = 0; i < fifo_depth; i++) + printf ("Sigsuspend woke up by signal %d\n", + sigfifo[i]); + fifo_depth = 0; + } + + pthread_exit (arg); + return (NULL); +} + + +static void +sighandler (int signo) +{ + sigset_t set; + pthread_t self; + + if ((signo >= 0) && (signo <= NSIG)) + sigcounts[signo]++; + + /* + * If we are running on behalf of the suspender thread, + * ensure that we have the correct mask set. + */ + self = pthread_self (); + if (self == suspender_tid) { + sigfifo[fifo_depth] = signo; + fifo_depth++; + printf (" -> Suspender thread signal handler caught signal %d\n", + signo); + sigprocmask (SIG_SETMASK, NULL, &set); + if (set != suspender_mask) + printf (" >>> FAIL: sigsuspender signal handler running " + "with incorrect mask.\n"); + } + else + printf (" -> Main thread signal handler caught signal %d\n", + signo); +} + + +static void +send_thread_signal (pthread_t tid, int signo) +{ + if (pthread_kill (tid, signo) != 0) { + printf ("Unable to send thread signal, errno %d.\n", errno); + exit (1); + } +} + + +static void +send_process_signal (int signo) +{ + if (kill (getpid (), signo) != 0) { + printf ("Unable to send process signal, errno %d.\n", errno); + exit (1); + } +} + + +int main (int argc, char *argv[]) +{ + pthread_attr_t pattr; + void * exit_status; + struct sigaction act; + sigset_t oldset; + sigset_t newset; + + /* Initialize our signal counts. */ + memset ((void *) sigcounts, 0, NSIG * sizeof (int)); + + /* Ignore signal SIGIO. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGIO); + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigaction (SIGIO, &act, NULL); + + /* Install a signal handler for SIGURG. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGURG); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGURG, &act, NULL); + + /* Install a signal handler for SIGXCPU */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGXCPU); + sigaction (SIGXCPU, &act, NULL); + + /* Get our current signal mask. */ + sigprocmask (SIG_SETMASK, NULL, &oldset); + + /* Mask out SIGUSR1 and SIGUSR2. */ + newset = oldset; + sigaddset (&newset, SIGUSR1); + sigaddset (&newset, SIGUSR2); + sigprocmask (SIG_SETMASK, &newset, NULL); + + /* Install a signal handler for SIGUSR1 and SIGUSR2 */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGUSR1); + sigaddset (&act.sa_mask, SIGUSR2); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGUSR1, &act, NULL); + sigaction (SIGUSR2, &act, NULL); + + /* + * Initialize the thread attribute. + */ + if ((pthread_attr_init (&pattr) != 0) || + (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_JOINABLE) != 0)) { + printf ("Unable to initialize thread attributes.\n"); + exit (1); + } + + /* + * Create the sigsuspender thread. + */ + if (pthread_create (&suspender_tid, &pattr, sigsuspender, NULL) != 0) { + printf ("Unable to create thread, errno %d.\n", errno); + exit (1); + } +#if defined(__FreeBSD__) + pthread_set_name_np (suspender_tid, "sigsuspender"); +#endif + + /* + * Verify that an ignored signal doesn't cause a wakeup. + * We don't have a handler installed for SIGIO. + */ + send_thread_signal (suspender_tid, SIGIO); + sleep (1); + send_process_signal (SIGIO); + sleep (1); + if (sigcounts[SIGIO] != 0) + printf ("FAIL: sigsuspend wakes up for ignored signal " + "SIGIO.\n"); + + /* + * Verify that a signal with a default action of ignore, for + * which we have a signal handler installed, will release a + * sigsuspend. + */ + send_thread_signal (suspender_tid, SIGURG); + sleep (1); + send_process_signal (SIGURG); + sleep (1); + if (sigcounts[SIGURG] != 3) + printf ("FAIL: sigsuspend doesn't wake up for SIGURG.\n"); + + /* + * Verify that a SIGUSR2 signal will release a sigsuspended + * thread. + */ + send_thread_signal (suspender_tid, SIGUSR2); + sleep (1); + send_process_signal (SIGUSR2); + sleep (1); + if (sigcounts[SIGUSR2] != 2) + printf ("FAIL: sigsuspend doesn't wake up for SIGUSR2.\n"); + + /* + * Verify that a signal, blocked in both the main and + * sigsuspender threads, does not cause the signal handler + * to be called. + */ + send_thread_signal (suspender_tid, SIGUSR1); + sleep (1); + send_process_signal (SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 0) + printf ("FAIL: signal hander called for SIGUSR1.\n"); + + /* + * Verify that we can still kill the process for a signal + * not being waited on by sigwait. + */ + send_process_signal (SIGPIPE); + printf ("FAIL: SIGPIPE did not terminate process.\n"); + + /* + * Wait for the thread to finish. + */ + pthread_join (suspender_tid, &exit_status); + + return (0); +} + diff --git a/lib/libc_r/test/sigwait/Makefile b/lib/libc_r/test/sigwait/Makefile new file mode 100644 index 00000000000..86f70c9a4ab --- /dev/null +++ b/lib/libc_r/test/sigwait/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile,v 1.1 1998/11/09 03:13:18 d Exp $ + +PROG= sigwait +SRCS= sigwait.c +NOMAN= 1 +LDFLAGS= -pthread + +.include <bsd.prog.mk> diff --git a/lib/libc_r/test/sigwait/sigwait.c b/lib/libc_r/test/sigwait/sigwait.c new file mode 100644 index 00000000000..6dd31087a6e --- /dev/null +++ b/lib/libc_r/test/sigwait/sigwait.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel M. Eischen. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <stdlib.h> +#include <unistd.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#if defined(__FreeBSD__) +#include <pthread_np.h> +#endif + +static int sigcounts[NSIG + 1]; +static sigset_t wait_mask; +static pthread_mutex_t waiter_mutex; + + +static void * +sigwaiter (void *arg) +{ + int signo; + sigset_t mask; + + /* Block SIGHUP */ + sigemptyset (&mask); + sigaddset (&mask, SIGHUP); + sigprocmask (SIG_BLOCK, &mask, NULL); + + while (sigcounts[SIGINT] == 0) { + if (sigwait (&wait_mask, &signo) != 0) { + printf ("Unable to wait for signal, errno %d\n", + errno); + exit (1); + } + sigcounts[signo]++; + printf ("Sigwait caught signal %d\n", signo); + + /* Allow the main thread to prevent the sigwait. */ + pthread_mutex_lock (&waiter_mutex); + pthread_mutex_unlock (&waiter_mutex); + } + + pthread_exit (arg); + return (NULL); +} + + +static void +sighandler (int signo) +{ + printf (" -> Signal handler caught signal %d\n", signo); + + if ((signo >= 0) && (signo <= NSIG)) + sigcounts[signo]++; +} + +static void +send_thread_signal (pthread_t tid, int signo) +{ + if (pthread_kill (tid, signo) != 0) { + printf ("Unable to send thread signal, errno %d.\n", errno); + exit (1); + } +} + +static void +send_process_signal (int signo) +{ + if (kill (getpid (), signo) != 0) { + printf ("Unable to send process signal, errno %d.\n", errno); + exit (1); + } +} + + +int main (int argc, char *argv[]) +{ + pthread_mutexattr_t mattr; + pthread_attr_t pattr; + pthread_t tid; + void * exit_status; + struct sigaction act; + + /* Initialize our signal counts. */ + memset ((void *) sigcounts, 0, NSIG * sizeof (int)); + + /* Setupt our wait mask. */ + sigemptyset (&wait_mask); /* Default action */ + sigaddset (&wait_mask, SIGHUP); /* terminate */ + sigaddset (&wait_mask, SIGINT); /* terminate */ + sigaddset (&wait_mask, SIGQUIT); /* create core image */ + sigaddset (&wait_mask, SIGURG); /* ignore */ + sigaddset (&wait_mask, SIGIO); /* ignore */ + sigaddset (&wait_mask, SIGUSR1); /* terminate */ + + /* Ignore signals SIGHUP and SIGIO. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + sigaddset (&act.sa_mask, SIGIO); + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigaction (SIGHUP, &act, NULL); + sigaction (SIGIO, &act, NULL); + + /* Install a signal handler for SIGURG */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGURG); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGURG, &act, NULL); + + /* Install a signal handler for SIGXCPU */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGXCPU); + sigaction (SIGXCPU, &act, NULL); + + /* + * Initialize the thread attribute. + */ + if ((pthread_attr_init (&pattr) != 0) || + (pthread_attr_setdetachstate (&pattr, + PTHREAD_CREATE_JOINABLE) != 0)) { + printf ("Unable to initialize thread attributes.\n"); + exit (1); + } + + /* + * Initialize and create a mutex. + */ + if ((pthread_mutexattr_init (&mattr) != 0) || + (pthread_mutex_init (&waiter_mutex, &mattr) != 0)) { + printf ("Unable to create waiter mutex.\n"); + exit (1); + } + + /* + * Create the sigwaiter thread. + */ + if (pthread_create (&tid, &pattr, sigwaiter, NULL) != 0) { + printf ("Unable to create thread.\n"); + exit (1); + } +#if defined(__FreeBSD__) + pthread_set_name_np (tid, "sigwaiter"); +#endif + + /* + * Verify that an ignored signal doesn't cause a wakeup. + * We don't have a handler installed for SIGIO. + */ + send_thread_signal (tid, SIGIO); + sleep (1); + send_process_signal (SIGIO); + sleep (1); + if (sigcounts[SIGIO] != 0) + printf ("FAIL: sigwait wakes up for ignored signal SIGIO.\n"); + + /* + * Verify that a signal with a default action of ignore, for + * which we have a signal handler installed, will release a sigwait. + */ + send_thread_signal (tid, SIGURG); + sleep (1); + send_process_signal (SIGURG); + sleep (1); + if (sigcounts[SIGURG] != 2) + printf ("FAIL: sigwait doesn't wake up for SIGURG.\n"); + + /* + * Verify that a signal with a default action that terminates + * the process will release a sigwait. + */ + send_thread_signal (tid, SIGUSR1); + sleep (1); + send_process_signal (SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + printf ("FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + + /* + * Verify that if we install a signal handler for a previously + * ignored signal, an occurrence of this signal will release + * the (already waiting) sigwait. + */ + + /* Install a signal handler for SIGHUP. */ + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGHUP); + act.sa_handler = sighandler; + act.sa_flags = SA_RESTART; + sigaction (SIGHUP, &act, NULL); + + /* Sending SIGHUP should release the sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + send_thread_signal (tid, SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 2) + printf ("FAIL: sigwait doesn't wake up for SIGHUP.\n"); + + /* + * Verify that a pending signal in the waiters mask will + * cause sigwait to return the pending signal. We do this + * by taking the waiters mutex and signaling the waiter to + * release him from the sigwait. The waiter will block + * on taking the mutex, and we can then send the waiter a + * signal which should be added to his pending signals. + * The next time the waiter does a sigwait, he should + * return with the pending signal. + */ + sigcounts[SIGHUP] = 0; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_process_signal (SIGHUP); + sleep (1); + if (sigcounts[SIGHUP] != 1) + printf ("FAIL: sigwait doesn't wake up for SIGHUP.\n"); + /* + * Add SIGHUP to all threads pending signals. Since there is + * a signal handler installed for SIGHUP and this signal is + * blocked from the waiter thread and unblocked in the main + * thread, the signal handler should be called once for SIGHUP. + */ + send_process_signal (SIGHUP); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGHUP] != 3) + printf ("FAIL: sigwait doesn't return for pending SIGHUP.\n"); + + /* + * Repeat the above test using pthread_kill and SIGUSR1 + */ + sigcounts[SIGUSR1] = 0; + pthread_mutex_lock (&waiter_mutex); + /* Release the waiter from sigwait. */ + send_thread_signal (tid, SIGUSR1); + sleep (1); + if (sigcounts[SIGUSR1] != 1) + printf ("FAIL: sigwait doesn't wake up for SIGUSR1.\n"); + /* Add SIGHUP to the waiters pending signals. */ + send_thread_signal (tid, SIGUSR1); + /* Release the waiter thread and allow him to run. */ + pthread_mutex_unlock (&waiter_mutex); + sleep (1); + if (sigcounts[SIGUSR1] != 2) + printf ("FAIL: sigwait doesn't return for pending SIGUSR1.\n"); + + /* + * Verify that we can still kill the process for a signal + * not being waited on by sigwait. + */ + send_process_signal (SIGPIPE); + printf ("FAIL: SIGPIPE did not terminate process.\n"); + + /* + * Wait for the thread to finish. + */ + pthread_join (tid, &exit_status); + + return (0); +} diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc index 0e285297a0b..196cddca170 100644 --- a/lib/libc_r/uthread/Makefile.inc +++ b/lib/libc_r/uthread/Makefile.inc @@ -1,5 +1,5 @@ -# $Id: Makefile.inc,v 1.1 1998/08/27 09:00:49 d Exp $ -# $OpenBSD: Makefile.inc,v 1.1 1998/08/27 09:00:49 d Exp $ +# $Id: Makefile.inc,v 1.2 1998/11/09 03:13:18 d Exp $ +# $OpenBSD: Makefile.inc,v 1.2 1998/11/09 03:13:18 d Exp $ # uthread sources .PATH: ${.CURDIR}/uthread @@ -42,6 +42,7 @@ SRCS+= \ uthread_fstat.c \ uthread_fstatfs.c \ uthread_fsync.c \ + uthread_gc.c \ uthread_getdirentries.c \ uthread_getpeername.c \ uthread_getprio.c \ @@ -69,6 +70,8 @@ SRCS+= \ uthread_recvfrom.c \ uthread_recvmsg.c \ uthread_resume_np.c \ + uthread_rwlock.c \ + uthread_rwlockattr.c \ uthread_select.c \ uthread_self.c \ uthread_sendmsg.c \ @@ -79,6 +82,7 @@ SRCS+= \ uthread_shutdown.c \ uthread_sig.c \ uthread_sigaction.c \ + uthread_sigaltstack.c \ uthread_sigblock.c \ uthread_sigmask.c \ uthread_sigprocmask.c \ @@ -91,6 +95,7 @@ SRCS+= \ uthread_spec.c \ uthread_spinlock.c \ uthread_suspend_np.c \ + uthread_vfork.c \ uthread_wait4.c \ uthread_write.c \ uthread_writev.c \ diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index ce7da3da5c4..2197bb709f6 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_private.h @@ -56,8 +56,8 @@ #define PANIC(string) _thread_exit(__FILE__,__LINE__,string) /* Output debug messages like this: */ -#define stdout_debug(_x) _write(1,_x,strlen(_x)); -#define stderr_debug(_x) _write(2,_x,strlen(_x)); +#define stdout_debug(_x) _thread_sys_write(1,_x,strlen(_x)); +#define stderr_debug(_x) _thread_sys_write(2,_x,strlen(_x)); /* * State change macro: @@ -218,6 +218,18 @@ struct pthread_key { void (*destructor) (); }; +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_rwlock { + pthread_mutex_t lock; /* monitor lock */ + int state; /* 0 = idle >0 = # of readers -1 = writer */ + pthread_cond_t read_signal; + pthread_cond_t write_signal; + int blocked_writers; +}; + /* * Thread states. */ @@ -234,6 +246,7 @@ enum pthread_state { PS_SELECT_WAIT, PS_SLEEP_WAIT, PS_WAIT_WAIT, + PS_SIGSUSPEND, PS_SIGWAIT, PS_JOIN, PS_SUSPENDED, @@ -264,9 +277,9 @@ struct fd_table_entry { struct pthread_queue w_queue; /* Write queue. */ struct pthread *r_owner; /* Ptr to thread owning read lock. */ struct pthread *w_owner; /* Ptr to thread owning write lock. */ - char *r_fname; /* Ptr to read lock source file name */ + const char *r_fname; /* Ptr to read lock source file name */ int r_lineno; /* Read lock source line number. */ - char *w_fname; /* Ptr to write lock source file name */ + const char *w_fname; /* Ptr to write lock source file name */ int w_lineno; /* Write lock source line number. */ int r_lockcount; /* Count for FILE read locks. */ int w_lockcount; /* Count for FILE write locks. */ @@ -287,7 +300,7 @@ union pthread_wait_data { struct { short fd; /* Used when thread waiting on fd */ short branch; /* Line number, for debugging. */ - char *fname; /* Source file name for debugging.*/ + const char *fname; /* Source file name for debugging.*/ } fd; struct pthread_select_data * select_data; }; @@ -315,6 +328,11 @@ struct pthread { struct pthread *nxt; /* + * Pointer to the next thread in the dead thread linked list. + */ + struct pthread *nxt_dead; + + /* * Thread start routine, argument, stack pointer and thread * attributes. */ @@ -426,7 +444,7 @@ struct pthread { /* Cleanup handlers Link List */ struct pthread_cleanup *cleanup; - char *fname; /* Ptr to source file name */ + const char *fname; /* Ptr to source file name */ int lineno; /* Source line number. */ }; @@ -486,6 +504,10 @@ extern int _pthread_stdio_flags[3]; extern struct fd_table_entry **_thread_fd_table; extern int _thread_dtablesize; +/* Garbage collector mutex and condition variable. */ +extern pthread_mutex_t _gc_mutex; +extern pthread_cond_t _gc_cond; + /* * Array of signal actions for this process. */ @@ -514,24 +536,23 @@ int _find_dead_thread(pthread_t); int _find_thread(pthread_t); int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); int _thread_fd_lock(int, int, struct timespec *); -int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno); +int _thread_fd_lock_debug(int, int, struct timespec *,const char *fname,int lineno); void _dispatch_signals(void); void _thread_signal(pthread_t, int); -void _lock_dead_thread_list(void); void _lock_thread(void); void _lock_thread_list(void); -void _unlock_dead_thread_list(void); void _unlock_thread(void); void _unlock_thread_list(void); -void _thread_exit(char *, int, char *); +void _thread_exit(char *, int, char *) + __attribute__((noreturn)); void _thread_fd_unlock(int, int); void _thread_fd_unlock_debug(int, int, char *, int); void *_thread_cleanup(pthread_t); void _thread_cleanupspecific(void); void _thread_dump_info(void); -void _thread_init(void) __attribute__((constructor)); +void _thread_init(void) /* __attribute__((constructor)) */; void _thread_kern_sched(struct sigcontext *); -void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno); +void _thread_kern_sched_state(enum pthread_state,const char *fname,int lineno); void _thread_kern_set_timeout(struct timespec *); void _thread_sig_handler(int, int, struct sigcontext *); void _thread_start(void); @@ -543,6 +564,8 @@ int _thread_queue_remove(struct pthread_queue *, struct pthread *); int _thread_fd_table_init(int fd); struct pthread *_thread_queue_get(struct pthread_queue *); struct pthread *_thread_queue_deq(struct pthread_queue *); +pthread_addr_t _thread_gc(pthread_addr_t); + /* #include <signal.h> */ #ifdef _USER_SIGNAL_H @@ -553,7 +576,7 @@ int _thread_sys_sigsuspend(const sigset_t *); int _thread_sys_siginterrupt(int, int); int _thread_sys_sigpause(int); int _thread_sys_sigreturn(struct sigcontext *); -int _thread_sys_sigstack(const struct sigstack *, struct sigstack *); +int _thread_sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); int _thread_sys_sigvec(int, struct sigvec *, struct sigvec *); void _thread_sys_psignal(unsigned int, const char *); void (*_thread_sys_signal(int, void (*)(int)))(int); @@ -675,7 +698,8 @@ pid_t _thread_sys_fork(void); pid_t _thread_sys_tcgetpgrp(int); ssize_t _thread_sys_read(int, void *, size_t); ssize_t _thread_sys_write(int, const void *, size_t); -void _thread_sys__exit(int); +void _thread_sys__exit(int) + __attribute__((noreturn)); #endif /* #include <fcntl.h> */ diff --git a/lib/libc_r/uthread/uthread_close.c b/lib/libc_r/uthread/uthread_close.c index 7e21853223e..4bc4999ebda 100644 --- a/lib/libc_r/uthread/uthread_close.c +++ b/lib/libc_r/uthread/uthread_close.c @@ -43,7 +43,6 @@ close(int fd) { int flags; int ret; - int status; struct stat sb; /* Lock the file descriptor while the file is closed: */ diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c index fae12ebb68b..aedc36b4b31 100644 --- a/lib/libc_r/uthread/uthread_cond.c +++ b/lib/libc_r/uthread/uthread_cond.c @@ -126,7 +126,6 @@ int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) { int rval = 0; - int status; if (cond == NULL) rval = EINVAL; @@ -190,7 +189,6 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) { int rval = 0; - int status; if (cond == NULL) rval = EINVAL; @@ -270,7 +268,6 @@ int pthread_cond_signal(pthread_cond_t * cond) { int rval = 0; - int status; pthread_t pthread; if (cond == NULL || *cond == NULL) @@ -309,7 +306,6 @@ int pthread_cond_broadcast(pthread_cond_t * cond) { int rval = 0; - int status; pthread_t pthread; if (cond == NULL || *cond == NULL) diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c index 53759d8f440..68db603cac2 100644 --- a/lib/libc_r/uthread/uthread_create.c +++ b/lib/libc_r/uthread/uthread_create.c @@ -44,9 +44,9 @@ int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg) { - int i; + int f_gc = 0; int ret = 0; - int status; + pthread_t gc_thread; pthread_t new_thread; pthread_attr_t pattr; void *stack; @@ -149,6 +149,12 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, /* Lock the thread list: */ _lock_thread_list(); + /* + * Check if the garbage collector thread + * needs to be started. + */ + f_gc = (_thread_link_list == _thread_initial); + /* Add the thread to the linked list of all threads: */ new_thread->nxt = _thread_link_list; _thread_link_list = new_thread; @@ -161,6 +167,14 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, /* Schedule the new user thread: */ _thread_kern_sched(NULL); + + /* + * Start a garbage collector thread + * if necessary. + */ + if (f_gc && pthread_create(&gc_thread,NULL, + _thread_gc,NULL) != 0) + PANIC("Can't create gc thread"); } } @@ -171,6 +185,9 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr, void _thread_start(void) { + /* We just left the scheduler via longjmp: */ + _thread_kern_in_sched = 0; + /* Run the current thread's start routine with argument: */ pthread_exit(_thread_run->start_routine(_thread_run->arg)); diff --git a/lib/libc_r/uthread/uthread_detach.c b/lib/libc_r/uthread/uthread_detach.c index da456bfbab9..d471da6f068 100644 --- a/lib/libc_r/uthread/uthread_detach.c +++ b/lib/libc_r/uthread/uthread_detach.c @@ -39,7 +39,6 @@ int pthread_detach(pthread_t pthread) { int rval = 0; - int status; pthread_t next_thread; /* Check for invalid calling parameters: */ diff --git a/lib/libc_r/uthread/uthread_dup2.c b/lib/libc_r/uthread/uthread_dup2.c index e9edddd35c1..3e4ed27d359 100644 --- a/lib/libc_r/uthread/uthread_dup2.c +++ b/lib/libc_r/uthread/uthread_dup2.c @@ -30,6 +30,7 @@ * SUCH DAMAGE. * */ +#include <errno.h> #include <unistd.h> #ifdef _THREAD_SAFE #include <pthread.h> @@ -39,11 +40,20 @@ int dup2(int fd, int newfd) { int ret; + int newfd_opened; + + /* Check if the file descriptor is out of range: */ + if (newfd < 0 || newfd >= _thread_dtablesize) { + /* Return a bad file descriptor error: */ + errno = EBADF; + ret = -1; + } /* Lock the file descriptor: */ - if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + else if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { /* Lock the file descriptor: */ - if ((ret = _FD_LOCK(newfd, FD_RDWR, NULL)) == 0) { + if (!(newfd_opened = (_thread_fd_table[newfd] != NULL)) || + (ret = _FD_LOCK(newfd, FD_RDWR, NULL)) == 0) { /* Perform the 'dup2' syscall: */ if ((ret = _thread_sys_dup2(fd, newfd)) < 0) { } @@ -63,7 +73,8 @@ dup2(int fd, int newfd) } /* Unlock the file descriptor: */ - _FD_UNLOCK(newfd, FD_RDWR); + if (newfd_opened) + _FD_UNLOCK(newfd, FD_RDWR); } /* Unlock the file descriptor: */ _FD_UNLOCK(fd, FD_RDWR); diff --git a/lib/libc_r/uthread/uthread_execve.c b/lib/libc_r/uthread/uthread_execve.c index 5f40e1c560e..0d289a44ab9 100644 --- a/lib/libc_r/uthread/uthread_execve.c +++ b/lib/libc_r/uthread/uthread_execve.c @@ -97,7 +97,7 @@ execve(const char *name, char *const * argv, char *const * envp) } } - /* Execute the process: */ + /* Set the signal mask: */ _thread_sys_sigprocmask(SIG_SETMASK, &_thread_run->sigmask, NULL); /* Execute the process: */ diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c index 0083f2b0169..bc061e0fa6a 100644 --- a/lib/libc_r/uthread/uthread_exit.c +++ b/lib/libc_r/uthread/uthread_exit.c @@ -34,10 +34,13 @@ #include <unistd.h> #include <fcntl.h> #include <string.h> +#include <stdio.h> +#include <stdlib.h> #ifdef _THREAD_SAFE #include <pthread.h> #include "pthread_private.h" +void _exit(int) __attribute__((noreturn)); void _exit(int status) { int flags; @@ -98,14 +101,12 @@ _thread_exit(char *fname, int lineno, char *string) void pthread_exit(void *status) { - int sig; - long l; pthread_t pthread; /* Check if this thread is already in the process of exiting: */ if ((_thread_run->flags & PTHREAD_EXITING) != 0) { char msg[128]; - snprintf(msg,"Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",_thread_run); + snprintf(msg,sizeof msg,"Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",_thread_run); PANIC(msg); } @@ -133,56 +134,29 @@ pthread_exit(void *status) PTHREAD_NEW_STATE(pthread,PS_RUNNING); } - /* Lock the thread list: */ - _lock_thread_list(); - - /* Check if the running thread is at the head of the linked list: */ - if (_thread_link_list == _thread_run) { - /* There is no previous thread: */ - _thread_link_list = _thread_run->nxt; - } else { - /* Point to the first thread in the list: */ - pthread = _thread_link_list; - - /* - * Enter a loop to find the thread in the linked list before - * the running thread: - */ - while (pthread != NULL && pthread->nxt != _thread_run) { - /* Point to the next thread: */ - pthread = pthread->nxt; - } - - /* Check that a previous thread was found: */ - if (pthread != NULL) { - /* - * Point the previous thread to the one after the - * running thread: - */ - pthread->nxt = _thread_run->nxt; - } - } - - /* Unlock the thread list: */ - _unlock_thread_list(); - - /* Lock the dead thread list: */ - _lock_dead_thread_list(); - /* - * This thread will never run again. Add it to the list of dead - * threads: + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. */ - _thread_run->nxt = _thread_dead; - _thread_dead = _thread_run; + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); - /* Unlock the dead thread list: */ - _unlock_dead_thread_list(); + /* Add this thread to the list of dead threads. */ + _thread_run->nxt_dead = _thread_dead; + _thread_dead = _thread_run; /* - * The running thread is no longer in the thread link list so it will - * now die: + * Signal the garbage collector thread that there is something + * to clean up. */ + if (pthread_cond_signal(&_gc_cond) != 0) + PANIC("Cannot signal gc cond"); + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* This this thread will never be re-scheduled. */ _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); /* This point should not be reached. */ diff --git a/lib/libc_r/uthread/uthread_fcntl.c b/lib/libc_r/uthread/uthread_fcntl.c index eecda60d8ae..6ea013afe5d 100644 --- a/lib/libc_r/uthread/uthread_fcntl.c +++ b/lib/libc_r/uthread/uthread_fcntl.c @@ -44,7 +44,6 @@ fcntl(int fd, int cmd,...) int nonblock; int oldfd; int ret; - int status; va_list ap; /* Lock the file descriptor: */ diff --git a/lib/libc_r/uthread/uthread_fd.c b/lib/libc_r/uthread/uthread_fd.c index 1e4495e6ef9..0c2b10a7d8a 100644 --- a/lib/libc_r/uthread/uthread_fd.c +++ b/lib/libc_r/uthread/uthread_fd.c @@ -29,8 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_fd.c,v 1.1 1998/08/27 09:01:01 d Exp $ - * $OpenBSD: uthread_fd.c,v 1.1 1998/08/27 09:01:01 d Exp $ + * $Id: uthread_fd.c,v 1.2 1998/11/09 03:13:19 d Exp $ + * $OpenBSD: uthread_fd.c,v 1.2 1998/11/09 03:13:19 d Exp $ * */ #include <errno.h> @@ -56,6 +56,7 @@ _thread_fd_table_init(int fd) { int ret = 0; struct fd_table_entry *entry; + int saved_errno; /* Check if the file descriptor is out of range: */ if (fd < 0 || fd >= _thread_dtablesize) { @@ -117,8 +118,10 @@ _thread_fd_table_init(int fd) * not support non-blocking calls, or if the * driver is naturally non-blocking. */ + saved_errno = errno; _thread_sys_fcntl(fd, F_SETFL, entry->flags | O_NONBLOCK); + errno = saved_errno; /* Lock the file descriptor table: */ _SPINLOCK(&fd_table_lock); @@ -531,7 +534,7 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno) int _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, - char *fname, int lineno) + const char *fname, int lineno) { int ret; diff --git a/lib/libc_r/uthread/uthread_file.c b/lib/libc_r/uthread/uthread_file.c index 71fecfea217..26f0835ec1c 100644 --- a/lib/libc_r/uthread/uthread_file.c +++ b/lib/libc_r/uthread/uthread_file.c @@ -29,8 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_file.c,v 1.1 1998/08/27 09:01:02 d Exp $ - * $OpenBSD: uthread_file.c,v 1.1 1998/08/27 09:01:02 d Exp $ + * $Id: uthread_file.c,v 1.2 1998/11/09 03:13:19 d Exp $ + * $OpenBSD: uthread_file.c,v 1.2 1998/11/09 03:13:19 d Exp $ * * POSIX stdio FILE locking functions. These assume that the locking * is only required at FILE structure level, not at file descriptor @@ -46,13 +46,6 @@ #include "pthread_private.h" /* - * Weak symbols for externally visible functions in this file: - */ -#pragma weak flockfile=_flockfile -#pragma weak ftrylockfile=_ftrylockfile -#pragma weak funlockfile=_funlockfile - -/* * The FILE lock structure. The FILE *fp is locked if the owner is * not NULL. If not locked, the file lock structure can be * reassigned to a different file by setting fp. @@ -83,7 +76,7 @@ struct file_lock { * structures. If there is a collision, a linear search of the * dynamic list of locks linked to each static lock is perfomed. */ -#define file_idx(_p) ((((long) _p) >> sizeof(void *)) % NUM_HEADS) +#define file_idx(_p) ((((u_long) _p) >> sizeof(void *)) % NUM_HEADS) /* * Global array of file locks. The first lock for each hash bucket is @@ -123,7 +116,7 @@ find_lock(int idx, FILE *fp) * Loop through the dynamic locks looking for the * target file: */ - while (p != NULL && p->fp != fp && p->owner != NULL) + while (p != NULL && (p->fp != fp || p->owner == NULL)) /* Not this file, try the next: */ p = p->entry.le_next; } @@ -180,10 +173,8 @@ do_lock(int idx, FILE *fp) } void -_flockfile_debug(FILE * fp, char *fname, int lineno) +_flockfile_debug(FILE * fp, const char *fname, int lineno) { - int fd, flags; - int status; int idx = file_idx(fp); struct file_lock *p; @@ -246,17 +237,16 @@ _flockfile_debug(FILE * fp, char *fname, int lineno) } void -_flockfile(FILE * fp) +flockfile(FILE * fp) { - _flockfile_debug(fp, __FILE__, __LINE__); + _flockfile_debug(fp, "?", 1); return; } int -_ftrylockfile(FILE * fp) +ftrylockfile(FILE * fp) { int ret = -1; - int status; int idx = file_idx(fp); struct file_lock *p; @@ -306,9 +296,8 @@ _ftrylockfile(FILE * fp) } void -_funlockfile(FILE * fp) +funlockfile(FILE * fp) { - int status; int idx = file_idx(fp); struct file_lock *p; diff --git a/lib/libc_r/uthread/uthread_find_thread.c b/lib/libc_r/uthread/uthread_find_thread.c index 99e302306d2..e4a59a0d83f 100644 --- a/lib/libc_r/uthread/uthread_find_thread.c +++ b/lib/libc_r/uthread/uthread_find_thread.c @@ -76,8 +76,12 @@ _find_dead_thread(pthread_t pthread) /* Invalid thread: */ return(EINVAL); - /* Lock the dead thread list: */ - _lock_dead_thread_list(); + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); /* Point to the first thread in the list: */ pthread1 = _thread_dead; @@ -85,11 +89,12 @@ _find_dead_thread(pthread_t pthread) /* Search for the thread to join to: */ while (pthread1 != NULL && pthread1 != pthread) { /* Point to the next thread: */ - pthread1 = pthread1->nxt; + pthread1 = pthread1->nxt_dead; } - /* Unlock the dead thread list: */ - _unlock_dead_thread_list(); + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); /* Return zero if the thread exists: */ return ((pthread1 != NULL) ? 0:ESRCH); diff --git a/lib/libc_r/uthread/uthread_fork.c b/lib/libc_r/uthread/uthread_fork.c index b62990a1a50..c9b5cee5f90 100644 --- a/lib/libc_r/uthread/uthread_fork.c +++ b/lib/libc_r/uthread/uthread_fork.c @@ -33,8 +33,8 @@ #include <errno.h> #include <string.h> #include <unistd.h> -#include <stdlib.h> #include <fcntl.h> +#include <stdlib.h> #ifdef _THREAD_SAFE #include <pthread.h> #include "pthread_private.h" @@ -43,7 +43,6 @@ pid_t fork(void) { int flags; - int status; pid_t ret; pthread_t pthread; pthread_t pthread_next; @@ -105,15 +104,16 @@ fork(void) pthread->nxt = NULL; } else { if (pthread->attr.stackaddr_attr == - NULL && pthread->stack != NULL) { + NULL && pthread->stack != NULL) /* * Free the stack of the * dead thread: */ free(pthread->stack); - } + if (pthread->specific_data != NULL) free(pthread->specific_data); + free(pthread); } diff --git a/lib/libc_r/uthread/uthread_gc.c b/lib/libc_r/uthread/uthread_gc.c new file mode 100644 index 00000000000..32d79b5dfac --- /dev/null +++ b/lib/libc_r/uthread/uthread_gc.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: uthread_gc.c,v 1.1 1998/11/09 03:13:19 d Exp $ + * $OpenBSD: uthread_gc.c,v 1.1 1998/11/09 03:13:19 d Exp $ + * + * Garbage collector thread. Frees memory allocated for dead threads. + * + */ +#include <errno.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +pthread_addr_t +_thread_gc(pthread_addr_t arg) +{ + int f_debug; + int f_done = 0; + int ret; + pthread_t pthread; + pthread_t pthread_cln; + pthread_t pthread_nxt; + pthread_t pthread_prv; + struct timespec abstime; + void *p_stack; + + /* Set a debug flag based on an environment variable. */ + f_debug = (getenv("LIBC_R_DEBUG") != NULL); + + /* Set the name of this thread. */ + pthread_set_name_np(_thread_run,"GC"); + + while (!f_done) { + /* Check if debugging this application. */ + if (f_debug) + /* Dump thread info to file. */ + _thread_dump_info(); + + /* Lock the thread list: */ + _lock_thread_list(); + + /* Check if this is the last running thread: */ + if (_thread_link_list == _thread_run && + _thread_link_list->nxt == NULL) + /* + * This is the last thread, so it can exit + * now. + */ + f_done = 1; + + /* Unlock the thread list: */ + _unlock_thread_list(); + + /* + * Lock the garbage collector mutex which ensures that + * this thread sees another thread exit: + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* No stack of thread structure to free yet: */ + p_stack = NULL; + pthread_cln = NULL; + + /* Point to the first dead thread (if there are any): */ + pthread = _thread_dead; + + /* There is no previous dead thread: */ + pthread_prv = NULL; + + /* + * Enter a loop to search for the first dead thread that + * has memory to free. + */ + while (p_stack == NULL && pthread_cln == NULL && + pthread != NULL) { + /* Save a pointer to the next thread: */ + pthread_nxt = pthread->nxt_dead; + + /* Check if the initial thread: */ + if (pthread == _thread_initial) + /* Don't destroy the initial thread. */ + pthread_prv = pthread; + + /* + * Check if this thread has detached: + */ + else if ((pthread->attr.flags & + PTHREAD_DETACHED) != 0) { + /* + * Check if there is no previous dead + * thread: + */ + if (pthread_prv == NULL) + /* + * The dead thread is at the head + * of the list: + */ + _thread_dead = pthread_nxt; + else + /* + * The dead thread is not at the + * head of the list: + */ + pthread_prv->nxt_dead = + pthread->nxt_dead; + + /* + * Check if the stack was not specified by + * the caller to pthread_create and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + /* + * Point to the stack that must + * be freed outside the locks: + */ + p_stack = pthread->stack; + } + + /* + * Point to the thread structure that must + * be freed outside the locks: + */ + pthread_cln = pthread; + } else { + /* + * This thread has not detached, so do + * not destroy it: + */ + pthread_prv = pthread; + + /* + * Check if the stack was not specified by + * the caller to pthread_create and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + /* + * Point to the stack that must + * be freed outside the locks: + */ + p_stack = pthread->stack; + + /* + * NULL the stack pointer now + * that the memory has been freed: + */ + pthread->stack = NULL; + } + } + + /* Point to the next thread: */ + pthread = pthread_nxt; + } + + /* + * Check if this is not the last thread and there is no + * memory to free this time around. + */ + if (!f_done && p_stack == NULL && pthread_cln == NULL) { + /* Get the current time. */ + if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) + PANIC("gc cannot get time"); + + /* + * Do a backup poll in 10 seconds if no threads + * die before then. + */ + abstime.tv_sec += 10; + + /* + * Wait for a signal from a dying thread or a + * timeout (for a backup poll). + */ + if ((ret = pthread_cond_timedwait(&_gc_cond, + &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) + PANIC("gc cannot wait for a signal"); + } + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* + * If there is memory to free, do it now. The call to + * free() might block, so this must be done outside the + * locks. + */ + if (p_stack != NULL) + free(p_stack); + if (pthread_cln != NULL) { + /* Lock the thread list: */ + _lock_thread_list(); + + /* + * Check if the thread is at the head of the + * linked list. + */ + if (_thread_link_list == pthread_cln) + /* There is no previous thread: */ + _thread_link_list = pthread_cln->nxt; + else { + /* Point to the first thread in the list: */ + pthread = _thread_link_list; + + /* + * Enter a loop to find the thread in the + * linked list before the thread that is + * about to be freed. + */ + while (pthread != NULL && + pthread->nxt != pthread_cln) + /* Point to the next thread: */ + pthread = pthread->nxt; + + /* Check that a previous thread was found: */ + if (pthread != NULL) { + /* + * Point the previous thread to + * the one after the thread being + * freed: + */ + pthread->nxt = pthread_cln->nxt; + } + } + + /* Unlock the thread list: */ + _unlock_thread_list(); + + /* + * Free the memory allocated for the thread + * structure. + */ + free(pthread_cln); + } + + } + return (NULL); +} +#endif /* _THREAD_SAFE */ diff --git a/lib/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c index bd829e8be55..9db574e7521 100644 --- a/lib/libc_r/uthread/uthread_info.c +++ b/lib/libc_r/uthread/uthread_info.c @@ -57,6 +57,7 @@ static const struct s_thread_info thread_info[] = { {PS_SELECT_WAIT , "Waiting on select"}, {PS_SLEEP_WAIT , "Sleeping"}, {PS_WAIT_WAIT , "Waiting process"}, + {PS_SIGSUSPEND , "Suspended, waiting for a signal"}, {PS_SIGWAIT , "Waiting for a signal"}, {PS_JOIN , "Waiting to join"}, {PS_SUSPENDED , "Suspended"}, @@ -67,7 +68,7 @@ static const struct s_thread_info thread_info[] = { void _thread_dump_info(void) { - char s[128]; + char s[512]; int fd; int i; int j; @@ -85,14 +86,20 @@ _thread_dump_info(void) _thread_sys_write(fd, s, strlen(s)); /* Enter a loop to report each thread in the global list: */ - for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { + for (pthread = _thread_link_list; pthread != NULL; + pthread = pthread->nxt) { /* Find the state: */ - for (j = 0; j < (sizeof(thread_info) / sizeof(struct s_thread_info)) - 1; j++) + for (j = 0; j < (sizeof(thread_info) / + sizeof(struct s_thread_info)) - 1; j++) if (thread_info[j].state == pthread->state) break; /* Output a record for the current thread: */ - sprintf(s, "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", - pthread, (pthread->name == NULL) ? "":pthread->name, pthread->pthread_priority, thread_info[j].name,pthread->fname,pthread->lineno); + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? + "":pthread->name, pthread->pthread_priority, + thread_info[j].name, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); /* Check if this is the running thread: */ @@ -115,13 +122,19 @@ _thread_dump_info(void) case PS_FDR_WAIT: case PS_FDW_WAIT: /* Write the lock details: */ - sprintf(s, "fd %d[%s:%d]", pthread->data.fd.fd, pthread->data.fd.fname, pthread->data.fd.branch); + snprintf(s, sizeof(s), "fd %d[%s:%d]", + pthread->data.fd.fd, + pthread->data.fd.fname, + pthread->data.fd.branch); _thread_sys_write(fd, s, strlen(s)); - sprintf(s, "owner %pr/%pw\n", _thread_fd_table[pthread->data.fd.fd]->r_owner, _thread_fd_table[pthread->data.fd.fd]->w_owner); + snprintf(s, sizeof(s), "owner %pr/%pw\n", + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); _thread_sys_write(fd, s, strlen(s)); break; case PS_SIGWAIT: - sprintf(s, "sigmask 0x%08lx\n", (unsigned long)pthread->sigmask); + snprintf(s, sizeof(s), "sigmask 0x%08lx\n", + (unsigned long)pthread->sigmask); _thread_sys_write(fd, s, strlen(s)); break; @@ -149,9 +162,13 @@ _thread_dump_info(void) * Enter a loop to report each thread in the global * dead thread list: */ - for (pthread = _thread_dead; pthread != NULL; pthread = pthread->nxt) { + for (pthread = _thread_dead; pthread != NULL; + pthread = pthread->nxt_dead) { /* Output a record for the current thread: */ - sprintf(s, "Thread %p prio %3d [%s:%d]\n", pthread, pthread->pthread_priority,pthread->fname,pthread->lineno); + snprintf(s, sizeof(s), + "Thread %p prio %3d [%s:%d]\n", + pthread, pthread->pthread_priority, + pthread->fname,pthread->lineno); _thread_sys_write(fd, s, strlen(s)); } } @@ -168,7 +185,8 @@ _thread_dump_info(void) */ if (_thread_fd_table[i] != NULL) { /* Report the file descriptor lock status: */ - sprintf(s, "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n", + snprintf(s, sizeof(s), + "fd[%3d] read owner %p count %d [%s:%d]\n write owner %p count %d [%s:%d]\n", i, _thread_fd_table[i]->r_owner, _thread_fd_table[i]->r_lockcount, diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c index 40922f5b64b..95bc34e2797 100644 --- a/lib/libc_r/uthread/uthread_init.c +++ b/lib/libc_r/uthread/uthread_init.c @@ -35,10 +35,12 @@ #include <stdlib.h> #include <string.h> #include <fcntl.h> +#include <paths.h> #include <unistd.h> #include <sys/time.h> -#include <paths.h> +#include <sys/ttycom.h> #include <sys/param.h> +#include <sys/ioctl.h> #include <signal.h> #ifdef _THREAD_SAFE #include <machine/reg.h> @@ -78,6 +80,8 @@ struct pthread_cond_attr pthread_condattr_default = { int _pthread_stdio_flags[3]; struct fd_table_entry ** _thread_fd_table = NULL; int _thread_dtablesize = NOFILE_MAX; +pthread_mutex_t _gc_mutex = NULL; +pthread_cond_t _gc_cond = NULL; struct sigaction _thread_sigact[NSIG]; #ifdef GCC_2_8_MADE_THREAD_AWARE @@ -112,6 +116,7 @@ static void ***dynamic_allocator_handler_fn() void _thread_init(void) { + int fd; int flags; int i; struct sigaction act; @@ -121,13 +126,11 @@ _thread_init(void) /* Only initialise the threaded application once. */ return; -#ifdef __FreeBSD__ /* * Check for the special case of this process running as * or in place of init as pid = 1: */ if (getpid() == 1) { - int fd; /* * Setup a new session for this process which is * assumed to be running as root. @@ -147,7 +150,6 @@ _thread_init(void) _thread_sys_dup2(fd,2) == -1) PANIC("Can't dup2"); } -#endif __FreeBSD__ /* Get the standard I/O flags before messing with them : */ for (i = 0; i < 3; i++) @@ -287,22 +289,29 @@ _thread_init(void) __set_dynamic_handler_allocator( dynamic_allocator_handler_fn ); #endif /* GCC_2_8_MADE_THREAD_AWARE */ + /* Initialise the garbage collector mutex and condition variable. */ + if (pthread_mutex_init(&_gc_mutex,NULL) != 0 || + pthread_cond_init(&_gc_cond,NULL) != 0) + PANIC("Failed to initialise garbage collector mutex or condvar"); + return; } -#if 0 /* - * Special start up code for NetBSD/Alpha + * Use the a.out .init symbol to start the thread package going */ -int -main(int argc, char *argv[], char *env); +extern void __init_threads __P((void)) asm(".init"); +void __init_threads() { + _thread_init(); +} -int -_thread_main(int argc, char *argv[], char *env) -{ +/* + * Use elf's ld.so _init symbol to start the thread package going + */ +extern int _init __P((void)); +int _init() { _thread_init(); - return (main(argc, argv, env)); + return 0; } -#endif alpha_special_code #endif _THREAD_SAFE diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c index 9a0f7828f7e..f2c54f69a51 100644 --- a/lib/libc_r/uthread/uthread_kern.c +++ b/lib/libc_r/uthread/uthread_kern.c @@ -29,8 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_kern.c,v 1.1 1998/08/27 09:01:08 d Exp $ - * $OpenBSD: uthread_kern.c,v 1.1 1998/08/27 09:01:08 d Exp $ + * $Id: uthread_kern.c,v 1.2 1998/11/09 03:13:20 d Exp $ + * $OpenBSD: uthread_kern.c,v 1.2 1998/11/09 03:13:20 d Exp $ * */ #include <errno.h> @@ -60,8 +60,6 @@ _thread_kern_sched(struct sigcontext * scp) int prio = -1; pthread_t pthread; pthread_t pthread_h = NULL; - pthread_t pthread_nxt = NULL; - pthread_t pthread_prv = NULL; pthread_t pthread_s = NULL; struct itimerval itimer; struct timespec ts; @@ -91,7 +89,7 @@ _thread_kern_sched(struct sigcontext * scp) _thread_run->sig_saved = 1; } /* Save the state of the current thread: */ - else if (setjmp(_thread_run->saved_jmp_buf) != 0) { + else if (_thread_machdep_setjmp(_thread_run->saved_jmp_buf) != 0) { /* * This point is reached when a longjmp() is called to * restore the state of a thread. @@ -106,89 +104,13 @@ _thread_kern_sched(struct sigcontext * scp) */ _dispatch_signals(); return; - } else { + } else /* Flag the jump buffer was the last state saved: */ _thread_run->sig_saved = 0; - } /* Save errno. */ _thread_run->error = errno; - /* Point to the first dead thread (if there are any): */ - pthread = _thread_dead; - - /* There is no previous dead thread: */ - pthread_prv = NULL; - - /* Enter a loop to cleanup after dead threads: */ - while (pthread != NULL) { - /* Save a pointer to the next thread: */ - pthread_nxt = pthread->nxt; - - /* Check if this thread is one which is running: */ - if (pthread == _thread_run || pthread == _thread_initial) { - /* - * Don't destroy the running thread or the initial - * thread. - */ - pthread_prv = pthread; - } - /* - * Check if this thread has detached: - */ - else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { - /* Check if there is no previous dead thread: */ - if (pthread_prv == NULL) { - /* - * The dead thread is at the head of the - * list: - */ - _thread_dead = pthread_nxt; - } else { - /* - * The dead thread is not at the head of the - * list: - */ - pthread_prv->nxt = pthread->nxt; - } - - /* - * Check if the stack was not specified by the caller - * to pthread_create and has not been destroyed yet: - */ - if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { - /* Free the stack of the dead thread: */ - free(pthread->stack); - } - /* Free the memory allocated to the thread structure: */ - free(pthread); - } else { - /* - * This thread has not detached, so do not destroy - * it: - */ - pthread_prv = pthread; - - /* - * Check if the stack was not specified by the caller - * to pthread_create and has not been destroyed yet: - */ - if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { - /* Free the stack of the dead thread: */ - free(pthread->stack); - - /* - * NULL the stack pointer now that the memory - * has been freed: - */ - pthread->stack = NULL; - } - } - - /* Point to the next thread: */ - pthread = pthread_nxt; - } - /* * Enter a the scheduling loop that finds the next thread that is * ready to run. This loop completes when there are no more threads @@ -280,10 +202,12 @@ _thread_kern_sched(struct sigcontext * scp) * Accumulate the number of microseconds that this * thread has run for: */ - _thread_run->slice_usec += (_thread_run->last_inactive.tv_sec - - _thread_run->last_active.tv_sec) * 1000000 + - _thread_run->last_inactive.tv_usec - - _thread_run->last_active.tv_usec; + if (_thread_run->slice_usec != -1) { + _thread_run->slice_usec += (_thread_run->last_inactive.tv_sec - + _thread_run->last_active.tv_sec) * 1000000 + + _thread_run->last_inactive.tv_usec - + _thread_run->last_active.tv_usec; + } /* * Check if this thread has reached its allocated @@ -316,7 +240,7 @@ _thread_kern_sched(struct sigcontext * scp) * the last incremental priority check was * made: */ - else if (timercmp(&_thread_run->last_inactive, &kern_inc_prio_time, <)) { + else if (timercmp(&pthread->last_inactive, &kern_inc_prio_time, <)) { /* * Increment the incremental priority * for this thread in the hope that @@ -657,7 +581,7 @@ _thread_kern_sched(struct sigcontext * scp) * was context switched out (by a longjmp to * a different thread): */ - longjmp(_thread_run->saved_jmp_buf, 1); + _thread_machdep_longjmp(_thread_run->saved_jmp_buf, 1); /* This point should not be reached. */ PANIC("Thread has returned from sigreturn or longjmp"); @@ -669,7 +593,7 @@ _thread_kern_sched(struct sigcontext * scp) } void -_thread_kern_sched_state(enum pthread_state state, char *fname, int lineno) +_thread_kern_sched_state(enum pthread_state state, const char *fname, int lineno) { /* Change the state of the current thread: */ _thread_run->state = state; @@ -750,6 +674,7 @@ _thread_kern_select(int wait_reqd) case PS_STATE_MAX: case PS_WAIT_WAIT: case PS_SUSPENDED: + case PS_SIGSUSPEND: /* Nothing to do here. */ break; @@ -1080,6 +1005,7 @@ _thread_kern_select(int wait_reqd) case PS_SIGTHREAD: case PS_STATE_MAX: case PS_SUSPENDED: + case PS_SIGSUSPEND: /* Nothing to do here. */ break; diff --git a/lib/libc_r/uthread/uthread_kill.c b/lib/libc_r/uthread/uthread_kill.c index 98b3a2d39b9..292ba5caf8f 100644 --- a/lib/libc_r/uthread/uthread_kill.c +++ b/lib/libc_r/uthread/uthread_kill.c @@ -46,18 +46,48 @@ pthread_kill(pthread_t pthread, int sig) /* Invalid signal: */ ret = EINVAL; + /* Ignored signals get dropped on the floor. */ + else if (_thread_sigact[sig - 1].sa_handler == SIG_IGN) + ret = 0; + /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { - if ((pthread->state == PS_SIGWAIT) && - sigismember(&pthread->sigmask, sig)) { - /* Change the state of the thread to run: */ - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + switch (pthread->state) { + case PS_SIGSUSPEND: + /* + * Only wake up the thread if the signal is unblocked + * and there is a handler installed for the signal. + */ + if (!sigismember(&pthread->sigmask, sig) && + _thread_sigact[sig - 1].sa_handler != SIG_DFL) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + /* Increment the pending signal count: */ + sigaddset(&pthread->sigpend,sig); + break; + + case PS_SIGWAIT: + /* Wake up the thread if the signal is blocked. */ + if (sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend,sig); + break; - /* Return the signal number: */ - pthread->signo = sig; - } else + default: /* Increment the pending signal count: */ sigaddset(&pthread->sigpend,sig); + break; + } } /* Return the completion status: */ diff --git a/lib/libc_r/uthread/uthread_rwlock.c b/lib/libc_r/uthread/uthread_rwlock.c new file mode 100644 index 00000000000..bfdd0b61fc1 --- /dev/null +++ b/lib/libc_r/uthread/uthread_rwlock.c @@ -0,0 +1,336 @@ +/*- + * Copyright (c) 1998 Alex Nash + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $OpenBSD: uthread_rwlock.c,v 1.1 1998/11/09 03:13:20 d Exp $ + * $Id: uthread_rwlock.c,v 1.1 1998/11/09 03:13:20 d Exp $ + */ + +#ifdef _THREAD_SAFE +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +/* maximum number of times a read lock may be obtained */ +#define MAX_READ_LOCKS (INT_MAX - 1) + +static int init_static (pthread_rwlock_t *rwlock); + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static int +init_static (pthread_rwlock_t *rwlock) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*rwlock == NULL) + ret = pthread_rwlock_init(rwlock, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +int +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int ret; + + if (rwlock == NULL) + ret = EINVAL; + else { + pthread_rwlock_t prwlock; + + prwlock = *rwlock; + + pthread_mutex_destroy(&prwlock->lock); + pthread_cond_destroy(&prwlock->read_signal); + pthread_cond_destroy(&prwlock->write_signal); + free(prwlock); + + *rwlock = NULL; + + ret = 0; + } + + return(ret); +} + +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + pthread_rwlock_t prwlock; + int ret; + + /* allocate rwlock object */ + prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock)); + + if (prwlock == NULL) + return(ENOMEM); + + /* initialize the lock */ + if ((ret = pthread_mutex_init(&prwlock->lock, NULL)) != 0) + free(prwlock); + else { + /* initialize the read condition signal */ + ret = pthread_cond_init(&prwlock->read_signal, NULL); + + if (ret != 0) { + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* initialize the write condition signal */ + ret = pthread_cond_init(&prwlock->write_signal, NULL); + + if (ret != 0) { + pthread_cond_destroy(&prwlock->read_signal); + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* success */ + prwlock->state = 0; + prwlock->blocked_writers = 0; + + *rwlock = prwlock; + } + } + } + + return(ret); +} + +int +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + ret = pthread_cond_wait(&prwlock->read_signal, &prwlock->lock); + + if (ret != 0) { + /* can't do a whole lot if this fails */ + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + } + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + if (prwlock->blocked_writers || prwlock->state < 0) + ret = EWOULDBLOCK; + else if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; /* too many read locks acquired */ + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state != 0) + ret = EWOULDBLOCK; + else + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state > 0) { + if (--prwlock->state == 0 && prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + else + ret = pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + while (prwlock->state != 0) { + ++prwlock->blocked_writers; + + ret = pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); + + if (ret != 0) { + --prwlock->blocked_writers; + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + + --prwlock->blocked_writers; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +#endif /* _THREAD_SAFE */ diff --git a/lib/libc_r/uthread/uthread_rwlockattr.c b/lib/libc_r/uthread/uthread_rwlockattr.c new file mode 100644 index 00000000000..3c16b77b8f5 --- /dev/null +++ b/lib/libc_r/uthread/uthread_rwlockattr.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 1998 Alex Nash + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: uthread_rwlockattr.c,v 1.1 1998/11/09 03:13:20 d Exp $ + * $OpenBSD: uthread_rwlockattr.c,v 1.1 1998/11/09 03:13:20 d Exp $ + */ + +#ifdef _THREAD_SAFE +#include <errno.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = *rwlockattr; + + if (prwlockattr == NULL) + return(EINVAL); + + free(prwlockattr); + + return(0); +} + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *rwlockattr, + int *pshared) +{ + *pshared = (*rwlockattr)->pshared; + + return(0); +} + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = (pthread_rwlockattr_t) + malloc(sizeof(struct pthread_rwlockattr)); + + if (prwlockattr == NULL) + return(ENOMEM); + + prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE; + *rwlockattr = prwlockattr; + + return(0); +} + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *rwlockattr, + int *pshared) +{ + int ps = *pshared; + + /* only PTHREAD_PROCESS_PRIVATE is supported */ + if (ps != PTHREAD_PROCESS_PRIVATE) + return(EINVAL); + + (*rwlockattr)->pshared = ps; + + return(0); +} + +#endif /* _THREAD_SAFE */ diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c index 7f13cd6dde1..3e55d6505a3 100644 --- a/lib/libc_r/uthread/uthread_sig.c +++ b/lib/libc_r/uthread/uthread_sig.c @@ -39,9 +39,7 @@ #include "pthread_private.h" /* Static variables: */ -static int volatile yield_on_unlock_dead = 0; static int volatile yield_on_unlock_thread = 0; -static spinlock_t thread_dead_lock = _SPINLOCK_INITIALIZER; static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER; /* Lock the thread list: */ @@ -52,14 +50,6 @@ _lock_thread_list() _SPINLOCK(&thread_link_list_lock); } -/* Lock the dead thread list: */ -void -_lock_dead_thread_list() -{ - /* Lock the dead thread list: */ - _SPINLOCK(&thread_dead_lock); -} - /* Lock the thread list: */ void _unlock_thread_list() @@ -80,26 +70,6 @@ _unlock_thread_list() } } -/* Lock the dead thread list: */ -void -_unlock_dead_thread_list() -{ - /* Unlock the dead thread list: */ - _SPINUNLOCK(&thread_dead_lock); - - /* - * Check if a scheduler interrupt occurred while the dead - * thread list was locked: - */ - if (yield_on_unlock_dead) { - /* Reset the interrupt flag: */ - yield_on_unlock_dead = 0; - - /* This thread has overstayed it's welcome: */ - sched_yield(); - } -} - void _thread_sig_handler(int sig, int code, struct sigcontext * scp) { @@ -144,18 +114,6 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) */ yield_on_unlock_thread = 1; - /* Check if the scheduler interrupt has come at an - * unfortunate time which one of the threads is - * modifying the dead thread list: - */ - if (thread_dead_lock.access_lock) - /* - * Set a flag so that the thread that has - * the lock yields when it unlocks the - * dead thread list: - */ - yield_on_unlock_dead = 1; - /* * Check if the kernel has not been interrupted while * executing scheduler code: @@ -198,7 +156,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) /* * POSIX says that pending SIGCONT signals are - * discarded when one of there signals occurs. + * discarded when one of these signals occurs. */ if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) { /* @@ -221,7 +179,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp) for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) { if ((pthread->state == PS_SIGWAIT) && - sigismember(&pthread->sigmask, sig)) { + sigismember(pthread->data.sigwait, sig)) { /* Change the state of the thread to run: */ PTHREAD_NEW_STATE(pthread,PS_RUNNING); @@ -325,6 +283,21 @@ _thread_signal(pthread_t pthread, int sig) pthread->signo = sig; } break; + + case PS_SIGSUSPEND: + /* + * Only wake up the thread if the signal is unblocked + * and there is a handler installed for the signal. + */ + if (!sigismember(&pthread->sigmask, sig) && + _thread_sigact[sig - 1].sa_handler != SIG_DFL) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; } } diff --git a/lib/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c index 3538f276eba..40f3850008e 100644 --- a/lib/libc_r/uthread/uthread_sigaction.c +++ b/lib/libc_r/uthread/uthread_sigaction.c @@ -75,7 +75,7 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact) sig != SIGINFO) { /* Initialise the global signal action structure: */ gact.sa_mask = act->sa_mask; - gact.sa_flags = act->sa_flags | SA_RESTART; + gact.sa_flags = 0; /* * Check if the signal handler is being set to diff --git a/lib/libc_r/uthread/uthread_sigaltstack.c b/lib/libc_r/uthread/uthread_sigaltstack.c new file mode 100644 index 00000000000..9a1f9614542 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigaltstack.c @@ -0,0 +1,21 @@ +/* + * $OpenBSD: uthread_sigaltstack.c,v 1.1 1998/11/09 03:13:20 d Exp $ + */ + +#include <signal.h> +#include <errno.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" + +/* + * placeholder for sigaltstack XXX impl to be done + */ + +int +sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss) +{ + errno = EINVAL; + return (-1); +} +#endif /* _THREAD_SAFE */ diff --git a/lib/libc_r/uthread/uthread_signal.c b/lib/libc_r/uthread/uthread_signal.c index cef725f7360..c9ece329762 100644 --- a/lib/libc_r/uthread/uthread_signal.c +++ b/lib/libc_r/uthread/uthread_signal.c @@ -44,7 +44,7 @@ _thread_sys_signal(int s, sig_t a) /* Initialise the signal action structure: */ sigemptyset(&sa.sa_mask); sa.sa_handler = a; - sa.sa_flags = SA_RESTART; + sa.sa_flags = 0; /* Perform the sigaction syscall: */ if (_thread_sys_sigaction(s, &sa, &osa) < 0) { diff --git a/lib/libc_r/uthread/uthread_sigsuspend.c b/lib/libc_r/uthread/uthread_sigsuspend.c index f7a7b123e34..0ae9a4f7b3e 100644 --- a/lib/libc_r/uthread/uthread_sigsuspend.c +++ b/lib/libc_r/uthread/uthread_sigsuspend.c @@ -44,14 +44,14 @@ sigsuspend(const sigset_t * set) /* Check if a new signal set was provided by the caller: */ if (set != NULL) { - /* Save the current sigmal mask: */ + /* Save the current signal mask: */ oset = _thread_run->sigmask; - /* Combine the caller's mask with the current one: */ - _thread_run->sigmask |= *set; + /* Change the caller's mask: */ + _thread_run->sigmask = *set; /* Wait for a signal: */ - _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); + _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__); /* Always return an interrupted error: */ errno = EINTR; diff --git a/lib/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c index f441fa3b731..e8d6d4ae0ca 100644 --- a/lib/libc_r/uthread/uthread_sigwait.c +++ b/lib/libc_r/uthread/uthread_sigwait.c @@ -41,7 +41,7 @@ sigwait(const sigset_t * set, int *sig) { int ret = 0; int i; - sigset_t oset; + sigset_t tempset; struct sigaction act; /* @@ -60,31 +60,48 @@ sigwait(const sigset_t * set, int *sig) sigdelset(&act.sa_mask, SIGCHLD); sigdelset(&act.sa_mask, SIGINFO); + /* Check to see if a pending signal is in the wait mask. */ + if ((tempset = (_thread_run->sigpend & act.sa_mask))) { + /* Enter a loop to find a pending signal: */ + for (i = 1; i < NSIG; i++) { + if (sigismember (&tempset, i)) + break; + } + + /* Clear the pending signal: */ + sigdelset(&_thread_run->sigpend,i); + + /* Return the signal number to the caller: */ + *sig = i; + + return (0); + } + /* * Enter a loop to find the signals that are SIG_DFL. For * these signals we must install a dummy signal handler in * order for the kernel to pass them in to us. POSIX says * that the application must explicitly install a dummy * handler for signals that are SIG_IGN in order to sigwait - * on them, so we ignore SIG_IGN signals. + * on them. Note that SIG_IGN signals are left in the + * mask because a subsequent sigaction could enable an + * ignored signal. */ for (i = 1; i < NSIG; i++) { if (sigismember(&act.sa_mask, i)) { - if (_thread_sigact[i - 1].sa_handler == SIG_DFL) { + if (_thread_sigact[i - 1].sa_handler == SIG_DFL) if (_thread_sys_sigaction(i,&act,NULL) != 0) ret = -1; - } - else if (_thread_sigact[i - 1].sa_handler == SIG_IGN) - sigdelset(&act.sa_mask, i); } } if (ret == 0) { - /* Save the current signal mask: */ - oset = _thread_run->sigmask; - - /* Combine the caller's mask with the current one: */ - _thread_run->sigmask |= act.sa_mask; + /* + * Save the wait signal mask. The wait signal + * mask is independent of the threads signal mask + * and requires separate storage. + */ + _thread_run->data.sigwait = &act.sa_mask; /* Wait for a signal: */ _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); @@ -92,8 +109,11 @@ sigwait(const sigset_t * set, int *sig) /* Return the signal number to the caller: */ *sig = _thread_run->signo; - /* Restore the signal mask: */ - _thread_run->sigmask = oset; + /* + * Probably unnecessary, but since it's in a union struct + * we don't know how it could be used in the future. + */ + _thread_run->data.sigwait = NULL; } /* Restore the sigactions: */ diff --git a/lib/libc_r/uthread/uthread_spec.c b/lib/libc_r/uthread/uthread_spec.c index 081a000788d..1fe789e6201 100644 --- a/lib/libc_r/uthread/uthread_spec.c +++ b/lib/libc_r/uthread/uthread_spec.c @@ -119,10 +119,12 @@ _thread_cleanupspecific(void) destructor(data); } else { free(_thread_run->specific_data); + _thread_run->specific_data = NULL; return; } } } + _thread_run->specific_data = NULL; free(_thread_run->specific_data); } diff --git a/lib/libc_r/uthread/uthread_spinlock.c b/lib/libc_r/uthread/uthread_spinlock.c index 1863bdfef9a..559f2d4c4b4 100644 --- a/lib/libc_r/uthread/uthread_spinlock.c +++ b/lib/libc_r/uthread/uthread_spinlock.c @@ -29,16 +29,16 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_spinlock.c,v 1.1 1998/08/27 09:01:25 d Exp $ - * $OpenBSD: uthread_spinlock.c,v 1.1 1998/08/27 09:01:25 d Exp $ + * $Id: uthread_spinlock.c,v 1.2 1998/11/09 03:13:21 d Exp $ + * $OpenBSD: uthread_spinlock.c,v 1.2 1998/11/09 03:13:21 d Exp $ * */ #include <stdio.h> #include <sched.h> #include <unistd.h> -#include <string.h> #include <pthread.h> +#include <string.h> #include "pthread_private.h" extern char *__progname; @@ -80,7 +80,7 @@ _spinlock(spinlock_t *lck) * returning. */ void -_spinlock_debug(spinlock_t *lck, char *fname, int lineno) +_spinlock_debug(spinlock_t *lck, const char *fname, int lineno) { /* * Try to grab the lock and loop if another thread grabs diff --git a/lib/libc_r/uthread/uthread_vfork.c b/lib/libc_r/uthread/uthread_vfork.c new file mode 100644 index 00000000000..a3b0ee5bb06 --- /dev/null +++ b/lib/libc_r/uthread/uthread_vfork.c @@ -0,0 +1,12 @@ +/* + * $OpenBSD: uthread_vfork.c,v 1.1 1998/11/09 03:13:21 d Exp $ + */ +#include <unistd.h> +#ifdef _THREAD_SAFE + +int +vfork(void) +{ + return (fork()); +} +#endif /* _THREAD_SAFE */ |