summaryrefslogtreecommitdiff
path: root/lib/libc_r
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc_r')
-rw-r--r--lib/libc_r/Makefile6
-rw-r--r--lib/libc_r/TODO19
-rw-r--r--lib/libc_r/arch/i386/uthread_machdep.h5
-rw-r--r--lib/libc_r/arch/mips/_atomic_lock.S35
-rw-r--r--lib/libc_r/arch/mips/uthread_machdep.h36
-rw-r--r--lib/libc_r/include/pthread.h45
-rw-r--r--lib/libc_r/man/Makefile.inc13
-rw-r--r--lib/libc_r/man/pread.336
-rw-r--r--lib/libc_r/man/pthread_cleanup_pop.31
-rw-r--r--lib/libc_r/man/pthread_cleanup_push.31
-rw-r--r--lib/libc_r/man/pthread_cond_broadcast.37
-rw-r--r--lib/libc_r/man/pthread_cond_destroy.37
-rw-r--r--lib/libc_r/man/pthread_cond_init.37
-rw-r--r--lib/libc_r/man/pthread_cond_signal.37
-rw-r--r--lib/libc_r/man/pthread_cond_timedwait.37
-rw-r--r--lib/libc_r/man/pthread_cond_wait.37
-rw-r--r--lib/libc_r/man/pthread_create.35
-rw-r--r--lib/libc_r/man/pthread_detach.31
-rw-r--r--lib/libc_r/man/pthread_equal.31
-rw-r--r--lib/libc_r/man/pthread_exit.31
-rw-r--r--lib/libc_r/man/pthread_getspecific.35
-rw-r--r--lib/libc_r/man/pthread_join.31
-rw-r--r--lib/libc_r/man/pthread_key_create.31
-rw-r--r--lib/libc_r/man/pthread_key_delete.31
-rw-r--r--lib/libc_r/man/pthread_mutex_destroy.35
-rw-r--r--lib/libc_r/man/pthread_mutex_init.35
-rw-r--r--lib/libc_r/man/pthread_mutex_lock.37
-rw-r--r--lib/libc_r/man/pthread_mutex_trylock.37
-rw-r--r--lib/libc_r/man/pthread_mutex_unlock.37
-rw-r--r--lib/libc_r/man/pthread_once.32
-rw-r--r--lib/libc_r/man/pthread_rwlock_destroy.381
-rw-r--r--lib/libc_r/man/pthread_rwlock_init.3100
-rw-r--r--lib/libc_r/man/pthread_rwlock_rdlock.3123
-rw-r--r--lib/libc_r/man/pthread_rwlock_unlock.380
-rw-r--r--lib/libc_r/man/pthread_rwlock_wrlock.3103
-rw-r--r--lib/libc_r/man/pthread_rwlockattr_destroy.369
-rw-r--r--lib/libc_r/man/pthread_rwlockattr_getpshared.381
-rw-r--r--lib/libc_r/man/pthread_rwlockattr_init.368
-rw-r--r--lib/libc_r/man/pthread_rwlockattr_setpshared.387
-rw-r--r--lib/libc_r/man/pthread_self.31
-rw-r--r--lib/libc_r/man/pthread_setspecific.31
-rw-r--r--lib/libc_r/man/pwrite.336
-rw-r--r--lib/libc_r/test/Makefile8
-rw-r--r--lib/libc_r/test/sigsuspend/Makefile8
-rw-r--r--lib/libc_r/test/sigsuspend/sigsuspend.c273
-rw-r--r--lib/libc_r/test/sigwait/Makefile8
-rw-r--r--lib/libc_r/test/sigwait/sigwait.c295
-rw-r--r--lib/libc_r/uthread/Makefile.inc9
-rw-r--r--lib/libc_r/uthread/pthread_private.h52
-rw-r--r--lib/libc_r/uthread/uthread_close.c1
-rw-r--r--lib/libc_r/uthread/uthread_cond.c4
-rw-r--r--lib/libc_r/uthread/uthread_create.c21
-rw-r--r--lib/libc_r/uthread/uthread_detach.c1
-rw-r--r--lib/libc_r/uthread/uthread_dup2.c17
-rw-r--r--lib/libc_r/uthread/uthread_execve.c2
-rw-r--r--lib/libc_r/uthread/uthread_exit.c68
-rw-r--r--lib/libc_r/uthread/uthread_fcntl.c1
-rw-r--r--lib/libc_r/uthread/uthread_fd.c9
-rw-r--r--lib/libc_r/uthread/uthread_file.c29
-rw-r--r--lib/libc_r/uthread/uthread_find_thread.c15
-rw-r--r--lib/libc_r/uthread/uthread_fork.c8
-rw-r--r--lib/libc_r/uthread/uthread_gc.c278
-rw-r--r--lib/libc_r/uthread/uthread_info.c40
-rw-r--r--lib/libc_r/uthread/uthread_init.c35
-rw-r--r--lib/libc_r/uthread/uthread_kern.c104
-rw-r--r--lib/libc_r/uthread/uthread_kill.c44
-rw-r--r--lib/libc_r/uthread/uthread_rwlock.c336
-rw-r--r--lib/libc_r/uthread/uthread_rwlockattr.c99
-rw-r--r--lib/libc_r/uthread/uthread_sig.c61
-rw-r--r--lib/libc_r/uthread/uthread_sigaction.c2
-rw-r--r--lib/libc_r/uthread/uthread_sigaltstack.c21
-rw-r--r--lib/libc_r/uthread/uthread_signal.c2
-rw-r--r--lib/libc_r/uthread/uthread_sigsuspend.c8
-rw-r--r--lib/libc_r/uthread/uthread_sigwait.c46
-rw-r--r--lib/libc_r/uthread/uthread_spec.c2
-rw-r--r--lib/libc_r/uthread/uthread_spinlock.c8
-rw-r--r--lib/libc_r/uthread/uthread_vfork.c12
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 */