From 71b3fa151e714295cd932238bb91973cd4a02c55 Mon Sep 17 00:00:00 2001 From: David Xu Date: Tue, 1 Feb 2005 12:38:27 +0000 Subject: [PATCH] Import initial version of 1:1 pthread library. --- lib/libthread_xu/Makefile | 38 + lib/libthread_xu/arch/Makefile.inc | 5 + lib/libthread_xu/arch/alpha/Makefile.inc | 5 + .../arch/alpha/alpha/pthread_md.c | 52 + .../arch/alpha/include/pthread_md.h | 82 + lib/libthread_xu/arch/amd64/Makefile.inc | 5 + .../arch/amd64/amd64/pthread_md.c | 62 + .../arch/amd64/include/pthread_md.h | 114 ++ lib/libthread_xu/arch/i386/Makefile.inc | 5 + lib/libthread_xu/arch/i386/i386/pthread_md.c | 181 ++ .../arch/i386/include/pthread_md.h | 141 ++ lib/libthread_xu/pthread.map | 372 ++++ lib/libthread_xu/sys/Makefile.inc | 5 + lib/libthread_xu/sys/thr_error.c | 53 + lib/libthread_xu/thread/Makefile.inc | 51 + lib/libthread_xu/thread/thr_attr.c | 532 ++++++ lib/libthread_xu/thread/thr_barrier.c | 108 ++ lib/libthread_xu/thread/thr_barrierattr.c | 94 + lib/libthread_xu/thread/thr_cancel.c | 161 ++ lib/libthread_xu/thread/thr_clean.c | 75 + lib/libthread_xu/thread/thr_concurrency.c | 62 + lib/libthread_xu/thread/thr_cond.c | 347 ++++ lib/libthread_xu/thread/thr_condattr.c | 122 ++ lib/libthread_xu/thread/thr_create.c | 252 +++ lib/libthread_xu/thread/thr_detach.c | 73 + lib/libthread_xu/thread/thr_equal.c | 45 + lib/libthread_xu/thread/thr_exit.c | 146 ++ lib/libthread_xu/thread/thr_fork.c | 228 +++ lib/libthread_xu/thread/thr_getprio.c | 57 + lib/libthread_xu/thread/thr_getschedparam.c | 76 + lib/libthread_xu/thread/thr_info.c | 200 ++ lib/libthread_xu/thread/thr_init.c | 415 ++++ lib/libthread_xu/thread/thr_join.c | 104 + lib/libthread_xu/thread/thr_kern.c | 105 ++ lib/libthread_xu/thread/thr_kill.c | 66 + lib/libthread_xu/thread/thr_list.c | 334 ++++ lib/libthread_xu/thread/thr_main_np.c | 48 + lib/libthread_xu/thread/thr_multi_np.c | 51 + lib/libthread_xu/thread/thr_mutex.c | 1676 +++++++++++++++++ .../thread/thr_mutex_prioceiling.c | 116 ++ lib/libthread_xu/thread/thr_mutex_protocol.c | 71 + lib/libthread_xu/thread/thr_mutexattr.c | 168 ++ lib/libthread_xu/thread/thr_once.c | 96 + lib/libthread_xu/thread/thr_printf.c | 136 ++ lib/libthread_xu/thread/thr_private.h | 850 +++++++++ lib/libthread_xu/thread/thr_pspinlock.c | 134 ++ lib/libthread_xu/thread/thr_resume_np.c | 91 + lib/libthread_xu/thread/thr_rtld.c | 148 ++ lib/libthread_xu/thread/thr_rwlock.c | 424 +++++ lib/libthread_xu/thread/thr_rwlockattr.c | 99 + lib/libthread_xu/thread/thr_self.c | 47 + lib/libthread_xu/thread/thr_sem.c | 251 +++ lib/libthread_xu/thread/thr_seterrno.c | 58 + lib/libthread_xu/thread/thr_setprio.c | 53 + lib/libthread_xu/thread/thr_setschedparam.c | 135 ++ lib/libthread_xu/thread/thr_sig.c | 247 +++ lib/libthread_xu/thread/thr_single_np.c | 50 + lib/libthread_xu/thread/thr_spec.c | 228 +++ lib/libthread_xu/thread/thr_spinlock.c | 125 ++ lib/libthread_xu/thread/thr_stack.c | 254 +++ lib/libthread_xu/thread/thr_suspend_np.c | 98 + lib/libthread_xu/thread/thr_switch_np.c | 54 + lib/libthread_xu/thread/thr_symbols.c | 63 + lib/libthread_xu/thread/thr_syscalls.c | 612 ++++++ lib/libthread_xu/thread/thr_umtx.c | 242 +++ lib/libthread_xu/thread/thr_umtx.h | 86 + lib/libthread_xu/thread/thr_yield.c | 45 + 67 files changed, 11529 insertions(+) create mode 100644 lib/libthread_xu/Makefile create mode 100644 lib/libthread_xu/arch/Makefile.inc create mode 100644 lib/libthread_xu/arch/alpha/Makefile.inc create mode 100644 lib/libthread_xu/arch/alpha/alpha/pthread_md.c create mode 100644 lib/libthread_xu/arch/alpha/include/pthread_md.h create mode 100644 lib/libthread_xu/arch/amd64/Makefile.inc create mode 100644 lib/libthread_xu/arch/amd64/amd64/pthread_md.c create mode 100644 lib/libthread_xu/arch/amd64/include/pthread_md.h create mode 100644 lib/libthread_xu/arch/i386/Makefile.inc create mode 100644 lib/libthread_xu/arch/i386/i386/pthread_md.c create mode 100644 lib/libthread_xu/arch/i386/include/pthread_md.h create mode 100644 lib/libthread_xu/pthread.map create mode 100644 lib/libthread_xu/sys/Makefile.inc create mode 100644 lib/libthread_xu/sys/thr_error.c create mode 100644 lib/libthread_xu/thread/Makefile.inc create mode 100644 lib/libthread_xu/thread/thr_attr.c create mode 100644 lib/libthread_xu/thread/thr_barrier.c create mode 100644 lib/libthread_xu/thread/thr_barrierattr.c create mode 100644 lib/libthread_xu/thread/thr_cancel.c create mode 100644 lib/libthread_xu/thread/thr_clean.c create mode 100644 lib/libthread_xu/thread/thr_concurrency.c create mode 100644 lib/libthread_xu/thread/thr_cond.c create mode 100644 lib/libthread_xu/thread/thr_condattr.c create mode 100644 lib/libthread_xu/thread/thr_create.c create mode 100644 lib/libthread_xu/thread/thr_detach.c create mode 100644 lib/libthread_xu/thread/thr_equal.c create mode 100644 lib/libthread_xu/thread/thr_exit.c create mode 100644 lib/libthread_xu/thread/thr_fork.c create mode 100644 lib/libthread_xu/thread/thr_getprio.c create mode 100644 lib/libthread_xu/thread/thr_getschedparam.c create mode 100644 lib/libthread_xu/thread/thr_info.c create mode 100644 lib/libthread_xu/thread/thr_init.c create mode 100644 lib/libthread_xu/thread/thr_join.c create mode 100644 lib/libthread_xu/thread/thr_kern.c create mode 100644 lib/libthread_xu/thread/thr_kill.c create mode 100644 lib/libthread_xu/thread/thr_list.c create mode 100644 lib/libthread_xu/thread/thr_main_np.c create mode 100644 lib/libthread_xu/thread/thr_multi_np.c create mode 100644 lib/libthread_xu/thread/thr_mutex.c create mode 100644 lib/libthread_xu/thread/thr_mutex_prioceiling.c create mode 100644 lib/libthread_xu/thread/thr_mutex_protocol.c create mode 100644 lib/libthread_xu/thread/thr_mutexattr.c create mode 100644 lib/libthread_xu/thread/thr_once.c create mode 100644 lib/libthread_xu/thread/thr_printf.c create mode 100644 lib/libthread_xu/thread/thr_private.h create mode 100644 lib/libthread_xu/thread/thr_pspinlock.c create mode 100644 lib/libthread_xu/thread/thr_resume_np.c create mode 100644 lib/libthread_xu/thread/thr_rtld.c create mode 100644 lib/libthread_xu/thread/thr_rwlock.c create mode 100644 lib/libthread_xu/thread/thr_rwlockattr.c create mode 100644 lib/libthread_xu/thread/thr_self.c create mode 100644 lib/libthread_xu/thread/thr_sem.c create mode 100644 lib/libthread_xu/thread/thr_seterrno.c create mode 100644 lib/libthread_xu/thread/thr_setprio.c create mode 100644 lib/libthread_xu/thread/thr_setschedparam.c create mode 100644 lib/libthread_xu/thread/thr_sig.c create mode 100644 lib/libthread_xu/thread/thr_single_np.c create mode 100644 lib/libthread_xu/thread/thr_spec.c create mode 100644 lib/libthread_xu/thread/thr_spinlock.c create mode 100644 lib/libthread_xu/thread/thr_stack.c create mode 100644 lib/libthread_xu/thread/thr_suspend_np.c create mode 100644 lib/libthread_xu/thread/thr_switch_np.c create mode 100644 lib/libthread_xu/thread/thr_symbols.c create mode 100644 lib/libthread_xu/thread/thr_syscalls.c create mode 100644 lib/libthread_xu/thread/thr_umtx.c create mode 100644 lib/libthread_xu/thread/thr_umtx.h create mode 100644 lib/libthread_xu/thread/thr_yield.c diff --git a/lib/libthread_xu/Makefile b/lib/libthread_xu/Makefile new file mode 100644 index 0000000000..554043fec7 --- /dev/null +++ b/lib/libthread_xu/Makefile @@ -0,0 +1,38 @@ +# $FreeBSD: src/lib/libpthread/Makefile,v 1.53 2004/10/24 15:32:32 ru Exp $ +# $DragonFly: src/lib/libthread_xu/Makefile,v 1.1 2005/02/01 12:38:26 davidxu Exp $ +# +# All library objects contain FreeBSD revision strings by default; they may be +# excluded as a space-saving measure. To produce a library that does +# not contain these strings, add -DSTRIP_FBSDID (see ) to CFLAGS +# below. Note, there are no IDs for syscall stubs whose sources are generated. +# To included legacy CSRG sccsid strings, add -DLIBC_SCCS and -DSYSLIBC_SCCS +# (for system call stubs) to CFLAGS below. -DSYSLIBC_SCCS affects just the +# system call stubs. +LIB=thread_xu +SHLIB_MAJOR= 1 +SHLIB_MINOR= 0 +CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE +CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \ + -I${.CURDIR}/../../include +CFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}/include +CFLAGS+=-I${.CURDIR}/sys +CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf +CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_ARCH} +CFLAGS+=-Winline + +CFLAGS+= -g + +# CFLAGS+=-DSYSTEM_SCOPE_ONLY + +LDFLAGS=--version-script=${.CURDIR}/pthread.map + +# enable extra internal consistancy checks +CFLAGS+=-D_PTHREADS_INVARIANTS -Wall + +PRECIOUSLIB= yes + +.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc" +.include "${.CURDIR}/sys/Makefile.inc" +.include "${.CURDIR}/thread/Makefile.inc" + +.include diff --git a/lib/libthread_xu/arch/Makefile.inc b/lib/libthread_xu/arch/Makefile.inc new file mode 100644 index 0000000000..9fa3c0d9c0 --- /dev/null +++ b/lib/libthread_xu/arch/Makefile.inc @@ -0,0 +1,5 @@ +# $DragonFly: src/lib/libthread_xu/arch/Makefile.inc,v 1.1 2005/02/01 12:38:26 davidxu Exp $ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthread_xu/arch/alpha/Makefile.inc b/lib/libthread_xu/arch/alpha/Makefile.inc new file mode 100644 index 0000000000..1c67f1415f --- /dev/null +++ b/lib/libthread_xu/arch/alpha/Makefile.inc @@ -0,0 +1,5 @@ +# $DragonFly: src/lib/libthread_xu/arch/alpha/Attic/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthread_xu/arch/alpha/alpha/pthread_md.c b/lib/libthread_xu/arch/alpha/alpha/pthread_md.c new file mode 100644 index 0000000000..39ca9fd19d --- /dev/null +++ b/lib/libthread_xu/arch/alpha/alpha/pthread_md.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003 Daniel Eischen + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $DragonFly: src/lib/libthread_xu/arch/alpha/alpha/Attic/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include "pthread_md.h" + +/* + * The constructors. + */ +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + + if ((tcb = malloc(sizeof(struct tcb))) != NULL) { + tcb->tcb_thread = thread; + } + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + free(tcb); +} diff --git a/lib/libthread_xu/arch/alpha/include/pthread_md.h b/lib/libthread_xu/arch/alpha/include/pthread_md.h new file mode 100644 index 0000000000..ee82b600f8 --- /dev/null +++ b/lib/libthread_xu/arch/alpha/include/pthread_md.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003 Marcel Moolenaar + * 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 ``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 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. + * + * $FreeBSD: src/lib/libpthread/arch/alpha/include/pthread_md.h,v 1.7 2004/08/16 14:07:38 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/arch/alpha/include/Attic/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include + +#define DTV_OFFSET offsetof(struct tcb, tcb_tdv) + +struct pthread; +struct tcb; +struct tdv; /* We don't know what this is yet? */ + +struct tcb { + struct tdv *tcb_tdv; /* dynamic TLS */ + struct pthread *tcb_thread; +}; + +#define _tp __builtin_thread_pointer() +#define _tcb ((struct tcb*)((char*)(_tp))) + +/* + * The constructors. + */ +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *); + +/* Called from the thread to set its private data. */ +static __inline void +_tcb_set(struct tcb *tcb) +{ + /* There is no thread yet; use the fake tcb. */ + __builtin_set_thread_pointer(tcb); +} + +/* + * Get the current tcb. + */ +static __inline struct tcb * +_tcb_get(void) +{ + return (_tcb); +} + +extern struct pthread *_thr_initial; + +static __inline struct pthread * +_get_curthread(void) +{ + if (_thr_initial) + return (_tcb->tcb_thread); + return (NULL); +} + +#endif /* _PTHREAD_MD_H_ */ diff --git a/lib/libthread_xu/arch/amd64/Makefile.inc b/lib/libthread_xu/arch/amd64/Makefile.inc new file mode 100644 index 0000000000..c641b7bf14 --- /dev/null +++ b/lib/libthread_xu/arch/amd64/Makefile.inc @@ -0,0 +1,5 @@ +# $DragonFly: src/lib/libthread_xu/arch/amd64/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthread_xu/arch/amd64/amd64/pthread_md.c b/lib/libthread_xu/arch/amd64/amd64/pthread_md.c new file mode 100644 index 0000000000..a9e1207ba9 --- /dev/null +++ b/lib/libthread_xu/arch/amd64/amd64/pthread_md.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003 Daniel Eischen + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $FreeBSD: src/lib/libpthread/arch/amd64/amd64/pthread_md.c,v 1.4 2004/11/06 03:33:19 peter Exp $ + * $DragonFly: src/lib/libthread_xu/arch/amd64/amd64/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include "rtld_tls.h" +#include "pthread_md.h" + +/* + * The constructors. + */ +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + void *oldtls; + + if (initial) { + __asm __volatile("movq %%fs:0, %0" : "=r" (oldtls)); + } else { + oldtls = NULL; + } + + tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); + if (tcb) { + tcb->tcb_thread = thread; + } + + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + _rtld_free_tls(tcb, sizeof(struct tcb), 16); +} diff --git a/lib/libthread_xu/arch/amd64/include/pthread_md.h b/lib/libthread_xu/arch/amd64/include/pthread_md.h new file mode 100644 index 0000000000..a3ea5d4128 --- /dev/null +++ b/lib/libthread_xu/arch/amd64/include/pthread_md.h @@ -0,0 +1,114 @@ +/*- + * Copyright (C) 2003 David Xu + * Copyright (c) 2001 Daniel Eischen + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE 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. + * + * $FreeBSD: src/lib/libpthread/arch/amd64/include/pthread_md.h,v 1.10 2004/08/25 23:42:40 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/arch/amd64/include/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* + * Machine-dependent thread prototypes/definitions for the thread kernel. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include +#include +#include +#include +#include + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +struct pthread; +struct tdv; + +/* + * %fs points to a struct tcb. + */ + +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; + void *tcb_spare[1]; /* align tcb_tmbx to 16 bytes */ +}; + +/* + * Evaluates to the byte offset of the per-kse variable name. + */ +#define __tcb_offset(name) __offsetof(struct tcb, name) + +/* + * Evaluates to the type of the per-kse variable name. + */ +#define __tcb_type(name) __typeof(((struct tcb *)0)->name) + +/* + * Evaluates to the value of the per-kse variable name. + */ +#define TCB_GET64(name) ({ \ + __tcb_type(name) __result; \ + \ + u_long __i; \ + __asm __volatile("movq %%fs:%1, %0" \ + : "=r" (__i) \ + : "m" (*(u_long *)(__tcb_offset(name)))); \ + __result = (__tcb_type(name))__i; \ + \ + __result; \ +}) + +/* + * The constructors. + */ +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *tcb); + +/* Called from the KSE to set its private data. */ +static __inline void +_tcb_set(struct tcb *tcb) +{ + amd64_set_fsbase(tcb); +} + +/* Get the current kcb. */ +static __inline struct tcb * +_tcb_get(void) +{ + return (TCB_GET64(tcb_self)); +} + +extern struct pthread *_thr_initial; + +/* Get the current thread. */ +static __inline struct pthread * +_get_curthread(void) +{ + if (_thr_initial) + return (TCB_GET64(tcb_thread)); + return (NULL); +} +#endif diff --git a/lib/libthread_xu/arch/i386/Makefile.inc b/lib/libthread_xu/arch/i386/Makefile.inc new file mode 100644 index 0000000000..cea024c7a3 --- /dev/null +++ b/lib/libthread_xu/arch/i386/Makefile.inc @@ -0,0 +1,5 @@ +# $DragonFly: src/lib/libthread_xu/arch/i386/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthread_xu/arch/i386/i386/pthread_md.c b/lib/libthread_xu/arch/i386/i386/pthread_md.c new file mode 100644 index 0000000000..c9adc203d6 --- /dev/null +++ b/lib/libthread_xu/arch/i386/i386/pthread_md.c @@ -0,0 +1,181 @@ +/*- + * Copyright (C) 2003 David Xu + * Copyright (c) 2001,2003 Daniel Eischen + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE 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. + * + * $DragonFly: src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef __DragonFly__ +#include "rtld_tls.h" +#endif + +#include "pthread_md.h" + +#ifdef __DragonFly__ + +#define LDT_ENTRIES 8192 +#define LDT_WORDS (8192/sizeof(unsigned int)) +#define LDT_RESERVED NLDT + +static unsigned int ldt_mask[LDT_WORDS]; +static int initialized = 0; + +static void initialize(void); + +static void +initialize(void) +{ + int i, j; + + memset(ldt_mask, 0xFF, sizeof(ldt_mask)); + /* Reserve system predefined LDT entries */ + for (i = 0; i < LDT_RESERVED; ++i) { + j = i / 32; + ldt_mask[j] &= ~(1 << (i % 32)); + } + initialized = 1; +} + +static u_int +alloc_ldt_entry(void) +{ + u_int i, j, index; + + index = 0; + for (i = 0; i < LDT_WORDS; ++i) { + if (ldt_mask[i] != 0) { + j = bsfl(ldt_mask[i]); + ldt_mask[i] &= ~(1 << j); + index = i * 32 + j; + break; + } + } + return (index); +} + +static void +free_ldt_entry(u_int index) +{ + u_int i, j; + + if (index < LDT_RESERVED || index >= LDT_ENTRIES) + return; + i = index / 32; + j = index % 32; + ldt_mask[i] |= (1 << j); +} + +#endif + +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ +#ifndef COMPAT_32BIT + union descriptor ldt; +#endif + struct tcb *tcb; + +#ifndef __DragonFly__ + void *oldtls; + + if (initial) + __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls)); + else + oldtls = NULL; + + tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); +#else + if (!initialized) + initialize(); + if ((tcb = malloc(sizeof(struct tcb))) == NULL) + return (NULL); + /* tcb_self and tcb_dtv should assigned by rtld tls code. */ + tcb->tcb_self = tcb; + tcb->tcb_dtv = NULL; + if ((tcb->tcb_ldt = alloc_ldt_entry()) == 0) { + free(tcb); + return (NULL); + } +#endif + + if (tcb) { + tcb->tcb_thread = thread; +#ifndef COMPAT_32BIT + ldt.sd.sd_hibase = (unsigned int)tcb >> 24; + ldt.sd.sd_lobase = (unsigned int)tcb & 0xFFFFFF; + ldt.sd.sd_hilimit = (sizeof(struct tcb) >> 16) & 0xF; + ldt.sd.sd_lolimit = sizeof(struct tcb) & 0xFFFF; + ldt.sd.sd_type = SDT_MEMRWA; + ldt.sd.sd_dpl = SEL_UPL; + ldt.sd.sd_p = 1; + ldt.sd.sd_xx = 0; + ldt.sd.sd_def32 = 1; + ldt.sd.sd_gran = 0; /* no more than 1M */ + +#ifdef __DragonFly__ + if (i386_set_ldt(tcb->tcb_ldt, &ldt, 1) == -1) { + free_ldt_entry(tcb->tcb_ldt); + free(tcb); + tcb = NULL; + } +#else + tcb->tcb_ldt = i386_set_ldt(LDT_AUTO_ALLOC, &ldt, 1); + if (tcb->tcb_ldt < 0) { + free(tcb); + tcb = NULL; + } +#endif +#endif + } + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ +#ifdef __DragonFly__ + if (tcb->tcb_ldt > 0) { + free_ldt_entry(tcb->tcb_ldt); + free(tcb); + } +#else +#ifndef COMPAT_32BIT + if (tcb->tcb_ldt > 0) + i386_set_ldt(tcb->tcb_ldt, NULL, 1); +#endif + _rtld_free_tls(tcb, sizeof(struct tcb), 16); +#endif +} diff --git a/lib/libthread_xu/arch/i386/include/pthread_md.h b/lib/libthread_xu/arch/i386/include/pthread_md.h new file mode 100644 index 0000000000..3398f8a6a4 --- /dev/null +++ b/lib/libthread_xu/arch/i386/include/pthread_md.h @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 2002 Daniel Eischen . + * Copyright (c) 2005 David Xu . + * 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. + * + * $FreeBSD: src/lib/libpthread/arch/i386/include/pthread_md.h,v 1.13 2004/11/06 03:35:51 peter Exp $ + * $DragonFly: src/lib/libthread_xu/arch/i386/include/pthread_md.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* + * Machine-dependent thread prototypes/definitions for the thread kernel. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include +#include +#include + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +struct pthread; + +/* + * %gs points to a struct tcb. + */ +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; + int tcb_ldt; +}; + +/* + * Evaluates to the byte offset of the per-thread variable name. + */ +#define __tcb_offset(name) __offsetof(struct tcb, name) + +/* + * Evaluates to the type of the per-thread variable name. + */ +#define __tcb_type(name) __typeof(((struct tcb *)0)->name) + +/* + * Evaluates to the value of the per-kse variable name. + */ +#define TCB_GET32(name) ({ \ + __tcb_type(name) __result; \ + \ + u_int __i; \ + __asm __volatile("movl %%gs:%1, %0" \ + : "=r" (__i) \ + : "m" (*(u_int *)(__tcb_offset(name)))); \ + __result = (__tcb_type(name))__i; \ + \ + __result; \ +}) + +#ifdef __DragonFly__ +static __inline int +atomic_cmpset_int(volatile int *dst, int exp, int src) +{ + int res = exp; + + __asm __volatile ( + " lock cmpxchgl %1,%2 ; " + " setz %%al ; " + " movzbl %%al,%0 ; " + "1: " + "# atomic_cmpset_int" + : "+a" (res) /* 0 (result) */ + : "r" (src), /* 1 */ + "m" (*(dst)) /* 2 */ + : "memory"); + + return (res); +} + +#define atomic_cmpset_acq_int atomic_cmpset_int +#endif + +/* + * The constructors. + */ +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *tcb); + +/* Called from the thread to set its private data. */ +static __inline void +_tcb_set(struct tcb *tcb) +{ +#ifndef COMPAT_32BIT + int val; + + val = (tcb->tcb_ldt << 3) | 7; + __asm __volatile("movl %0, %%gs" : : "r" (val)); +#else + _amd64_set_gsbase(tcb); +#endif + +} + +/* Get the current kcb. */ +static __inline struct tcb * +_tcb_get(void) +{ + return (TCB_GET32(tcb_self)); +} + +extern struct pthread *_thr_initial; + +/* Get the current thread. */ +static __inline struct pthread * +_get_curthread(void) +{ + if (_thr_initial) + return (TCB_GET32(tcb_thread)); + return (NULL); +} +#endif diff --git a/lib/libthread_xu/pthread.map b/lib/libthread_xu/pthread.map new file mode 100644 index 0000000000..b561c78e9b --- /dev/null +++ b/lib/libthread_xu/pthread.map @@ -0,0 +1,372 @@ +# $FreeBSD: src/lib/libpthread/pthread.map,v 1.13 2004/09/26 06:50:14 deischen Exp $ +# $DragonFly: src/lib/libthread_xu/pthread.map,v 1.1 2005/02/01 12:38:26 davidxu Exp $ + +LIBTHREAD_1_0 { +global: + ___creat; + __accept; + __close; + __connect; + __error; + __fcntl; + __fsync; + __msync; + __nanosleep; + __open; + __poll; + __pthread_cond_timedwait; + __pthread_cond_wait; + __pthread_mutex_init; + __pthread_mutex_lock; + __pthread_mutex_trylock; + __pthread_mutex_timedlock; + __read; + __readv; + __recvfrom; + __recvmsg; + __select; + __sendmsg; + __sendto; + __sigsuspend; + __wait4; + __write; + __writev; + _aio_suspend; + _execve; + _fork; + _nanosleep; + _pause; + _pselect; + _pthread_atfork; + _pthread_barrier_destroy; + _pthread_barrier_init; + _pthread_barrier_wait; + _pthread_barrierattr_destroy; + _pthread_barrierattr_getpshared; + _pthread_barrierattr_init; + _pthread_barrierattr_setpshared; + _pthread_attr_default; + _pthread_attr_destroy; + _pthread_attr_get_np; + _pthread_attr_getdetachstate; + _pthread_attr_getguardsize; + _pthread_attr_getinheritsched; + _pthread_attr_getschedparam; + _pthread_attr_getschedpolicy; + _pthread_attr_getscope; + _pthread_attr_getstack; + _pthread_attr_getstackaddr; + _pthread_attr_getstacksize; + _pthread_attr_init; + _pthread_attr_setcreatesuspend_np; + _pthread_attr_setdetachstate; + _pthread_attr_setguardsize; + _pthread_attr_setinheritsched; + _pthread_attr_setschedparam; + _pthread_attr_setschedpolicy; + _pthread_attr_setscope; + _pthread_attr_setstack; + _pthread_attr_setstackaddr; + _pthread_attr_setstacksize; + _pthread_cancel; + _pthread_cleanup_pop; + _pthread_cleanup_push; + _pthread_cond_broadcast; + _pthread_cond_destroy; + _pthread_cond_init; + _pthread_cond_signal; + _pthread_cond_timedwait; + _pthread_cond_wait; + _pthread_condattr_default; + _pthread_condattr_destroy; + _pthread_condattr_getclock; + _pthread_condattr_getpshared; + _pthread_condattr_init; + _pthread_condattr_setclock; + _pthread_condattr_setpshared; + _pthread_create; + _pthread_detach; + _pthread_equal; + _pthread_exit; + _pthread_getconcurrency; + _pthread_getprio; + _pthread_getschedparam; + _pthread_getspecific; + _pthread_join; + _pthread_key_create; + _pthread_key_delete; + _pthread_kill; + _pthread_main_np; + _pthread_multi_np; + _pthread_mutex_destroy; + _pthread_mutex_getprioceiling; + _pthread_mutex_init; + _pthread_mutex_lock; + _pthread_mutex_setprioceiling; + _pthread_mutex_timedlock; + _pthread_mutex_trylock; + _pthread_mutex_unlock; + _pthread_mutexattr_default; + _pthread_mutexattr_destroy; + _pthread_mutexattr_getkind_np; + _pthread_mutexattr_getprioceiling; + _pthread_mutexattr_getprotocol; + _pthread_mutexattr_gettype; + _pthread_mutexattr_init; + _pthread_mutexattr_setkind_np; + _pthread_mutexattr_setprioceiling; + _pthread_mutexattr_setprotocol; + _pthread_mutexattr_settype; + _pthread_once; + _pthread_resume_all_np; + _pthread_resume_np; + _pthread_rwlock_destroy; + _pthread_rwlock_init; + _pthread_rwlock_rdlock; + _pthread_rwlock_timedrdlock; + _pthread_rwlock_timedwrlock; + _pthread_rwlock_tryrdlock; + _pthread_rwlock_trywrlock; + _pthread_rwlock_unlock; + _pthread_rwlock_wrlock; + _pthread_rwlockattr_destroy; + _pthread_rwlockattr_getpshared; + _pthread_rwlockattr_init; + _pthread_rwlockattr_setpshared; + _pthread_self; + _pthread_set_name_np; + _pthread_setcancelstate; + _pthread_setcanceltype; + _pthread_setconcurrency; + _pthread_setprio; + _pthread_setschedparam; + _pthread_setspecific; + _pthread_sigmask; + _pthread_single_np; + _pthread_spin_destroy; + _pthread_spin_init; + _pthread_spin_lock; + _pthread_spin_trylock; + _pthread_spin_unlock; + _pthread_suspend_all_np; + _pthread_suspend_np; + _pthread_switch_add_np; + _pthread_switch_delete_np; + _pthread_testcancel; + _pthread_yield; + _raise; + _sem_close; + _sem_destroy; + _sem_getvalue; + _sem_init; + _sem_open; + _sem_post; + _sem_timedwait; + _sem_trywait; + _sem_unlink; + _sem_wait; + _sigaction; + _sigprocmask; + _sigsuspend; + _sigwait; + _sigtimedwait; + _sigwaitinfo; + _sleep; + _spinlock; + _spinlock_debug; + _spinunlock; + _system; + _tcdrain; + _vfork; + _wait; + _waitpid; + accept; + aio_suspend; + close; + connect; + creat; + execve; + fcntl; + fork; + fsync; + msync; + nanosleep; + open; + pause; + poll; + pselect; + pthread_atfork; + pthread_barrier_destroy; + pthread_barrier_init; + pthread_barrier_wait; + pthread_barrierattr_destroy; + pthread_barrierattr_getpshared; + pthread_barrierattr_init; + pthread_barrierattr_setpshared; + pthread_attr_destroy; + pthread_attr_get_np; + pthread_attr_getdetachstate; + pthread_attr_getguardsize; + pthread_attr_getinheritsched; + pthread_attr_getschedparam; + pthread_attr_getschedpolicy; + pthread_attr_getscope; + pthread_attr_getstack; + pthread_attr_getstackaddr; + pthread_attr_getstacksize; + pthread_attr_init; + pthread_attr_setcreatesuspend_np; + pthread_attr_setdetachstate; + pthread_attr_setguardsize; + pthread_attr_setinheritsched; + pthread_attr_setschedparam; + pthread_attr_setschedpolicy; + pthread_attr_setscope; + pthread_attr_setstack; + pthread_attr_setstackaddr; + pthread_attr_setstacksize; + pthread_cancel; + pthread_cleanup_pop; + pthread_cleanup_push; + pthread_cond_broadcast; + pthread_cond_destroy; + pthread_cond_init; + pthread_cond_signal; + pthread_cond_timedwait; + pthread_cond_wait; + pthread_condattr_destroy; + pthread_condattr_getclock; + pthread_condattr_getpshared; + pthread_condattr_init; + pthread_condattr_setclock; + pthread_condattr_setpshared; + pthread_create; + pthread_detach; + pthread_equal; + pthread_exit; + pthread_getconcurrency; + pthread_getprio; + pthread_getschedparam; + pthread_getspecific; + pthread_join; + pthread_key_create; + pthread_key_delete; + pthread_kill; + pthread_main_np; + pthread_multi_np; + pthread_mutex_destroy; + pthread_mutex_getprioceiling; + pthread_mutex_init; + pthread_mutex_lock; + pthread_mutex_setprioceiling; + pthread_mutex_timedlock; + pthread_mutex_trylock; + pthread_mutex_unlock; + pthread_mutexattr_destroy; + pthread_mutexattr_getkind_np; + pthread_mutexattr_getprioceiling; + pthread_mutexattr_getprotocol; + pthread_mutexattr_gettype; + pthread_mutexattr_init; + pthread_mutexattr_setkind_np; + pthread_mutexattr_setprioceiling; + pthread_mutexattr_setprotocol; + pthread_mutexattr_settype; + pthread_once; + pthread_resume_all_np; + pthread_resume_np; + pthread_rwlock_destroy; + pthread_rwlock_init; + pthread_rwlock_rdlock; + pthread_rwlock_timedrdlock; + pthread_rwlock_timedwrlock; + pthread_rwlock_tryrdlock; + pthread_rwlock_trywrlock; + pthread_rwlock_unlock; + pthread_rwlock_wrlock; + pthread_rwlockattr_destroy; + pthread_rwlockattr_getpshared; + pthread_rwlockattr_init; + pthread_rwlockattr_setpshared; + pthread_self; + pthread_set_name_np; + pthread_setcancelstate; + pthread_setcanceltype; + pthread_setconcurrency; + pthread_setprio; + pthread_setschedparam; + pthread_setspecific; + pthread_sigmask; + pthread_single_np; + pthread_spin_destroy; + pthread_spin_init; + pthread_spin_lock; + pthread_spin_trylock; + pthread_spin_unlock; + pthread_suspend_all_np; + pthread_suspend_np; + pthread_switch_add_np; + pthread_switch_delete_np; + pthread_testcancel; + pthread_yield; + raise; + read; + readv; + recvfrom; + recvmsg; + select; + sem_close; + sem_destroy; + sem_getvalue; + sem_init; + sem_open; + sem_post; + sem_timedwait; + sem_trywait; + sem_unlink; + sem_wait; + sendmsg; + sendto; + sigaction; + sigaltstack; + sigpending; + sigprocmask; + sigsuspend; + sigwait; + sigwaitinfo; + sigtimedwait; + sleep; + system; + tcdrain; + vfork; + wait; + wait4; + waitpid; + write; + writev; + + # Debugger needs these. + _libthread_xu_debug; + _thread_inited; + _thread_active_threads; + _thread_keytable; + _thread_list; + _thread_max_keys; + _thread_off_attr_flags; + _thread_off_dtv; + _thread_off_linkmap; + _thread_off_next; + _thread_off_tcb; + _thread_off_tid; + _thread_off_key_allocated; + _thread_off_key_destructor; + _thread_off_state; + _thread_off_thr_locklevel; + _thread_off_tlsindex; + _thread_off_isdead; + _thread_size_key; + _thread_state_running; + _thread_state_zoombie; +local: + *; +}; diff --git a/lib/libthread_xu/sys/Makefile.inc b/lib/libthread_xu/sys/Makefile.inc new file mode 100644 index 0000000000..712fbb19f7 --- /dev/null +++ b/lib/libthread_xu/sys/Makefile.inc @@ -0,0 +1,5 @@ +# $DragonFly: src/lib/libthread_xu/sys/Attic/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + +.PATH: ${.CURDIR}/sys + +SRCS+= thr_error.c diff --git a/lib/libthread_xu/sys/thr_error.c b/lib/libthread_xu/sys/thr_error.c new file mode 100644 index 0000000000..87a571a596 --- /dev/null +++ b/lib/libthread_xu/sys/thr_error.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995 John Birrell . + * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell + * and Chris Provenzano. + * 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. + * + * $FreeBSD: src/lib/libpthread/sys/thr_error.c,v 1.7 2003/04/23 21:46:50 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/sys/Attic/thr_error.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "libc_private.h" +#include "thr_private.h" + +#undef errno +extern int errno; + +int * +__error(void) +{ + struct pthread *curthread = _get_curthread(); + + if (curthread != NULL && curthread != _thr_initial) + return (&curthread->error); + else + return (&errno); +} diff --git a/lib/libthread_xu/thread/Makefile.inc b/lib/libthread_xu/thread/Makefile.inc new file mode 100644 index 0000000000..4c3e7db198 --- /dev/null +++ b/lib/libthread_xu/thread/Makefile.inc @@ -0,0 +1,51 @@ +# $DragonFly: src/lib/libthread_xu/thread/Makefile.inc,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + +# thr sources +.PATH: ${.CURDIR}/thread + +SRCS+= \ + thr_attr.c \ + thr_cancel.c \ + thr_clean.c \ + thr_concurrency.c \ + thr_cond.c \ + thr_condattr.c \ + thr_create.c \ + thr_detach.c \ + thr_equal.c \ + thr_exit.c \ + thr_fork.c \ + thr_getprio.c \ + thr_getschedparam.c \ + thr_init.c \ + thr_join.c \ + thr_list.c \ + thr_kern.c \ + thr_kill.c \ + thr_main_np.c \ + thr_multi_np.c \ + thr_mutex.c \ + thr_mutexattr.c \ + thr_mutex_prioceiling.c \ + thr_mutex_protocol.c \ + thr_once.c \ + thr_printf.c \ + thr_resume_np.c \ + thr_rwlock.c \ + thr_rwlockattr.c \ + thr_self.c \ + thr_sem.c \ + thr_seterrno.c \ + thr_setprio.c \ + thr_setschedparam.c \ + thr_sig.c \ + thr_single_np.c \ + thr_spec.c \ + thr_spinlock.c \ + thr_stack.c \ + thr_syscalls.c \ + thr_suspend_np.c \ + thr_switch_np.c \ + thr_symbols.c \ + thr_umtx.c \ + thr_yield.c diff --git a/lib/libthread_xu/thread/thr_attr.c b/lib/libthread_xu/thread/thr_attr.c new file mode 100644 index 0000000000..8ffb748de6 --- /dev/null +++ b/lib/libthread_xu/thread/thr_attr.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2003 Craig Rodrigues . + * 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 Craig Rodrigues. + * 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 CRAIG RODRIGUES 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. + * + */ + +/* + * Copyright (c) 1998 Daniel Eischen . + * Copyright (C) 2001 Jason Evans . + * Copyright (c) 2002,2003 Alexey Zelkin + * 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(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + */ + +/* + * Copyright (c) 1996 John Birrell . + * 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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_attr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include + +#include "thr_private.h" + +__weak_reference(_pthread_attr_destroy, pthread_attr_destroy); + +int +_pthread_attr_destroy(pthread_attr_t *attr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL) + /* Invalid argument: */ + ret = EINVAL; + else { + /* Free the memory allocated to the attribute object: */ + free(*attr); + + /* + * Leave the attribute pointer NULL now that the memory + * has been freed: + */ + *attr = NULL; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_get_np, pthread_attr_get_np); + +int +_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst) +{ + struct pthread *curthread; + struct pthread_attr attr; + int ret; + + if (pid == NULL || dst == NULL || *dst == NULL) + return (EINVAL); + + curthread = _get_curthread(); + if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0) + return (ret); + attr = pid->attr; + _thr_ref_delete(curthread, pid); + memcpy(*dst, &attr, sizeof(struct pthread_attr)); + + return (0); +} + +__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate); + +int +_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || detachstate == NULL) + ret = EINVAL; + else { + /* Check if the detached flag is set: */ + if ((*attr)->flags & PTHREAD_DETACHED) + /* Return detached: */ + *detachstate = PTHREAD_CREATE_DETACHED; + else + /* Return joinable: */ + *detachstate = PTHREAD_CREATE_JOINABLE; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize); + +int +_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || guardsize == NULL) + ret = EINVAL; + else { + /* Return the guard size: */ + *guardsize = (*attr)->guardsize_attr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched); + +int +_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else + *sched_inherit = (*attr)->sched_inherit; + + return(ret); +} + +__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam); + +int +_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (param == NULL)) + ret = EINVAL; + else + param->sched_priority = (*attr)->prio; + + return(ret); +} + +__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); + +int +_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (policy == NULL)) + ret = EINVAL; + else + *policy = (*attr)->sched_policy; + + return(ret); +} + +__weak_reference(_pthread_attr_getscope, pthread_attr_getscope); + +int +_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL)) + /* Return an invalid argument: */ + ret = EINVAL; + + else + *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ? + PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; + + return(ret); +} + +__weak_reference(_pthread_attr_getstack, pthread_attr_getstack); + +int +_pthread_attr_getstack(const pthread_attr_t * __restrict attr, + void ** __restrict stackaddr, + size_t * __restrict stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL + || stacksize == NULL ) + ret = EINVAL; + else { + /* Return the stack address and size */ + *stackaddr = (*attr)->stackaddr_attr; + *stacksize = (*attr)->stacksize_attr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr); + +int +_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Return the stack address: */ + *stackaddr = (*attr)->stackaddr_attr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize); + +int +_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize == NULL) + ret = EINVAL; + else { + /* Return the stack size: */ + *stacksize = (*attr)->stacksize_attr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_init, pthread_attr_init); + +int +_pthread_attr_init(pthread_attr_t *attr) +{ + int ret; + pthread_attr_t pattr; + + /* Allocate memory for the attribute object: */ + if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) + /* Insufficient memory: */ + ret = ENOMEM; + else { + /* Initialise the attribute object with the defaults: */ + memcpy(pattr, &_pthread_attr_default, + sizeof(struct pthread_attr)); + pattr->guardsize_attr = _thr_guard_default; + + /* Return a pointer to the attribute object: */ + *attr = pattr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np); + +int +_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) +{ + int ret; + + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + (*attr)->suspend = THR_CREATE_SUSPENDED; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate); + +int +_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || + (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE)) + ret = EINVAL; + else { + /* Check if detached state: */ + if (detachstate == PTHREAD_CREATE_DETACHED) + /* Set the detached flag: */ + (*attr)->flags |= PTHREAD_DETACHED; + else + /* Reset the detached flag: */ + (*attr)->flags &= ~PTHREAD_DETACHED; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize); + +int +_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) +{ + int ret; + + /* Check for invalid arguments. */ + if (attr == NULL || *attr == NULL) + ret = EINVAL; + else { + /* Save the stack size. */ + (*attr)->guardsize_attr = guardsize; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched); + +int +_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if (sched_inherit != PTHREAD_INHERIT_SCHED && + sched_inherit != PTHREAD_EXPLICIT_SCHED) + ret = ENOTSUP; + else + (*attr)->sched_inherit = sched_inherit; + + return(ret); +} + +__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam); + +int +_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if (param == NULL) { + ret = ENOTSUP; + } else if ((param->sched_priority < THR_MIN_PRIORITY) || + (param->sched_priority > THR_MAX_PRIORITY)) { + /* Return an unsupported value error. */ + ret = ENOTSUP; + } else + (*attr)->prio = param->sched_priority; + + return(ret); +} + +__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); + +int +_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) { + ret = ENOTSUP; + } else + (*attr)->sched_policy = policy; + + return(ret); +} + +__weak_reference(_pthread_attr_setscope, pthread_attr_setscope); + +int +_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) { + /* Return an invalid argument: */ + ret = EINVAL; + } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) && + (contentionscope != PTHREAD_SCOPE_SYSTEM)) { + ret = EINVAL; + } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) { + (*attr)->flags |= contentionscope; + } else { + (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM; + } + return (ret); +} + +__weak_reference(_pthread_attr_setstack, pthread_attr_setstack); + +int +_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, + size_t stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL + || stacksize < PTHREAD_STACK_MIN) + ret = EINVAL; + else { + /* Save the stack address and stack size */ + (*attr)->stackaddr_attr = stackaddr; + (*attr)->stacksize_attr = stacksize; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr); + +int +_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Save the stack address: */ + (*attr)->stackaddr_attr = stackaddr; + ret = 0; + } + return(ret); +} + +__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize); + +int +_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) + ret = EINVAL; + else { + /* Save the stack size: */ + (*attr)->stacksize_attr = stacksize; + ret = 0; + } + return(ret); +} diff --git a/lib/libthread_xu/thread/thr_barrier.c b/lib/libthread_xu/thread/thr_barrier.c new file mode 100644 index 0000000000..2f7027100b --- /dev/null +++ b/lib/libthread_xu/thread/thr_barrier.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2003 David Xu + * 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_barrier.c,v 1.1 2003/09/04 14:06:43 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_barrier.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include + +#include "thr_private.h" + +__weak_reference(_pthread_barrier_init, pthread_barrier_init); +__weak_reference(_pthread_barrier_wait, pthread_barrier_wait); +__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); + +int +_pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + pthread_barrier_t bar; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + bar = *barrier; + if (bar->b_waiters > 0) + return (EBUSY); + *barrier = NULL; + free(bar); + return (0); +} + +int +_pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, int count) +{ + pthread_barrier_t bar; + + if (barrier == NULL || count <= 0) + return (EINVAL); + + bar = malloc(sizeof(struct pthread_barrier)); + if (bar == NULL) + return (ENOMEM); + + _thr_umtx_init(&bar->b_lock); + bar->b_cycle = 0; + bar->b_waiters = 0; + bar->b_count = count; + *barrier = bar; + + return (0); +} + +int +_pthread_barrier_wait(pthread_barrier_t *barrier) +{ + struct pthread *curthread = _get_curthread(); + pthread_barrier_t bar; + long cycle; + int ret; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + bar = *barrier; + THR_UMTX_LOCK(curthread, &bar->b_lock); + if (++bar->b_waiters == bar->b_count) { + /* Current thread is lastest thread */ + bar->b_waiters = 0; + bar->b_cycle++; + _thr_umtx_wake(&bar->b_cycle, INT_MAX); + THR_UMTX_UNLOCK(curthread, &bar->b_lock); + ret = PTHREAD_BARRIER_SERIAL_THREAD; + } else { + cycle = bar->b_cycle; + THR_UMTX_UNLOCK(curthread, &bar->b_lock); + do { + _thr_umtx_wait(&bar->b_cycle, cycle, NULL); + /* test cycle to avoid bogus wakeup */ + } while (cycle == bar->b_cycle); + ret = 0; + } + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_barrierattr.c b/lib/libthread_xu/thread/thr_barrierattr.c new file mode 100644 index 0000000000..70256ac61b --- /dev/null +++ b/lib/libthread_xu/thread/thr_barrierattr.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003 David Xu . + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_barrierattr.c,v 1.1 2003/09/04 14:06:43 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_barrierattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy); +__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init); +__weak_reference(_pthread_barrierattr_setpshared, + pthread_barrierattr_setpshared); +__weak_reference(_pthread_barrierattr_getpshared, + pthread_barrierattr_getpshared); + +int +_pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + free(*attr); + return (0); +} + +int +_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, + int *pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + *pshared = (*attr)->pshared; + return (0); +} + +int +_pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + + if (attr == NULL) + return (EINVAL); + + if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL) + return (ENOMEM); + + (*attr)->pshared = PTHREAD_PROCESS_PRIVATE; + return (0); +} + +int +_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (EINVAL); + + (*attr)->pshared = pshared; + return (0); +} diff --git a/lib/libthread_xu/thread/thr_cancel.c b/lib/libthread_xu/thread/thr_cancel.c new file mode 100644 index 0000000000..c5a1e4079e --- /dev/null +++ b/lib/libthread_xu/thread/thr_cancel.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2005, David Xu + * 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 unmodified, 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 ``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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_cancel.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include "thr_private.h" + +__weak_reference(_pthread_cancel, pthread_cancel); +__weak_reference(_pthread_setcancelstate, pthread_setcancelstate); +__weak_reference(_pthread_setcanceltype, pthread_setcanceltype); +__weak_reference(_pthread_testcancel, pthread_testcancel); + +int _pthread_setcanceltype(int type, int *oldtype); + +int +_pthread_cancel(pthread_t pthread) +{ + struct pthread *curthread = _get_curthread(); + int oldval, newval = 0; + int oldtype; + int ret; + + /* + * POSIX says _pthread_cancel should be async cancellation safe, + * so we temporarily disable async cancellation. + */ + _pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + if ((ret = _thr_ref_add(curthread, pthread, 0)) != 0) { + _pthread_setcanceltype(oldtype, NULL); + return (ret); + } + + do { + oldval = pthread->cancelflags; + if (oldval & THR_CANCEL_NEEDED) + break; + newval = oldval | THR_CANCEL_NEEDED; + } while (!atomic_cmpset_acq_int(&pthread->cancelflags, oldval, newval)); + + if (!(oldval & THR_CANCEL_NEEDED) && SHOULD_ASYNC_CANCEL(newval)) + _thr_send_sig(pthread, SIGCANCEL); + + _thr_ref_delete(curthread, pthread); + _pthread_setcanceltype(oldtype, NULL); + return (0); +} + +static inline void +testcancel(struct pthread *curthread) +{ + int newval; + + newval = curthread->cancelflags; + if (SHOULD_CANCEL(newval)) + pthread_exit(PTHREAD_CANCELED); +} + +int +_pthread_setcancelstate(int state, int *oldstate) +{ + struct pthread *curthread = _get_curthread(); + int oldval, ret; + + oldval = curthread->cancelflags; + if (oldstate != NULL) + *oldstate = ((oldval & THR_CANCEL_DISABLE) ? + PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE); + switch (state) { + case PTHREAD_CANCEL_DISABLE: + atomic_set_int(&curthread->cancelflags, THR_CANCEL_DISABLE); + ret = 0; + break; + case PTHREAD_CANCEL_ENABLE: + atomic_clear_int(&curthread->cancelflags, THR_CANCEL_DISABLE); + testcancel(curthread); + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +int +_pthread_setcanceltype(int type, int *oldtype) +{ + struct pthread *curthread = _get_curthread(); + int oldval, ret; + + oldval = curthread->cancelflags; + if (oldtype != NULL) + *oldtype = ((oldval & THR_CANCEL_AT_POINT) ? + PTHREAD_CANCEL_ASYNCHRONOUS : + PTHREAD_CANCEL_DEFERRED); + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT); + testcancel(curthread); + ret = 0; + break; + case PTHREAD_CANCEL_DEFERRED: + atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT); + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +void +_pthread_testcancel(void) +{ + testcancel(_get_curthread()); +} + +int +_thr_cancel_enter(struct pthread *curthread) +{ + int oldval; + + oldval = curthread->cancelflags; + if (!(oldval & THR_CANCEL_AT_POINT)) { + atomic_set_int(&curthread->cancelflags, THR_CANCEL_AT_POINT); + testcancel(curthread); + } + return (oldval); +} + +void +_thr_cancel_leave(struct pthread *curthread, int previous) +{ + if (!(previous & THR_CANCEL_AT_POINT)) + atomic_clear_int(&curthread->cancelflags, THR_CANCEL_AT_POINT); +} diff --git a/lib/libthread_xu/thread/thr_clean.c b/lib/libthread_xu/thread/thr_clean.c new file mode 100644 index 0000000000..3e0d221419 --- /dev/null +++ b/lib/libthread_xu/thread/thr_clean.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_clean.c,v 1.9 2004/12/18 18:07:37 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_clean.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_cleanup_push, pthread_cleanup_push); +__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop); + +void +_pthread_cleanup_push(void (*routine) (void *), void *routine_arg) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_cleanup *new; + + if ((new = (struct pthread_cleanup *) + malloc(sizeof(struct pthread_cleanup))) != NULL) { + new->routine = routine; + new->routine_arg = routine_arg; + new->onstack = 0; + new->next = curthread->cleanup; + + curthread->cleanup = new; + } +} + +void +_pthread_cleanup_pop(int execute) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_cleanup *old; + + if ((old = curthread->cleanup) != NULL) { + curthread->cleanup = old->next; + if (execute) { + old->routine(old->routine_arg); + } + if (old->onstack == 0) + free(old); + } +} diff --git a/lib/libthread_xu/thread/thr_concurrency.c b/lib/libthread_xu/thread/thr_concurrency.c new file mode 100644 index 0000000000..be668b33b7 --- /dev/null +++ b/lib/libthread_xu/thread/thr_concurrency.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003 Daniel M. Eischen + * Copyright (c) 2003 Sergey Osokin . + * 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. 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 THE AUTHORS 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_concurrency.c,v 1.8 2004/03/14 05:24:27 bde Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_concurrency.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include + +#include "thr_private.h" + +/*#define DEBUG_CONCURRENCY */ +#ifdef DEBUG_CONCURRENCY +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +static int level = 0; + +__weak_reference(_pthread_getconcurrency, pthread_getconcurrency); +__weak_reference(_pthread_setconcurrency, pthread_setconcurrency); + +int +_pthread_getconcurrency(void) +{ + return (level); +} + +int +_pthread_setconcurrency(int new_level) +{ + if (new_level < 0) + return (EINVAL); + level = new_level; + return 0; +} diff --git a/lib/libthread_xu/thread/thr_cond.c b/lib/libthread_xu/thread/thr_cond.c new file mode 100644 index 0000000000..6c33b70754 --- /dev/null +++ b/lib/libthread_xu/thread/thr_cond.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2005 David Xu + * 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 unmodified, 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 ``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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_cond.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include + +#include "thr_private.h" + +/* + * Prototypes + */ +static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime, int cancel); +static int cond_signal_common(pthread_cond_t *cond, int broadcast); + +/* + * Double underscore versions are cancellation points. Single underscore + * versions are not and are provided for libc internal usage (which + * shouldn't introduce cancellation points). + */ +__weak_reference(__pthread_cond_wait, pthread_cond_wait); +__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait); + +__weak_reference(_pthread_cond_init, pthread_cond_init); +__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); +__weak_reference(_pthread_cond_signal, pthread_cond_signal); +__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); + +static int +cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + pthread_cond_t pcond; + int rval = 0; + + if ((pcond = (pthread_cond_t) + malloc(sizeof(struct pthread_cond))) == NULL) { + rval = ENOMEM; + } else { + /* + * Initialise the condition variable structure: + */ + _thr_umtx_init(&pcond->c_lock); + pcond->c_seqno = 0; + pcond->c_waiters = 0; + pcond->c_wakeups = 0; + if (cond_attr == NULL || *cond_attr == NULL) { + pcond->c_pshared = 0; + pcond->c_clockid = CLOCK_REALTIME; + } else { + pcond->c_pshared = (*cond_attr)->c_pshared; + pcond->c_clockid = (*cond_attr)->c_clockid; + } + *cond = pcond; + } + /* Return the completion status: */ + return (rval); +} + +static int +init_static(struct pthread *thread, pthread_cond_t *cond) +{ + int ret; + + THR_LOCK_ACQUIRE(thread, &_cond_static_lock); + + if (*cond == NULL) + ret = cond_init(cond, NULL); + else + ret = 0; + + THR_LOCK_RELEASE(thread, &_cond_static_lock); + + return (ret); +} + +int +_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + *cond = NULL; + return cond_init(cond, cond_attr); +} + +int +_pthread_cond_destroy(pthread_cond_t *cond) +{ + struct pthread_cond *cv; + struct pthread *curthread = _get_curthread(); + int rval = 0; + + if (*cond == NULL) + rval = EINVAL; + else { + /* Lock the condition variable structure: */ + THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); + if ((*cond)->c_waiters + (*cond)->c_wakeups != 0) { + THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); + return (EBUSY); + } + + /* + * NULL the caller's pointer now that the condition + * variable has been destroyed: + */ + cv = *cond; + *cond = NULL; + + /* Unlock the condition variable structure: */ + THR_LOCK_RELEASE(curthread, &cv->c_lock); + + /* Free the cond lock structure: */ + + /* + * Free the memory allocated for the condition + * variable structure: + */ + free(cv); + + } + /* Return the completion status: */ + return (rval); +} + +struct cond_cancel_info +{ + pthread_mutex_t *mutex; + pthread_cond_t *cond; + long seqno; +}; + +static void +cond_cancel_handler(void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct cond_cancel_info *cci = (struct cond_cancel_info *)arg; + pthread_cond_t cv; + + cv = *(cci->cond); + THR_LOCK_ACQUIRE(curthread, &cv->c_lock); + if (cv->c_seqno != cci->seqno && cv->c_wakeups != 0) { + if (cv->c_waiters > 0) { + cv->c_seqno++; + _thr_umtx_wake(&cv->c_seqno, 1); + } else + cv->c_wakeups--; + } else { + cv->c_waiters--; + } + THR_LOCK_RELEASE(curthread, &cv->c_lock); + + _mutex_cv_lock(cci->mutex); +} + +static int +cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime, int cancel) +{ + struct pthread *curthread = _get_curthread(); + struct timespec ts, ts2, *tsp; + struct cond_cancel_info cci; + pthread_cond_t cv; + long seq, oldseq; + int oldcancel; + int ret = 0; + + /* + * If the condition variable is statically initialized, + * perform the dynamic initialization: + */ + if (__predict_false(*cond == NULL && + (ret = init_static(curthread, cond)) != 0)) + return (ret); + + cv = *cond; + THR_LOCK_ACQUIRE(curthread, &cv->c_lock); + ret = _mutex_cv_unlock(mutex); + if (ret) { + THR_LOCK_RELEASE(curthread, &cv->c_lock); + return (ret); + } + oldseq = seq = cv->c_seqno; + cci.mutex = mutex; + cci.cond = cond; + cci.seqno = oldseq; + + cv->c_waiters++; + do { + THR_LOCK_RELEASE(curthread, &cv->c_lock); + + if (abstime != NULL) { + clock_gettime(cv->c_clockid, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + tsp = &ts2; + } else + tsp = NULL; + + if (cancel) { + THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &cci); + oldcancel = _thr_cancel_enter(curthread); + ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp); + _thr_cancel_leave(curthread, oldcancel); + THR_CLEANUP_POP(curthread, 0); + } else { + ret = _thr_umtx_wait(&cv->c_seqno, seq, tsp); + } + + THR_LOCK_ACQUIRE(curthread, &cv->c_lock); + seq = cv->c_seqno; + if (abstime != NULL && ret == ETIMEDOUT) + break; + + /* + * loop if we have never been told to wake up + * or we lost a race. + */ + } while (seq == oldseq || cv->c_wakeups == 0); + + if (seq != oldseq && cv->c_wakeups != 0) { + cv->c_wakeups--; + ret = 0; + } else { + cv->c_waiters--; + } + THR_LOCK_RELEASE(curthread, &cv->c_lock); + _mutex_cv_lock(mutex); + return (ret); +} + +int +_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + return cond_wait_common(cond, mutex, NULL, 0); +} + +__strong_reference(_pthread_cond_wait, _thr_cond_wait); + +int +__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + int ret; + + ret = cond_wait_common(cond, mutex, NULL, 1); + return (ret); +} + +int +_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, + const struct timespec * abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + + return cond_wait_common(cond, mutex, abstime, 0); +} + +__strong_reference(_pthread_cond_timedwait, _thr_cond_timedwait); + +int +__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + + return cond_wait_common(cond, mutex, abstime, 1); +} + +static int +cond_signal_common(pthread_cond_t *cond, int broadcast) +{ + struct pthread *curthread = _get_curthread(); + pthread_cond_t cv; + int ret = 0; + + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + if (__predict_false(*cond == NULL && + (ret = init_static(curthread, cond)) != 0)) + return (ret); + + cv = *cond; + /* Lock the condition variable structure. */ + THR_LOCK_ACQUIRE(curthread, &cv->c_lock); + if (cv->c_waiters) { + if (!broadcast) { + cv->c_wakeups++; + cv->c_waiters--; + cv->c_seqno++; + _thr_umtx_wake(&cv->c_seqno, 1); + } else { + cv->c_wakeups += cv->c_waiters; + cv->c_waiters = 0; + cv->c_seqno++; + _thr_umtx_wake(&cv->c_seqno, INT_MAX); + } + } + THR_LOCK_RELEASE(curthread, &cv->c_lock); + return (ret); +} + +int +_pthread_cond_signal(pthread_cond_t * cond) +{ + return cond_signal_common(cond, 0); +} + +__strong_reference(_pthread_cond_signal, _thr_cond_signal); + +int +_pthread_cond_broadcast(pthread_cond_t * cond) +{ + return cond_signal_common(cond, 1); +} + +__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast); diff --git a/lib/libthread_xu/thread/thr_condattr.c b/lib/libthread_xu/thread/thr_condattr.c new file mode 100644 index 0000000000..b4fe7ed878 --- /dev/null +++ b/lib/libthread_xu/thread/thr_condattr.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1997 John Birrell . + * 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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_condattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_condattr_init, pthread_condattr_init); +__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy); +__weak_reference(_pthread_condattr_getclock, pthread_condattr_getclock); +__weak_reference(_pthread_condattr_setclock, pthread_condattr_setclock); +__weak_reference(_pthread_condattr_getpshared, pthread_condattr_getpshared); +__weak_reference(_pthread_condattr_setpshared, pthread_condattr_setpshared); + +int +_pthread_condattr_init(pthread_condattr_t *attr) +{ + pthread_condattr_t pattr; + int ret; + + if ((pattr = (pthread_condattr_t) + malloc(sizeof(struct pthread_cond_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &_pthread_condattr_default, + sizeof(struct pthread_cond_attr)); + *attr = pattr; + ret = 0; + } + return (ret); +} + +int +_pthread_condattr_destroy(pthread_condattr_t *attr) +{ + int ret; + + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} + +int +_pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clock_id) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + *clock_id = (*attr)->c_clockid; + return (0); +} + +int +_pthread_condattr_setclock(const pthread_condattr_t *attr, + clockid_t clock_id) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + if (clock_id != CLOCK_REALTIME) + return (EINVAL); + (*attr)->c_clockid = clock_id; + return (0); +} + +int +_pthread_condattr_getpshared(const pthread_condattr_t *attr, + int *pshared) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + pshared = PTHREAD_PROCESS_PRIVATE; + return (0); +} + +int +_pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (EINVAL); + return (0); +} diff --git a/lib/libthread_xu/thread/thr_create.c b/lib/libthread_xu/thread/thr_create.c new file mode 100644 index 0000000000..09198c5715 --- /dev/null +++ b/lib/libthread_xu/thread/thr_create.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2005 David Xu + * Copyright (c) 2003 Daniel M. Eischen + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_create.c,v 1.58 2004/10/23 23:28:36 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_create.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thr_private.h" +#include "libc_private.h" + +struct start_arg { + struct pthread *thread; + volatile umtx_t started; +}; + +static void free_thread(struct pthread *curthread, struct pthread *thread); +static int create_stack(struct pthread_attr *pattr); +static void free_stack(struct pthread *curthread, struct pthread_attr *pattr); +static void thread_start(void *); + +__weak_reference(_pthread_create, pthread_create); + +int +_pthread_create(pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + struct start_arg start_arg; + void *stack; + sigset_t sigmask, oldsigmask; + struct pthread *curthread, *new_thread; + int ret = 0; + + _thr_check_init(); + + /* + * Tell libc and others now they need lock to protect their data. + */ + if (_thr_isthreaded() == 0 && _thr_setthreaded(1)) + return (EAGAIN); + + curthread = _get_curthread(); + if ((new_thread = _thr_alloc(curthread)) == NULL) + return (EAGAIN); + + if (attr == NULL || *attr == NULL) + /* Use the default thread attributes: */ + new_thread->attr = _pthread_attr_default; + else + new_thread->attr = *(*attr); + if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { + /* inherit scheduling contention scope */ + if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM) + new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; + else + new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; + /* + * scheduling policy and scheduling parameters will be + * inherited in following code. + */ + } + + if (_thread_scope_system > 0) + new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; + else if (_thread_scope_system < 0) + new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; + + if (create_stack(&new_thread->attr) != 0) { + /* Insufficient memory to create a stack: */ + new_thread->terminated = 1; + _thr_free(curthread, new_thread); + return (EAGAIN); + } + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + new_thread->magic = THR_MAGIC; + new_thread->start_routine = start_routine; + new_thread->arg = arg; + new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + /* + * Check if this thread is to inherit the scheduling + * attributes from its parent: + */ + if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { + /* + * Copy the scheduling attributes. Lock the scheduling + * lock to get consistent scheduling parameters. + */ + THR_LOCK(curthread); + new_thread->base_priority = curthread->base_priority; + new_thread->attr.prio = curthread->base_priority; + new_thread->attr.sched_policy = curthread->attr.sched_policy; + THR_UNLOCK(curthread); + } else { + /* + * Use just the thread priority, leaving the + * other scheduling attributes as their + * default values: + */ + new_thread->base_priority = new_thread->attr.prio; + } + new_thread->active_priority = new_thread->base_priority; + + /* Initialize the mutex queue: */ + TAILQ_INIT(&new_thread->mutexq); + TAILQ_INIT(&new_thread->pri_mutexq); + + /* Initialise hooks in the thread structure: */ + if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) + new_thread->flags = THR_FLAGS_SUSPENDED; + new_thread->state = PS_RUNNING; + /* + * Thread created by thr_create() inherits currrent thread + * sigmask, however, before new thread setup itself correctly, + * it can not handle signal, so we should masks all signals here. + */ + SIGFILLSET(sigmask); + __sys_sigprocmask(SIG_SETMASK, &sigmask, &oldsigmask); + new_thread->sigmask = oldsigmask; + /* Add the new thread. */ + _thr_link(curthread, new_thread); + /* Return thread pointer eariler so that new thread can use it. */ + (*thread) = new_thread; + /* Schedule the new thread. */ + stack = (char *)new_thread->attr.stackaddr_attr + + new_thread->attr.stacksize_attr; + start_arg.thread = new_thread; + start_arg.started = 0; + ret = rfork_thread(RFPROC | RFNOWAIT | RFMEM | RFSIGSHARE, stack, + (int (*)(void *))thread_start, &start_arg); + __sys_sigprocmask(SIG_SETMASK, &oldsigmask, NULL); + if (ret >= 0) { + /* + * Wait until new thread get its thread id, so we can + * send signal to it immediately after we return. + */ + while (start_arg.started == 0) + _thr_umtx_wait(&start_arg.started, 0, 0); + ret = 0; + } else { + ret = EAGAIN; + } + if (ret != 0) { + _thr_unlink(curthread, new_thread); + free_thread(curthread, new_thread); + (*thread) = 0; + ret = EAGAIN; + } + return (ret); +} + +static void +free_thread(struct pthread *curthread, struct pthread *thread) +{ + free_stack(curthread, &thread->attr); + curthread->terminated = 1; + _thr_free(curthread, thread); +} + +static int +create_stack(struct pthread_attr *pattr) +{ + int ret; + + /* Check if a stack was specified in the thread attributes: */ + if ((pattr->stackaddr_attr) != NULL) { + pattr->guardsize_attr = 0; + pattr->flags |= THR_STACK_USER; + ret = 0; + } + else + ret = _thr_stack_alloc(pattr); + return (ret); +} + +static void +free_stack(struct pthread *curthread, struct pthread_attr *pattr) +{ + if ((pattr->flags & THR_STACK_USER) == 0) { + THREAD_LIST_LOCK(curthread); + /* Stack routines don't use malloc/free. */ + _thr_stack_free(pattr); + THREAD_LIST_UNLOCK(curthread); + } +} + +static void +thread_start(void *arg) +{ + struct pthread *curthread; + struct start_arg *start_arg = arg; + + curthread = start_arg->thread; + curthread->tid = _thr_get_tid(); + _tcb_set(curthread->tcb); + start_arg->started = 1; + _thr_umtx_wake(&start_arg->started, 1); + + /* Thread was created with all signals blocked, unblock them. */ + __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); + + if (curthread->flags & THR_FLAGS_NEED_SUSPEND) + _thr_suspend_check(curthread); + + /* Run the current thread's start routine with argument: */ + pthread_exit(curthread->start_routine(curthread->arg)); + + /* This point should never be reached. */ + PANIC("Thread has resumed after exit"); +} diff --git a/lib/libthread_xu/thread/thr_detach.c b/lib/libthread_xu/thread/thr_detach.c new file mode 100644 index 0000000000..6f323108c9 --- /dev/null +++ b/lib/libthread_xu/thread/thr_detach.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_detach.c,v 1.23 2003/07/23 02:11:07 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_detach.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_detach, pthread_detach); + +int +_pthread_detach(pthread_t pthread) +{ + struct pthread *curthread = _get_curthread(); + int rval; + + if (pthread == NULL) + return (EINVAL); + + THREAD_LIST_LOCK(curthread); + if ((rval = _thr_find_thread(curthread, pthread, + /*include dead*/1)) != 0) { + THREAD_LIST_UNLOCK(curthread); + return (rval); + } + + /* Check if the thread is already detached or has a joiner. */ + if ((pthread->tlflags & TLFLAGS_DETACHED) != 0 || + (pthread->joiner != NULL)) { + THREAD_LIST_UNLOCK(curthread); + return (EINVAL); + } + + /* Flag the thread as detached. */ + pthread->tlflags |= TLFLAGS_DETACHED; + if (pthread->state == PS_DEAD) + THR_GCLIST_ADD(pthread); + THREAD_LIST_UNLOCK(curthread); + + return (0); +} diff --git a/lib/libthread_xu/thread/thr_equal.c b/lib/libthread_xu/thread/thr_equal.c new file mode 100644 index 0000000000..2f3d577064 --- /dev/null +++ b/lib/libthread_xu/thread/thr_equal.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_equal.c,v 1.6 2002/09/16 08:45:34 mini Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_equal.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "thr_private.h" + +__weak_reference(_pthread_equal, pthread_equal); + +int +_pthread_equal(pthread_t t1, pthread_t t2) +{ + /* Compare the two thread pointers: */ + return (t1 == t2); +} diff --git a/lib/libthread_xu/thread/thr_exit.c b/lib/libthread_xu/thread/thr_exit.c new file mode 100644 index 0000000000..6c5b293ade --- /dev/null +++ b/lib/libthread_xu/thread/thr_exit.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_exit.c,v 1.39 2004/10/23 23:37:54 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_exit.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include "thr_private.h" + +void _pthread_exit(void *status); + +__weak_reference(_pthread_exit, pthread_exit); + +void +_thread_exit(char *fname, int lineno, char *msg) +{ + + /* Write an error message to the standard error file descriptor: */ + _thread_printf(2, + "Fatal error '%s' at line %d in file %s (errno = %d)\n", + msg, lineno, fname, errno); + + abort(); +} + +/* + * Only called when a thread is cancelled. It may be more useful + * to call it from pthread_exit() if other ways of asynchronous or + * abnormal thread termination can be found. + */ +void +_thr_exit_cleanup(void) +{ + struct pthread *curthread = _get_curthread(); + + /* + * POSIX states that cancellation/termination of a thread should + * not release any visible resources (such as mutexes) and that + * it is the applications responsibility. Resources that are + * internal to the threads library, including file and fd locks, + * are not visible to the application and need to be released. + */ + /* Unlock all private mutexes: */ + _mutex_unlock_private(curthread); + + /* + * This still isn't quite correct because we don't account + * for held spinlocks (see libc/stdlib/malloc.c). + */ +} + +void +_pthread_exit(void *status) +{ + struct pthread *curthread = _get_curthread(); + + /* Check if this thread is already in the process of exiting: */ + if ((curthread->cancelflags & THR_CANCEL_EXITING) != 0) { + char msg[128]; + 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!", curthread); + PANIC(msg); + } + + /* Flag this thread as exiting. */ + atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING); + + _thr_exit_cleanup(); + + /* Save the return value: */ + curthread->ret = status; + while (curthread->cleanup != NULL) { + pthread_cleanup_pop(1); + } + if (curthread->attr.cleanup_attr != NULL) { + curthread->attr.cleanup_attr(curthread->attr.arg_attr); + } + /* Check if there is thread specific data: */ + if (curthread->specific != NULL) { + /* Run the thread-specific data destructors: */ + _thread_cleanupspecific(); + } + + if (!_thr_isthreaded()) + exit(0); + + THREAD_LIST_LOCK(curthread); + _thread_active_threads--; + if (_thread_active_threads == 0) { + THREAD_LIST_UNLOCK(curthread); + exit(0); + /* Never reach! */ + } + if (curthread->tlflags & TLFLAGS_DETACHED) + THR_GCLIST_ADD(curthread); + curthread->state = PS_DEAD; + THREAD_LIST_UNLOCK(curthread); + if (curthread->joiner) + _thr_umtx_wake(&curthread->state, INT_MAX); + /* XXX + * All the code is incorrect on DragonFly. + * DragonFly has race condition here. it should provide + * an interface to tell userland that a thread is now + * in kernel, and userland stack can be safely recycled + * by userland GC code. + */ + curthread->terminated = 1; + _exit(0); + PANIC("thr_exit() returned"); + /* Never reach! */ +} diff --git a/lib/libthread_xu/thread/thr_fork.c b/lib/libthread_xu/thread/thr_fork.c new file mode 100644 index 0000000000..9a58bc2f94 --- /dev/null +++ b/lib/libthread_xu/thread/thr_fork.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2005 David Xu + * Copyright (c) 2003 Daniel Eischen + * 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. 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_atfork.c,v 1.1 2003/11/05 03:42:10 davidxu Exp $ + */ + +/* + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_fork.c,v 1.34 2003/11/05 18:18:45 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_fork.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include +#include + +#include "libc_private.h" +#include "thr_private.h" + +__weak_reference(_pthread_atfork, pthread_atfork); + +int +_pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) +{ + struct pthread *curthread; + struct pthread_atfork *af; + + _thr_check_init(); + + if ((af = malloc(sizeof(struct pthread_atfork))) == NULL) + return (ENOMEM); + + curthread = _get_curthread(); + af->prepare = prepare; + af->parent = parent; + af->child = child; + THR_UMTX_LOCK(curthread, &_thr_atfork_lock); + TAILQ_INSERT_TAIL(&_thr_atfork_list, af, qe); + THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); + return (0); +} + +/* + * For a while, allow libpthread to work with a libc that doesn't + * export the malloc lock. + */ +#pragma weak __malloc_lock + +__weak_reference(_fork, fork); + +pid_t +_fork(void) +{ + static umtx_t inprogress; + static int waiters; + umtx_t tmp; + + struct pthread *curthread; + struct pthread_atfork *af; + pid_t ret; + int errsave; +#ifndef __DragonFly__ + int unlock_malloc; +#endif + + if (!_thr_is_inited()) + return (__sys_fork()); + + curthread = _get_curthread(); + + THR_UMTX_LOCK(curthread, &_thr_atfork_lock); + tmp = inprogress; + while (tmp) { + waiters++; + THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); + _thr_umtx_wait(&inprogress, tmp, NULL); + THR_UMTX_LOCK(curthread, &_thr_atfork_lock); + waiters--; + tmp = inprogress; + } + inprogress = 1; + THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); + + /* Run down atfork prepare handlers. */ + TAILQ_FOREACH_REVERSE(af, &_thr_atfork_list, atfork_head, qe) { + if (af->prepare != NULL) + af->prepare(); + } + +#ifndef __DragonFly__ + /* + * Try our best to protect memory from being corrupted in + * child process because another thread in malloc code will + * simply be kill by fork(). + */ + if ((_thr_isthreaded() != 0) && (__malloc_lock != NULL)) { + unlock_malloc = 1; + _spinlock(__malloc_lock); + } else { + unlock_malloc = 0; + } +#endif + + /* + * Block all signals until we reach a safe point. + */ + _thr_signal_block(curthread); + + /* Fork a new process: */ + if ((ret = __sys_fork()) == 0) { + /* Child process */ + errsave = errno; + inprogress = 0; + curthread->cancelflags &= ~THR_CANCEL_NEEDED; + /* + * Thread list will be reinitialized, and later we call + * _libpthread_init(), it will add us back to list. + */ + curthread->tlflags &= ~(TLFLAGS_IN_TDLIST | TLFLAGS_DETACHED); + + /* child is a new kernel thread. */ + curthread->tid = _thr_get_tid(); + + /* clear other threads locked us. */ + _thr_umtx_init(&curthread->lock); + _thr_umtx_init(&_thr_atfork_lock); + _thr_setthreaded(0); + + /* reinitialize libc spinlocks, this includes __malloc_lock. */ + _thr_spinlock_init(); + _mutex_fork(curthread); + + /* reinitalize library. */ + _libpthread_init(curthread); + + /* Ready to continue, unblock signals. */ + _thr_signal_unblock(curthread); + + /* Run down atfork child handlers. */ + TAILQ_FOREACH(af, &_thr_atfork_list, qe) { + if (af->child != NULL) + af->child(); + } + } else { + /* Parent process */ + errsave = errno; + +#ifndef __DragonFly__ + if (unlock_malloc) + _spinunlock(__malloc_lock); +#endif + + /* Ready to continue, unblock signals. */ + _thr_signal_unblock(curthread); + + /* Run down atfork parent handlers. */ + TAILQ_FOREACH(af, &_thr_atfork_list, qe) { + if (af->parent != NULL) + af->parent(); + } + + THR_UMTX_LOCK(curthread, &_thr_atfork_lock); + inprogress = 0; + if (waiters) + _thr_umtx_wake(&inprogress, waiters); + THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); + } + errno = errsave; + + /* Return the process ID: */ + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_getprio.c b/lib/libthread_xu/thread/thr_getprio.c new file mode 100644 index 0000000000..6778a1f0a2 --- /dev/null +++ b/lib/libthread_xu/thread/thr_getprio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_getprio.c,v 1.9 2002/09/16 08:45:34 mini Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_getprio.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_getprio, pthread_getprio); + +int +_pthread_getprio(pthread_t pthread) +{ + int policy, ret; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) + ret = param.sched_priority; + else { + /* Invalid thread: */ + errno = ret; + ret = -1; + } + + /* Return the thread priority or an error status: */ + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_getschedparam.c b/lib/libthread_xu/thread/thr_getschedparam.c new file mode 100644 index 0000000000..8bdd28c0c6 --- /dev/null +++ b/lib/libthread_xu/thread/thr_getschedparam.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1998 Daniel Eischen . + * 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 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 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_getschedparam.c,v 1.10 2003/07/07 04:28:23 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_getschedparam.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_getschedparam, pthread_getschedparam); + +int +_pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param) +{ + struct pthread *curthread = _get_curthread(); + int ret, tmp; + + if ((param == NULL) || (policy == NULL)) + /* Return an invalid argument error: */ + ret = EINVAL; + else if (pthread == curthread) { + /* + * Avoid searching the thread list when it is the current + * thread. + */ + THR_THREAD_LOCK(curthread, curthread); + param->sched_priority = + THR_BASE_PRIORITY(pthread->base_priority); + tmp = pthread->attr.sched_policy; + THR_THREAD_UNLOCK(curthread, curthread); + *policy = tmp; + ret = 0; + } + /* Find the thread in the list of active threads. */ + else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) + == 0) { + THR_THREAD_LOCK(curthread, pthread); + param->sched_priority = + THR_BASE_PRIORITY(pthread->base_priority); + tmp = pthread->attr.sched_policy; + THR_THREAD_UNLOCK(curthread, pthread); + _thr_ref_delete(curthread, pthread); + *policy = tmp; + } + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_info.c b/lib/libthread_xu/thread/thr_info.c new file mode 100644 index 0000000000..01b63007c6 --- /dev/null +++ b/lib/libthread_xu/thread/thr_info.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_info.c,v 1.27 2003/09/22 00:40:23 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_info.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include "thr_private.h" + +#ifndef NELEMENTS +#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +static void dump_thread(int fd, pthread_t pthread, int long_version); + +__weak_reference(_pthread_set_name_np, pthread_set_name_np); + +struct s_thread_info { + enum pthread_state state; + char *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { + {PS_RUNNING , "Running"}, + {PS_MUTEX_WAIT , "Waiting on a mutex"}, + {PS_JOIN , "Waiting to join"}, + {PS_SUSPENDED , "Suspended"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} +}; + +void +_thread_dump_info(void) +{ + char s[512], tmpfile[128]; + pthread_t pthread; + int fd, i; + + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/pthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ + return; + } else { + /* Dump the active threads. */ + strcpy(s, "\n\n========\nACTIVE THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the global list: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + if (pthread->state != PS_DEAD) + dump_thread(fd, pthread, /*long_verson*/ 1); + } + + /* + * Dump the ready threads. + * XXX - We can't easily do this because the run queues + * are per-KSEG. + */ + strcpy(s, "\n\n========\nREADY THREADS - unimplemented\n\n"); + __sys_write(fd, s, strlen(s)); + + + /* + * Dump the waiting threads. + * XXX - We can't easily do this because the wait queues + * are per-KSEG. + */ + strcpy(s, "\n\n========\nWAITING THREADS - unimplemented\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Close the dump file. */ + __sys_close(fd); + } +} + +static void +dump_thread(int fd, pthread_t pthread, int long_version) +{ + struct pthread *curthread = _get_curthread(); + char s[512]; + int i; + + /* Find the state: */ + for (i = 0; i < NELEMENTS(thread_info) - 1; i++) + if (thread_info[i].state == pthread->state) + break; + + /* Output a record for the thread: */ + snprintf(s, sizeof(s), + "--------------------\n" + "Thread %p (%s), scope %s, prio %3d, state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? "" : pthread->name, + pthread->attr.flags & PTHREAD_SCOPE_SYSTEM ? "system" : "process", + pthread->active_priority, + thread_info[i].name, pthread->fname, pthread->lineno); + __sys_write(fd, s, strlen(s)); + + if (long_version != 0) { + /* Check if this is the running thread: */ + if (pthread == curthread) { + /* Output a record for the running thread: */ + strcpy(s, "This is the running thread\n"); + __sys_write(fd, s, strlen(s)); + } + /* Check if this is the initial thread: */ + if (pthread == _thr_initial) { + /* Output a record for the initial thread: */ + strcpy(s, "This is the initial thread\n"); + __sys_write(fd, s, strlen(s)); + } + + /* Process according to thread state: */ + switch (pthread->state) { + /* + * Trap other states that are not explicitly + * coded to dump information: + */ + default: + snprintf(s, sizeof(s), "sigmask (hi) "); + __sys_write(fd, s, strlen(s)); + for (i = _SIG_WORDS - 1; i >= 0; i--) { + snprintf(s, sizeof(s), "%08x ", + pthread->sigmask.__bits[i]); + __sys_write(fd, s, strlen(s)); + } + snprintf(s, sizeof(s), "(lo)\n"); + __sys_write(fd, s, strlen(s)); + break; + } + } +} + +/* Set the thread name for debug: */ +void +_pthread_set_name_np(pthread_t thread, char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == THR_MAGIC) { + if (thread->name != NULL) { + /* Free space for previous name. */ + free(thread->name); + } + thread->name = strdup(name); + } +} diff --git a/lib/libthread_xu/thread/thr_init.c b/lib/libthread_xu/thread/thr_init.c new file mode 100644 index 0000000000..9710cd602f --- /dev/null +++ b/lib/libthread_xu/thread/thr_init.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2003 Daniel M. Eischen + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_init.c,v 1.66 2004/08/21 11:49:19 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_init.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* Allocate space for global thread variables here: */ +#define GLOBAL_PTHREAD_PRIVATE + +#include "namespace.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "libc_private.h" +#include "thr_private.h" + +extern int _thread_state_running; + +int __pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int __pthread_mutex_lock(pthread_mutex_t *); +int __pthread_mutex_trylock(pthread_mutex_t *); + +void _thread_init(void) __attribute__ ((constructor)); + +static void init_private(void); +static void init_main_thread(struct pthread *thread); + +/* + * All weak references used within libc should be in this table. + * This is so that static libraries will work. + */ +static void *references[] = { + &_accept, + &_bind, + &_close, + &_connect, + &_dup, + &_dup2, + &_execve, + &_fcntl, + &_flock, + &_flockfile, + &_fstat, + &_fstatfs, + &_fsync, + &_funlockfile, + &_getdirentries, + &_getlogin, + &_getpeername, + &_getsockname, + &_getsockopt, + &_ioctl, + &_kevent, + &_listen, + &_nanosleep, + &_open, + &_pthread_getspecific, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_mutex_destroy, + &_pthread_mutex_init, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock, + &_pthread_mutexattr_init, + &_pthread_mutexattr_destroy, + &_pthread_mutexattr_settype, + &_pthread_once, + &_pthread_setspecific, + &_read, + &_readv, + &_recvfrom, + &_recvmsg, + &_select, + &_sendmsg, + &_sendto, + &_setsockopt, + &_sigaction, + &_sigprocmask, + &_sigsuspend, + &_socket, + &_socketpair, + &_thread_init, + &_wait4, + &_write, + &_writev +}; + +/* + * These are needed when linking statically. All references within + * libgcc (and in the future libc) to these routines are weak, but + * if they are not (strongly) referenced by the application or other + * libraries, then the actual functions will not be loaded. + */ +static void *libgcc_references[] = { + &_pthread_once, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_getspecific, + &_pthread_setspecific, + &_pthread_mutex_init, + &_pthread_mutex_destroy, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock, + &_pthread_cond_init, + &_pthread_cond_destroy, + &_pthread_cond_wait, + &_pthread_cond_timedwait, + &_pthread_cond_signal, + &_pthread_cond_broadcast +}; + +#if 0 +#define DUAL_ENTRY(entry) \ + (pthread_func_t)entry, (pthread_func_t)entry + +static pthread_func_t jmp_table[][2] = { + {DUAL_ENTRY(_pthread_cond_broadcast)}, /* PJT_COND_BROADCAST */ + {DUAL_ENTRY(_pthread_cond_destroy)}, /* PJT_COND_DESTROY */ + {DUAL_ENTRY(_pthread_cond_init)}, /* PJT_COND_INIT */ + {DUAL_ENTRY(_pthread_cond_signal)}, /* PJT_COND_SIGNAL */ + {(pthread_func_t)__pthread_cond_wait, + (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */ + {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */ + {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */ + {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/ + {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */ + {DUAL_ENTRY(_pthread_mutex_destroy)}, /* PJT_MUTEX_DESTROY */ + {DUAL_ENTRY(_pthread_mutex_init)}, /* PJT_MUTEX_INIT */ + {(pthread_func_t)__pthread_mutex_lock, + (pthread_func_t)_pthread_mutex_lock}, /* PJT_MUTEX_LOCK */ + {(pthread_func_t)__pthread_mutex_trylock, + (pthread_func_t)_pthread_mutex_trylock},/* PJT_MUTEX_TRYLOCK */ + {DUAL_ENTRY(_pthread_mutex_unlock)}, /* PJT_MUTEX_UNLOCK */ + {DUAL_ENTRY(_pthread_mutexattr_destroy)}, /* PJT_MUTEXATTR_DESTROY */ + {DUAL_ENTRY(_pthread_mutexattr_init)}, /* PJT_MUTEXATTR_INIT */ + {DUAL_ENTRY(_pthread_mutexattr_settype)}, /* PJT_MUTEXATTR_SETTYPE */ + {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */ + {DUAL_ENTRY(_pthread_rwlock_destroy)}, /* PJT_RWLOCK_DESTROY */ + {DUAL_ENTRY(_pthread_rwlock_init)}, /* PJT_RWLOCK_INIT */ + {DUAL_ENTRY(_pthread_rwlock_rdlock)}, /* PJT_RWLOCK_RDLOCK */ + {DUAL_ENTRY(_pthread_rwlock_tryrdlock)},/* PJT_RWLOCK_TRYRDLOCK */ + {DUAL_ENTRY(_pthread_rwlock_trywrlock)},/* PJT_RWLOCK_TRYWRLOCK */ + {DUAL_ENTRY(_pthread_rwlock_unlock)}, /* PJT_RWLOCK_UNLOCK */ + {DUAL_ENTRY(_pthread_rwlock_wrlock)}, /* PJT_RWLOCK_WRLOCK */ + {DUAL_ENTRY(_pthread_self)}, /* PJT_SELF */ + {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */ + {DUAL_ENTRY(_pthread_sigmask)} /* PJT_SIGMASK */ +}; +#endif + +static int init_once = 0; + +/* + * Threaded process initialization. + * + * This is only called under two conditions: + * + * 1) Some thread routines have detected that the library hasn't yet + * been initialized (_thr_initial == NULL && curthread == NULL), or + * + * 2) An explicit call to reinitialize after a fork (indicated + * by curthread != NULL) + */ +void +_libpthread_init(struct pthread *curthread) +{ + int fd, first = 0; + sigset_t sigset, oldset; + + /* Check if this function has already been called: */ + if ((_thr_initial != NULL) && (curthread == NULL)) + /* Only initialize the threaded application once. */ + return; + + /* + * Make gcc quiescent about {,libgcc_}references not being + * referenced: + */ + if ((references[0] == NULL) || (libgcc_references[0] == NULL)) + PANIC("Failed loading mandatory references in _thread_init"); + + /* Pull debug symbols in for static binary */ + _thread_state_running = PS_RUNNING; + +#if 0 + /* + * Check the size of the jump table to make sure it is preset + * with the correct number of entries. + */ + if (sizeof(jmp_table) != (sizeof(pthread_func_t) * PJT_MAX * 2)) + PANIC("Thread jump table not properly initialized"); + memcpy(__thr_jtable, jmp_table, sizeof(jmp_table)); +#endif + /* + * Check for the special case of this process running as + * or in place of init as pid = 1: + */ + if ((_thr_pid = getpid()) == 1) { + /* + * Setup a new session for this process which is + * assumed to be running as root. + */ + if (setsid() == -1) + PANIC("Can't set session ID"); + if (revoke(_PATH_CONSOLE) != 0) + PANIC("Can't revoke console"); + if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) + PANIC("Can't open console"); + if (setlogin("root") == -1) + PANIC("Can't set login to root"); + if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) + PANIC("Can't set controlling terminal"); + } + + /* Initialize pthread private data. */ + init_private(); + + /* Set the initial thread. */ + if (curthread == NULL) { + first = 1; + /* Create and initialize the initial thread. */ + curthread = _thr_alloc(NULL); + if (curthread == NULL) + PANIC("Can't allocate initial thread"); + init_main_thread(curthread); + } + /* + * Add the thread to the thread list queue. + */ + THR_LIST_ADD(curthread); + _thread_active_threads = 1; + + /* Setup the thread specific data */ + _tcb_set(curthread->tcb); + + if (first) { + SIGFILLSET(sigset); + __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); + _thr_signal_init(); + _thr_initial = curthread; + SIGDELSET(oldset, SIGCANCEL); + __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + } +} + +/* + * This function and pthread_create() do a lot of the same things. + * It'd be nice to consolidate the common stuff in one place. + */ +static void +init_main_thread(struct pthread *thread) +{ + /* Setup the thread attributes. */ + thread->tid = _thr_get_tid(); + thread->attr = _pthread_attr_default; + /* + * Set up the thread stack. + * + * Create a red zone below the main stack. All other stacks + * are constrained to a maximum size by the parameters + * passed to mmap(), but this stack is only limited by + * resource limits, so this stack needs an explicitly mapped + * red zone to protect the thread stack that is just beyond. + */ + if (mmap((void *)_usrstack - THR_STACK_INITIAL - + _thr_guard_default, _thr_guard_default, 0, MAP_ANON, + -1, 0) == MAP_FAILED) + PANIC("Cannot allocate red zone for initial thread"); + + /* + * Mark the stack as an application supplied stack so that it + * isn't deallocated. + * + * XXX - I'm not sure it would hurt anything to deallocate + * the main thread stack because deallocation doesn't + * actually free() it; it just puts it in the free + * stack queue for later reuse. + */ + thread->attr.stackaddr_attr = (void *)_usrstack - THR_STACK_INITIAL; + thread->attr.stacksize_attr = THR_STACK_INITIAL; + thread->attr.guardsize_attr = _thr_guard_default; + thread->attr.flags |= THR_STACK_USER; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + thread->magic = THR_MAGIC; + + thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; + thread->name = strdup("initial thread"); + + /* Default the priority of the initial thread: */ + thread->base_priority = THR_DEFAULT_PRIORITY; + thread->active_priority = THR_DEFAULT_PRIORITY; + thread->inherited_priority = 0; + + /* Initialize the mutex queue: */ + TAILQ_INIT(&thread->mutexq); + TAILQ_INIT(&thread->pri_mutexq); + + thread->state = PS_RUNNING; + thread->uniqueid = 0; + + /* Others cleared to zero by thr_alloc() */ +} + +static void +init_private(void) +{ + size_t len; + int mib[2]; + + _thr_umtx_init(&_mutex_static_lock); + _thr_umtx_init(&_cond_static_lock); + _thr_umtx_init(&_rwlock_static_lock); + _thr_umtx_init(&_keytable_lock); + _thr_umtx_init(&_thr_atfork_lock); + _thr_spinlock_init(); + _thr_list_init(); + + /* + * Avoid reinitializing some things if they don't need to be, + * e.g. after a fork(). + */ + if (init_once == 0) { + /* Find the stack top */ + mib[0] = CTL_KERN; + mib[1] = KERN_USRSTACK; + len = sizeof (_usrstack); + if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) + PANIC("Cannot get kern.usrstack from sysctl"); + _thr_page_size = getpagesize(); + _thr_guard_default = _thr_page_size; + _pthread_attr_default.guardsize_attr = _thr_guard_default; + + TAILQ_INIT(&_thr_atfork_list); +#ifdef SYSTEM_SCOPE_ONLY + _thread_scope_system = 1; +#else + if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL) + _thread_scope_system = 1; + else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL) + _thread_scope_system = -1; +#endif + } + init_once = 1; +} + +void +_thread_init(void) +{ + _libpthread_init(NULL); +} + +extern int _thread_autoinit_dummy_decl; +int _thread_autoinit_dummy_decl = 0; diff --git a/lib/libthread_xu/thread/thr_join.c b/lib/libthread_xu/thread/thr_join.c new file mode 100644 index 0000000000..626b0d398f --- /dev/null +++ b/lib/libthread_xu/thread/thr_join.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_join.c,v 1.28 2003/12/09 02:20:56 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_join.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_join, pthread_join); + +static void backout_join(void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *pthread = (struct pthread *)arg; + + THREAD_LIST_LOCK(curthread); + pthread->joiner = NULL; + THREAD_LIST_UNLOCK(curthread); +} + +int +_pthread_join(pthread_t pthread, void **thread_return) +{ + struct pthread *curthread = _get_curthread(); + void *tmp; + long state; + int oldcancel; + int ret = 0; + + if (pthread == NULL) + return (EINVAL); + + if (pthread == curthread) + return (EDEADLK); + + THREAD_LIST_LOCK(curthread); + if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) { + ret = ESRCH; + } else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) { + ret = ESRCH; + } else if (pthread->joiner != NULL) { + /* Multiple joiners are not supported. */ + ret = ENOTSUP; + } + if (ret) { + THREAD_LIST_UNLOCK(curthread); + return (ret); + } + /* Set the running thread to be the joiner: */ + pthread->joiner = curthread; + + THREAD_LIST_UNLOCK(curthread); + + THR_CLEANUP_PUSH(curthread, backout_join, pthread); + oldcancel = _thr_cancel_enter(curthread); + + while ((state = pthread->state) != PS_DEAD) { + _thr_umtx_wait(&pthread->state, state, NULL); + } + + _thr_cancel_leave(curthread, oldcancel); + THR_CLEANUP_POP(curthread, 0); + + tmp = pthread->ret; + THREAD_LIST_LOCK(curthread); + pthread->tlflags |= TLFLAGS_DETACHED; + THR_GCLIST_ADD(pthread); + THREAD_LIST_UNLOCK(curthread); + + if (thread_return != NULL) + *thread_return = tmp; + + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_kern.c b/lib/libthread_xu/thread/thr_kern.c new file mode 100644 index 0000000000..5c29c80ee8 --- /dev/null +++ b/lib/libthread_xu/thread/thr_kern.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005 David Xu + * 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 unmodified, 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 ``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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_kern.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include "thr_private.h" + +/*#define DEBUG_THREAD_KERN */ +#ifdef DEBUG_THREAD_KERN +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +/* + * This is called when the first thread (other than the initial + * thread) is created. + */ +int +_thr_setthreaded(int threaded) +{ + if (((threaded == 0) ^ (__isthreaded == 0)) == 0) + return (0); + + __isthreaded = threaded; +#if 0 + if (threaded != 0) { + _thr_rtld_init(); + } else { + _thr_rtld_fini(); + } +#endif + return (0); +} + +void +_thr_signal_block(struct pthread *curthread) +{ + sigset_t set; + + if (curthread->sigblock > 0) { + curthread->sigblock++; + return; + } + SIGFILLSET(set); + SIGDELSET(set, SIGBUS); + SIGDELSET(set, SIGILL); + SIGDELSET(set, SIGFPE); + SIGDELSET(set, SIGSEGV); + SIGDELSET(set, SIGTRAP); + __sys_sigprocmask(SIG_BLOCK, &set, &curthread->sigmask); + curthread->sigblock++; +} + +void +_thr_signal_unblock(struct pthread *curthread) +{ + if (--curthread->sigblock == 0) + __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); +} + +void +_thr_assert_lock_level() +{ + PANIC("locklevel <= 0"); +} + +int +_thr_send_sig(struct pthread *thread, int sig) +{ + return (kill(thread->tid, sig)); +} + +int +_thr_get_tid() +{ + return (getpid()); +} diff --git a/lib/libthread_xu/thread/thr_kill.c b/lib/libthread_xu/thread/thr_kill.c new file mode 100644 index 0000000000..2902a0bff0 --- /dev/null +++ b/lib/libthread_xu/thread/thr_kill.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1997 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_kill.c,v 1.16 2003/06/28 09:55:02 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_kill.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_kill, pthread_kill); + +int +_pthread_kill(pthread_t pthread, int sig) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* Check for invalid signal numbers: */ + if (sig < 0 || sig > _SIG_MAXSIG) + /* Invalid signal: */ + ret = EINVAL; + /* + * Ensure the thread is in the list of active threads, and the + * signal is valid (signal 0 specifies error checking only) and + * not being ignored: + */ + else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) + == 0) { + if (sig > 0) + _thr_send_sig(pthread, sig); + _thr_ref_delete(curthread, pthread); + } + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_list.c b/lib/libthread_xu/thread/thr_list.c new file mode 100644 index 0000000000..0483717e37 --- /dev/null +++ b/lib/libthread_xu/thread/thr_list.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2005 David Xu + * Copyright (C) 2003 Daniel M. Eischen + * 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 unmodified, 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 ``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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_list.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include + +#include +#include +#include + +#include "thr_private.h" +#include "libc_private.h" + +/*#define DEBUG_THREAD_LIST */ +#ifdef DEBUG_THREAD_LIST +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +/* + * Define a high water mark for the maximum number of threads that + * will be cached. Once this level is reached, any extra threads + * will be free()'d. + */ +#define MAX_CACHED_THREADS 100 + +/* + * We've got to keep track of everything that is allocated, not only + * to have a speedy free list, but also so they can be deallocated + * after a fork(). + */ +static TAILQ_HEAD(, pthread) free_threadq; +static umtx_t free_thread_lock; +static umtx_t tcb_lock; +static int free_thread_count = 0; +static int inited = 0; +static u_int64_t next_uniqueid = 1; + +LIST_HEAD(thread_hash_head, pthread); +#define HASH_QUEUES 128 +static struct thread_hash_head thr_hashtable[HASH_QUEUES]; +#define THREAD_HASH(thrd) (((unsigned long)thrd >> 12) % HASH_QUEUES) + +static void thr_destroy(struct pthread *curthread, struct pthread *thread); + +void +_thr_list_init(void) +{ + int i; + + _gc_count = 0; + _thr_umtx_init(&_thr_list_lock); + TAILQ_INIT(&_thread_list); + TAILQ_INIT(&free_threadq); + _thr_umtx_init(&free_thread_lock); + _thr_umtx_init(&tcb_lock); + if (inited) { + for (i = 0; i < HASH_QUEUES; ++i) + LIST_INIT(&thr_hashtable[i]); + } + inited = 1; +} + +void +_thr_gc(struct pthread *curthread) +{ + struct pthread *td, *td_next; + TAILQ_HEAD(, pthread) worklist; + + TAILQ_INIT(&worklist); + THREAD_LIST_LOCK(curthread); + + /* Check the threads waiting for GC. */ + for (td = TAILQ_FIRST(&_thread_gc_list); td != NULL; td = td_next) { + td_next = TAILQ_NEXT(td, gcle); + if (td->terminated == 0) { + /* make sure we are not still in userland */ + continue; + } + _thr_stack_free(&td->attr); + if (((td->tlflags & TLFLAGS_DETACHED) != 0) && + (td->refcount == 0)) { + THR_GCLIST_REMOVE(td); + /* + * The thread has detached and is no longer + * referenced. It is safe to remove all + * remnants of the thread. + */ + THR_LIST_REMOVE(td); + TAILQ_INSERT_HEAD(&worklist, td, gcle); + } + } + THREAD_LIST_UNLOCK(curthread); + + while ((td = TAILQ_FIRST(&worklist)) != NULL) { + TAILQ_REMOVE(&worklist, td, gcle); + /* + * XXX we don't free initial thread, because there might + * have some code referencing initial thread. + */ + if (td == _thr_initial) { + DBG_MSG("Initial thread won't be freed\n"); + continue; + } + + DBG_MSG("Freeing thread %p\n", td); + _thr_free(curthread, td); + } +} + +struct pthread * +_thr_alloc(struct pthread *curthread) +{ + struct pthread *thread = NULL; + struct tcb *tcb = NULL; + + if (curthread != NULL) { + if (GC_NEEDED()) + _thr_gc(curthread); + if (free_thread_count > 0) { + THR_LOCK_ACQUIRE(curthread, &free_thread_lock); + if ((thread = TAILQ_FIRST(&free_threadq)) != NULL) { + TAILQ_REMOVE(&free_threadq, thread, tle); + tcb = thread->tcb; + free_thread_count--; + } + THR_LOCK_RELEASE(curthread, &free_thread_lock); + } + } + if ((thread == NULL) && + ((thread = malloc(sizeof(struct pthread))) != NULL)) { + if (curthread) { + THR_LOCK_ACQUIRE(curthread, &tcb_lock); + tcb = _tcb_ctor(thread, 0 /* not initial tls */); + THR_LOCK_RELEASE(curthread, &tcb_lock); + } else { + tcb = _tcb_ctor(thread, 1 /* initial tls */); + } + if (tcb == NULL) { + free(thread); + thread = NULL; + } + } + if (thread) { + memset(thread, 0, sizeof(*thread)); + thread->tcb = tcb; + } + return (thread); +} + +void +_thr_free(struct pthread *curthread, struct pthread *thread) +{ + DBG_MSG("Freeing thread %p\n", thread); + if (thread->name) { + free(thread->name); + thread->name = NULL; + } + if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) { + thr_destroy(curthread, thread); + } else { + /* Add the thread to the free thread list. */ + THR_LOCK_ACQUIRE(curthread, &free_thread_lock); + TAILQ_INSERT_TAIL(&free_threadq, thread, tle); + free_thread_count++; + THR_LOCK_RELEASE(curthread, &free_thread_lock); + } +} + +static void +thr_destroy(struct pthread *curthread, struct pthread *thread) +{ + if (curthread) { + THR_LOCK_ACQUIRE(curthread, &tcb_lock); + _tcb_dtor(thread->tcb); + THR_LOCK_RELEASE(curthread, &tcb_lock); + } else { + _tcb_dtor(thread->tcb); + } + free(thread); +} + +/* + * Add an active thread: + * + * o Assign the thread a unique id (which GDB uses to track + * threads. + * o Add the thread to the list of all threads and increment + * number of active threads. + */ +void +_thr_link(struct pthread *curthread, struct pthread *thread) +{ + THREAD_LIST_LOCK(curthread); + /* + * Initialize the unique id (which GDB uses to track + * threads), add the thread to the list of all threads, + * and + */ + thread->uniqueid = next_uniqueid++; + THR_LIST_ADD(thread); + if (thread->attr.flags & PTHREAD_DETACHED) + thread->tlflags |= TLFLAGS_DETACHED; + _thread_active_threads++; + THREAD_LIST_UNLOCK(curthread); +} + +/* + * Remove an active thread. + */ +void +_thr_unlink(struct pthread *curthread, struct pthread *thread) +{ + THREAD_LIST_LOCK(curthread); + THR_LIST_REMOVE(thread); + _thread_active_threads--; + THREAD_LIST_UNLOCK(curthread); +} + +void +_thr_hash_add(struct pthread *thread) +{ + struct thread_hash_head *head; + + head = &thr_hashtable[THREAD_HASH(thread)]; + LIST_INSERT_HEAD(head, thread, hle); +} + +void +_thr_hash_remove(struct pthread *thread) +{ + LIST_REMOVE(thread, hle); +} + +struct pthread * +_thr_hash_find(struct pthread *thread) +{ + struct pthread *td; + struct thread_hash_head *head; + + head = &thr_hashtable[THREAD_HASH(thread)]; + LIST_FOREACH(td, head, hle) { + if (td == thread) + return (thread); + } + return (NULL); +} + +/* + * Find a thread in the linked list of active threads and add a reference + * to it. Threads with positive reference counts will not be deallocated + * until all references are released. + */ +int +_thr_ref_add(struct pthread *curthread, struct pthread *thread, + int include_dead) +{ + int ret; + + if (thread == NULL) + /* Invalid thread: */ + return (EINVAL); + + THREAD_LIST_LOCK(curthread); + if ((ret = _thr_find_thread(curthread, thread, include_dead)) == 0) { + thread->refcount++; + } + THREAD_LIST_UNLOCK(curthread); + + /* Return zero if the thread exists: */ + return (ret); +} + +void +_thr_ref_delete(struct pthread *curthread, struct pthread *thread) +{ + if (thread != NULL) { + THREAD_LIST_LOCK(curthread); + thread->refcount--; + if ((thread->refcount == 0) && + (thread->tlflags & TLFLAGS_GC_SAFE) != 0) + THR_GCLIST_ADD(thread); + THREAD_LIST_UNLOCK(curthread); + } +} + +int +_thr_find_thread(struct pthread *curthread, struct pthread *thread, + int include_dead) +{ + struct pthread *pthread; + + if (thread == NULL) + /* Invalid thread: */ + return (EINVAL); + + pthread = _thr_hash_find(thread); + if (pthread) { + if (include_dead == 0 && pthread->state == PS_DEAD) { + pthread = NULL; + } + } + + /* Return zero if the thread exists: */ + return ((pthread != NULL) ? 0 : ESRCH); +} diff --git a/lib/libthread_xu/thread/thr_main_np.c b/lib/libthread_xu/thread/thr_main_np.c new file mode 100644 index 0000000000..9f9da3ff27 --- /dev/null +++ b/lib/libthread_xu/thread/thr_main_np.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein + * 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_main_np.c,v 1.5 2003/04/18 05:04:16 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_main_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_main_np, pthread_main_np); + +/* + * Provide the equivelant to Solaris thr_main() function + */ +int +_pthread_main_np() +{ + + if (!_thr_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thr_initial) ? 1 : 0); +} diff --git a/lib/libthread_xu/thread/thr_multi_np.c b/lib/libthread_xu/thread/thr_multi_np.c new file mode 100644 index 0000000000..2d6192ac17 --- /dev/null +++ b/lib/libthread_xu/thread/thr_multi_np.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_multi_np.c,v 1.7 2002/05/24 04:32:28 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_multi_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include + +__weak_reference(_pthread_multi_np, pthread_multi_np); + +int +_pthread_multi_np() +{ + + /* Return to multi-threaded scheduling mode: */ + /* + * XXX - Do we want to do this? + * __is_threaded = 1; + */ + pthread_resume_all_np(); + return (0); +} diff --git a/lib/libthread_xu/thread/thr_mutex.c b/lib/libthread_xu/thread/thr_mutex.c new file mode 100644 index 0000000000..7cbde9afa4 --- /dev/null +++ b/lib/libthread_xu/thread/thr_mutex.c @@ -0,0 +1,1676 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_mutex.c,v 1.46 2004/10/31 05:03:50 green Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_mutex.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include +#include "thr_private.h" + +#if defined(_PTHREADS_INVARIANTS) +#define MUTEX_INIT_LINK(m) do { \ + (m)->m_qe.tqe_prev = NULL; \ + (m)->m_qe.tqe_next = NULL; \ +} while (0) +#define MUTEX_ASSERT_IS_OWNED(m) do { \ + if ((m)->m_qe.tqe_prev == NULL) \ + PANIC("mutex is not on list"); \ +} while (0) +#define MUTEX_ASSERT_NOT_OWNED(m) do { \ + if (((m)->m_qe.tqe_prev != NULL) || \ + ((m)->m_qe.tqe_next != NULL)) \ + PANIC("mutex is on list"); \ +} while (0) +#define THR_ASSERT_NOT_IN_SYNCQ(thr) do { \ + THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \ + "thread in syncq when it shouldn't be."); \ +} while (0); +#else +#define MUTEX_INIT_LINK(m) +#define MUTEX_ASSERT_IS_OWNED(m) +#define MUTEX_ASSERT_NOT_OWNED(m) +#define THR_ASSERT_NOT_IN_SYNCQ(thr) +#endif + +#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0) +#define MUTEX_DESTROY(m) do { \ + free(m); \ +} while (0) + + +/* + * Prototypes + */ +static long mutex_handoff(struct pthread *, struct pthread_mutex *); +static int mutex_self_trylock(struct pthread *, pthread_mutex_t); +static int mutex_self_lock(struct pthread *, pthread_mutex_t, + const struct timespec *abstime); +static int mutex_unlock_common(pthread_mutex_t *, int); +static void mutex_priority_adjust(struct pthread *, pthread_mutex_t); +static void mutex_rescan_owned (struct pthread *, struct pthread *, + struct pthread_mutex *); +#if 0 +static pthread_t mutex_queue_deq(pthread_mutex_t); +#endif +static void mutex_queue_remove(pthread_mutex_t, pthread_t); +static void mutex_queue_enq(pthread_mutex_t, pthread_t); + +__weak_reference(__pthread_mutex_init, pthread_mutex_init); +__weak_reference(__pthread_mutex_lock, pthread_mutex_lock); +__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock); +__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); + +/* Single underscore versions provided for libc internal usage: */ +/* No difference between libc and application usage of these: */ +__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy); +__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock); + +static int +mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr, int private) +{ + struct pthread_mutex *pmutex; + enum pthread_mutextype type; + int protocol; + int ceiling; + int flags; + int ret = 0; + + /* Check if default mutex attributes: */ + if (mutex_attr == NULL || *mutex_attr == NULL) { + /* Default to a (error checking) POSIX mutex: */ + type = PTHREAD_MUTEX_ERRORCHECK; + protocol = PTHREAD_PRIO_NONE; + ceiling = THR_MAX_PRIORITY; + flags = 0; + } + + /* Check mutex type: */ + else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) || + ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Check mutex protocol: */ + else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) || + ((*mutex_attr)->m_protocol > PTHREAD_PRIO_PROTECT)) + /* Return an invalid argument error: */ + ret = EINVAL; + + else { + /* Use the requested mutex type and protocol: */ + type = (*mutex_attr)->m_type; + protocol = (*mutex_attr)->m_protocol; + ceiling = (*mutex_attr)->m_ceiling; + flags = (*mutex_attr)->m_flags; + } + + /* Check no errors so far: */ + if (ret == 0) { + if ((pmutex = (pthread_mutex_t) + malloc(sizeof(struct pthread_mutex))) == NULL) { + ret = ENOMEM; + } else { + _thr_umtx_init(&pmutex->m_lock); + /* Set the mutex flags: */ + pmutex->m_flags = flags; + + /* Process according to mutex type: */ + switch (type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + /* Nothing to do here. */ + break; + + /* Single UNIX Spec 2 recursive mutex: */ + case PTHREAD_MUTEX_RECURSIVE: + /* Reset the mutex count: */ + pmutex->m_count = 0; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + if (ret == 0) { + /* Initialise the rest of the mutex: */ + TAILQ_INIT(&pmutex->m_queue); + pmutex->m_flags |= MUTEX_FLAGS_INITED; + if (private) + pmutex->m_flags |= MUTEX_FLAGS_PRIVATE; + pmutex->m_owner = NULL; + pmutex->m_type = type; + pmutex->m_protocol = protocol; + pmutex->m_refcount = 0; + if (protocol == PTHREAD_PRIO_PROTECT) + pmutex->m_prio = ceiling; + else + pmutex->m_prio = -1; + pmutex->m_saved_prio = 0; + MUTEX_INIT_LINK(pmutex); + *mutex = pmutex; + } else { + /* Free the mutex lock structure: */ + MUTEX_DESTROY(pmutex); + *mutex = NULL; + } + } + } + /* Return the completion status: */ + return (ret); +} + +static int +init_static(struct pthread *thread, pthread_mutex_t *mutex) +{ + int ret; + + THR_LOCK_ACQUIRE(thread, &_mutex_static_lock); + + if (*mutex == NULL) + ret = mutex_init(mutex, NULL, 0); + else + ret = 0; + + THR_LOCK_RELEASE(thread, &_mutex_static_lock); + + return (ret); +} + +static int +init_static_private(struct pthread *thread, pthread_mutex_t *mutex) +{ + int ret; + + THR_LOCK_ACQUIRE(thread, &_mutex_static_lock); + + if (*mutex == NULL) + ret = mutex_init(mutex, NULL, 1); + else + ret = 0; + + THR_LOCK_RELEASE(thread, &_mutex_static_lock); + + return (ret); +} + +int +_pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr) +{ + return mutex_init(mutex, mutex_attr, 1); +} + +int +__pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr) +{ + return mutex_init(mutex, mutex_attr, 0); +} + +int +_mutex_reinit(pthread_mutex_t *mutex) +{ + _thr_umtx_init(&(*mutex)->m_lock); + TAILQ_INIT(&(*mutex)->m_queue); + MUTEX_INIT_LINK(*mutex); + (*mutex)->m_owner = NULL; + (*mutex)->m_count = 0; + (*mutex)->m_refcount = 0; + (*mutex)->m_prio = 0; + (*mutex)->m_saved_prio = 0; + return (0); +} + +void +_mutex_fork(struct pthread *curthread) +{ + struct pthread_mutex *m; + + TAILQ_FOREACH(m, &curthread->mutexq, m_qe) + m->m_lock = UMTX_LOCKED; + + /* Clear contender for priority mutexes */ + TAILQ_FOREACH(m, &curthread->pri_mutexq, m_qe) { + /* clear another thread locked us */ + _thr_umtx_init(&m->m_lock); + TAILQ_INIT(&m->m_queue); + } +} + +int +_pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + pthread_mutex_t m; + int ret = 0; + + if (mutex == NULL || *mutex == NULL) + ret = EINVAL; + else { + /* + * Try to lock the mutex structure, we only need to + * try once, if failed, the mutex is in used. + */ + ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock); + if (ret) + return (ret); + + /* + * Check mutex other fields to see if this mutex is + * in use. Mostly for prority mutex types, or there + * are condition variables referencing it. + */ + if (((*mutex)->m_owner != NULL) || + (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) || + ((*mutex)->m_refcount != 0)) { + THR_UMTX_UNLOCK(curthread, &(*mutex)->m_lock); + ret = EBUSY; + } else { + /* + * Save a pointer to the mutex so it can be free'd + * and set the caller's pointer to NULL: + */ + m = *mutex; + *mutex = NULL; + + /* Unlock the mutex structure: */ + _thr_umtx_unlock(&m->m_lock, curthread->tid); + + /* + * Free the memory allocated for the mutex + * structure: + */ + MUTEX_ASSERT_NOT_OWNED(m); + MUTEX_DESTROY(m); + } + } + + /* Return the completion status: */ + return (ret); +} + +static int +mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex) +{ + int ret = 0; + + THR_ASSERT((mutex != NULL) && (*mutex != NULL), + "Uninitialized mutex in mutex_trylock_common"); + + /* Short cut for simple mutex. */ + if ((*mutex)->m_protocol == PTHREAD_PRIO_NONE) { + ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock); + if (ret == 0) { + (*mutex)->m_owner = curthread; + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) { + ret = mutex_self_trylock(curthread, *mutex); + } /* else {} */ + + return (ret); + } + + /* Code for priority mutex */ + + /* Lock the mutex structure: */ + THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*mutex)->m_queue); + MUTEX_INIT_LINK(*mutex); + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + } + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = curthread; + + THR_LOCK(curthread); + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The mutex takes on the attributes of the + * running thread when there are no waiters. + */ + (*mutex)->m_prio = curthread->active_priority; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = (*mutex)->m_prio; + THR_UNLOCK(curthread); + + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->pri_mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_trylock(curthread, *mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (curthread->active_priority > (*mutex)->m_prio) + ret = EINVAL; + + /* Check if this mutex is not locked: */ + else if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = curthread; + + THR_LOCK(curthread); + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority. + */ + curthread->active_priority = (*mutex)->m_prio; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = + (*mutex)->m_prio; + THR_UNLOCK(curthread); + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->pri_mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_trylock(curthread, *mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock); + + /* Return the completion status: */ + return (ret); +} + +int +__pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if ((*mutex != NULL) || + ((ret = init_static(curthread, mutex)) == 0)) + ret = mutex_trylock_common(curthread, mutex); + + return (ret); +} + +int +_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking the mutex private (delete safe): + */ + if ((*mutex != NULL) || + ((ret = init_static_private(curthread, mutex)) == 0)) + ret = mutex_trylock_common(curthread, mutex); + + return (ret); +} + +static int +mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m, + const struct timespec * abstime) +{ + struct timespec ts, ts2; + long cycle; + int ret = 0; + + THR_ASSERT((m != NULL) && (*m != NULL), + "Uninitialized mutex in mutex_lock_common"); + + if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000)) + return (EINVAL); + + /* Short cut for simple mutex. */ + + if ((*m)->m_protocol == PTHREAD_PRIO_NONE) { + /* Default POSIX mutex: */ + ret = THR_UMTX_TRYLOCK(curthread, &(*m)->m_lock); + if (ret == 0) { + (*m)->m_owner = curthread; + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*m); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*m), m_qe); + } else if ((*m)->m_owner == curthread) { + ret = mutex_self_lock(curthread, *m, abstime); + } else { + if (abstime == NULL) { + THR_UMTX_LOCK(curthread, &(*m)->m_lock); + ret = 0; + } else { + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + ret = THR_UMTX_TIMEDLOCK(curthread, + &(*m)->m_lock, &ts2); + /* + * Timed out wait is not restarted if + * it was interrupted, not worth to do it. + */ + if (ret == EINTR) + ret = ETIMEDOUT; + } + if (ret == 0) { + (*m)->m_owner = curthread; + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*m); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*m), m_qe); + } + } + return (ret); + } + + /* Code for priority mutex */ + + /* + * Enter a loop waiting to become the mutex owner. We need a + * loop in case the waiting thread is interrupted by a signal + * to execute a signal handler. It is not (currently) possible + * to remain in the waiting queue while running a handler. + * Instead, the thread is interrupted and backed out of the + * waiting queue prior to executing the signal handler. + */ + do { + /* Lock the mutex structure: */ + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*m)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*m)->m_queue); + (*m)->m_flags |= MUTEX_FLAGS_INITED; + MUTEX_INIT_LINK(*m); + } + + /* Process according to mutex type: */ + switch ((*m)->m_protocol) { + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*m)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*m)->m_owner = curthread; + + THR_LOCK(curthread); + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The mutex takes on attributes of the + * running thread when there are no waiters. + * Make sure the thread's scheduling lock is + * held while priorities are adjusted. + */ + (*m)->m_prio = curthread->active_priority; + (*m)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = (*m)->m_prio; + THR_UNLOCK(curthread); + + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*m); + TAILQ_INSERT_TAIL(&curthread->pri_mutexq, + (*m), m_qe); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } else if ((*m)->m_owner == curthread) { + ret = mutex_self_lock(curthread, *m, abstime); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } else { + /* + * Join the queue of threads waiting to lock + * the mutex and save a pointer to the mutex. + */ + mutex_queue_enq(*m, curthread); + curthread->data.mutex = *m; + + if (curthread->active_priority > (*m)->m_prio) + /* Adjust priorities: */ + mutex_priority_adjust(curthread, *m); + + THR_LOCK(curthread); + cycle = curthread->cycle; + THR_UNLOCK(curthread); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + ret = _thr_umtx_wait(&curthread->cycle, cycle, + &ts2); + if (ret == EINTR) + ret = 0; + + if (THR_IN_MUTEXQ(curthread)) { + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + mutex_queue_remove(*m, curthread); + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } + /* + * Only clear these after assuring the + * thread is dequeued. + */ + curthread->data.mutex = NULL; + } + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (curthread->active_priority > (*m)->m_prio) { + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + ret = EINVAL; + } + /* Check if this mutex is not locked: */ + else if ((*m)->m_owner == NULL) { + /* + * Lock the mutex for the running + * thread: + */ + (*m)->m_owner = curthread; + + THR_LOCK(curthread); + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority. Make sure the thread's + * scheduling lock is held while priorities + * are adjusted. + */ + curthread->active_priority = (*m)->m_prio; + (*m)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = (*m)->m_prio; + THR_UNLOCK(curthread); + + /* Add to the list of owned mutexes: */ + MUTEX_ASSERT_NOT_OWNED(*m); + TAILQ_INSERT_TAIL(&curthread->pri_mutexq, + (*m), m_qe); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } else if ((*m)->m_owner == curthread) { + ret = mutex_self_lock(curthread, *m, abstime); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } else { + /* + * Join the queue of threads waiting to lock + * the mutex and save a pointer to the mutex. + */ + mutex_queue_enq(*m, curthread); + curthread->data.mutex = *m; + + /* Clear any previous error: */ + curthread->error = 0; + + THR_LOCK(curthread); + cycle = curthread->cycle; + THR_UNLOCK(curthread); + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + ret = _thr_umtx_wait(&curthread->cycle, cycle, + &ts2); + if (ret == EINTR) + ret = 0; + + curthread->data.mutex = NULL; + if (THR_IN_MUTEXQ(curthread)) { + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + mutex_queue_remove(*m, curthread); + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } + /* + * Only clear these after assuring the + * thread is dequeued. + */ + curthread->data.mutex = NULL; + + /* + * The threads priority may have changed while + * waiting for the mutex causing a ceiling + * violation. + */ + ret = curthread->error; + curthread->error = 0; + } + break; + + /* Trap invalid mutex types: */ + default: + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + } while (((*m)->m_owner != curthread) && (ret == 0)); + + /* Return the completion status: */ + return (ret); +} + +int +__pthread_mutex_lock(pthread_mutex_t *m) +{ + struct pthread *curthread; + int ret = 0; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, NULL); + + return (ret); +} + +__strong_reference(__pthread_mutex_lock, _thr_mutex_lock); + +int +_pthread_mutex_lock(pthread_mutex_t *m) +{ + struct pthread *curthread; + int ret = 0; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + if ((*m != NULL) || + ((ret = init_static_private(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, NULL); + + return (ret); +} + +int +__pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *abs_timeout) +{ + struct pthread *curthread; + int ret = 0; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, abs_timeout); + + return (ret); +} + +int +_pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *abs_timeout) +{ + struct pthread *curthread; + int ret = 0; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + if ((*m != NULL) || + ((ret = init_static_private(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, abs_timeout); + + return (ret); +} + +int +_pthread_mutex_unlock(pthread_mutex_t *m) +{ + return (mutex_unlock_common(m, /* add reference */ 0)); +} + +__strong_reference(_pthread_mutex_unlock, _thr_mutex_unlock); + +int +_mutex_cv_unlock(pthread_mutex_t *m) +{ + return (mutex_unlock_common(m, /* add reference */ 1)); +} + +int +_mutex_cv_lock(pthread_mutex_t *m) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + if ((ret = _pthread_mutex_lock(m)) == 0) + (*m)->m_refcount--; + return (ret); +} + +static int +mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m) +{ + int ret; + + switch (m->m_type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + ret = EBUSY; + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + if (m->m_count + 1 > 0) { + m->m_count++; + ret = 0; + } else + ret = EAGAIN; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return (ret); +} + +static int +mutex_self_lock(struct pthread *curthread, pthread_mutex_t m, + const struct timespec *abstime) +{ + struct timespec ts1, ts2; + int ret; + + switch (m->m_type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + if (abstime) { + clock_gettime(CLOCK_REALTIME, &ts1); + TIMESPEC_SUB(&ts2, abstime, &ts1); + __sys_nanosleep(&ts2, NULL); + ret = ETIMEDOUT; + } else { + /* + * POSIX specifies that mutexes should return + * EDEADLK if a recursive lock is detected. + */ + ret = EDEADLK; + } + break; + + case PTHREAD_MUTEX_NORMAL: + /* + * What SS2 define as a 'normal' mutex. Intentionally + * deadlock on attempts to get a lock you already own. + */ + ret = 0; + if (m->m_protocol != PTHREAD_PRIO_NONE) { + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &m->m_lock); + } + if (abstime) { + clock_gettime(CLOCK_REALTIME, &ts1); + TIMESPEC_SUB(&ts2, abstime, &ts1); + __sys_nanosleep(&ts2, NULL); + ret = ETIMEDOUT; + } else { + ts1.tv_sec = 30; + ts1.tv_nsec = 0; + for (;;) + __sys_nanosleep(&ts1, NULL); + } + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + if (m->m_count + 1 > 0) { + m->m_count++; + ret = 0; + } else + ret = EAGAIN; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return (ret); +} + +static int +mutex_unlock_common(pthread_mutex_t *m, int add_reference) +{ + struct pthread *curthread = _get_curthread(); + long tid = -1; + int ret = 0; + + if (m == NULL || *m == NULL) + ret = EINVAL; + else { + /* Short cut for simple mutex. */ + + if ((*m)->m_protocol == PTHREAD_PRIO_NONE) { + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if (__predict_false((*m)->m_owner != curthread)) { + ret = EPERM; + } else if (__predict_false( + (*m)->m_type == PTHREAD_MUTEX_RECURSIVE && + (*m)->m_count > 0)) { + /* Decrement the count: */ + (*m)->m_count--; + if (add_reference) + (*m)->m_refcount++; + } else { + /* + * Clear the count in case this is a recursive + * mutex. + */ + (*m)->m_count = 0; + (*m)->m_owner = NULL; + /* Remove the mutex from the threads queue. */ + MUTEX_ASSERT_IS_OWNED(*m); + TAILQ_REMOVE(&curthread->mutexq, (*m), m_qe); + MUTEX_INIT_LINK(*m); + if (add_reference) + (*m)->m_refcount++; + /* + * Hand off the mutex to the next waiting + * thread. + */ + _thr_umtx_unlock(&(*m)->m_lock, curthread->tid); + } + return (ret); + } + + /* Code for priority mutex */ + + /* Lock the mutex structure: */ + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + + /* Process according to mutex type: */ + switch ((*m)->m_protocol) { + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*m)->m_owner != curthread) + ret = EPERM; + else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*m)->m_count > 0)) + /* Decrement the count: */ + (*m)->m_count--; + else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*m)->m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + THR_LOCK(curthread); + curthread->inherited_priority = + (*m)->m_saved_prio; + curthread->active_priority = + MAX(curthread->inherited_priority, + curthread->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + curthread->priority_mutex_count--; + THR_UNLOCK(curthread); + + /* Remove the mutex from the threads queue. */ + MUTEX_ASSERT_IS_OWNED(*m); + TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq, + (*m), m_qe); + MUTEX_INIT_LINK(*m); + + /* + * Hand off the mutex to the next waiting + * thread: + */ + tid = mutex_handoff(curthread, *m); + } + break; + + /* POSIX priority ceiling mutex: */ + case PTHREAD_PRIO_PROTECT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*m)->m_owner != curthread) + ret = EPERM; + else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*m)->m_count > 0)) + /* Decrement the count: */ + (*m)->m_count--; + else { + /* + * Clear the count in case this is a recursive + * mutex. + */ + (*m)->m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + THR_LOCK(curthread); + curthread->inherited_priority = + (*m)->m_saved_prio; + curthread->active_priority = + MAX(curthread->inherited_priority, + curthread->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + curthread->priority_mutex_count--; + THR_UNLOCK(curthread); + + /* Remove the mutex from the threads queue. */ + MUTEX_ASSERT_IS_OWNED(*m); + TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq, + (*m), m_qe); + MUTEX_INIT_LINK(*m); + + /* + * Hand off the mutex to the next waiting + * thread: + */ + tid = mutex_handoff(curthread, *m); + } + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + if ((ret == 0) && (add_reference != 0)) + /* Increment the reference count: */ + (*m)->m_refcount++; + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } + + /* Return the completion status: */ + return (ret); +} + + +/* + * This function is called when a change in base priority occurs for + * a thread that is holding or waiting for a priority protection or + * inheritence mutex. A change in a threads base priority can effect + * changes to active priorities of other threads and to the ordering + * of mutex locking by waiting threads. + * + * This must be called without the target thread's scheduling lock held. + */ +void +_mutex_notify_priochange(struct pthread *curthread, struct pthread *pthread, + int propagate_prio) +{ + struct pthread_mutex *m; + + /* Adjust the priorites of any owned priority mutexes: */ + if (pthread->priority_mutex_count > 0) { + /* + * Rescan the mutexes owned by this thread and correct + * their priorities to account for this threads change + * in priority. This has the side effect of changing + * the threads active priority. + * + * Be sure to lock the first mutex in the list of owned + * mutexes. This acts as a barrier against another + * simultaneous call to change the threads priority + * and from the owning thread releasing the mutex. + */ + m = TAILQ_FIRST(&pthread->pri_mutexq); + if (m != NULL) { + THR_LOCK_ACQUIRE(curthread, &m->m_lock); + /* + * Make sure the thread still owns the lock. + */ + if (m == TAILQ_FIRST(&pthread->pri_mutexq)) + mutex_rescan_owned(curthread, pthread, + /* rescan all owned */ NULL); + THR_LOCK_RELEASE(curthread, &m->m_lock); + } + } + + /* + * If this thread is waiting on a priority inheritence mutex, + * check for priority adjustments. A change in priority can + * also cause a ceiling violation(*) for a thread waiting on + * a priority protection mutex; we don't perform the check here + * as it is done in pthread_mutex_unlock. + * + * (*) It should be noted that a priority change to a thread + * _after_ taking and owning a priority ceiling mutex + * does not affect ownership of that mutex; the ceiling + * priority is only checked before mutex ownership occurs. + */ + if (propagate_prio != 0) { + /* + * Lock the thread's scheduling queue. This is a bit + * convoluted; the "in synchronization queue flag" can + * only be cleared with both the thread's scheduling and + * mutex locks held. The thread's pointer to the wanted + * mutex is guaranteed to be valid during this time. + */ + THR_THREAD_LOCK(curthread, pthread); + + if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) || + ((m = pthread->data.mutex) == NULL)) + THR_THREAD_UNLOCK(curthread, pthread); + else { + /* + * This thread is currently waiting on a mutex; unlock + * the scheduling queue lock and lock the mutex. We + * can't hold both at the same time because the locking + * order could cause a deadlock. + */ + THR_THREAD_UNLOCK(curthread, pthread); + THR_LOCK_ACQUIRE(curthread, &m->m_lock); + + /* + * Check to make sure this thread is still in the + * same state (the lock above can yield the CPU to + * another thread or the thread may be running on + * another CPU). + */ + if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) && + (pthread->data.mutex == m)) { + /* + * Remove and reinsert this thread into + * the list of waiting threads to preserve + * decreasing priority order. + */ + mutex_queue_remove(m, pthread); + mutex_queue_enq(m, pthread); + + if (m->m_protocol == PTHREAD_PRIO_INHERIT) + /* Adjust priorities: */ + mutex_priority_adjust(curthread, m); + } + + /* Unlock the mutex structure: */ + THR_LOCK_RELEASE(curthread, &m->m_lock); + } + } +} + +/* + * Called when a new thread is added to the mutex waiting queue or + * when a threads priority changes that is already in the mutex + * waiting queue. + * + * This must be called with the mutex locked by the current thread. + */ +static void +mutex_priority_adjust(struct pthread *curthread, pthread_mutex_t mutex) +{ + pthread_mutex_t m = mutex; + struct pthread *pthread_next, *pthread = mutex->m_owner; + int done, temp_prio; + + /* + * Calculate the mutex priority as the maximum of the highest + * active priority of any waiting threads and the owning threads + * active priority(*). + * + * (*) Because the owning threads current active priority may + * reflect priority inherited from this mutex (and the mutex + * priority may have changed) we must recalculate the active + * priority based on the threads saved inherited priority + * and its base priority. + */ + pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, pthread->base_priority)); + + /* See if this mutex really needs adjusting: */ + if (temp_prio == m->m_prio) + /* No need to propagate the priority: */ + return; + + /* Set new priority of the mutex: */ + m->m_prio = temp_prio; + + /* + * Don't unlock the mutex passed in as an argument. It is + * expected to be locked and unlocked by the caller. + */ + done = 1; + do { + /* + * Save the threads priority before rescanning the + * owned mutexes: + */ + temp_prio = pthread->active_priority; + + /* + * Fix the priorities for all mutexes held by the owning + * thread since taking this mutex. This also has a + * potential side-effect of changing the threads priority. + * + * At this point the mutex is locked by the current thread. + * The owning thread can't release the mutex until it is + * unlocked, so we should be able to safely walk its list + * of owned mutexes. + */ + mutex_rescan_owned(curthread, pthread, m); + + /* + * If this isn't the first time through the loop, + * the current mutex needs to be unlocked. + */ + if (done == 0) + THR_LOCK_RELEASE(curthread, &m->m_lock); + + /* Assume we're done unless told otherwise: */ + done = 1; + + /* + * If the thread is currently waiting on a mutex, check + * to see if the threads new priority has affected the + * priority of the mutex. + */ + if ((temp_prio != pthread->active_priority) && + ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) && + ((m = pthread->data.mutex) != NULL) && + (m->m_protocol == PTHREAD_PRIO_INHERIT)) { + /* Lock the mutex structure: */ + THR_LOCK_ACQUIRE(curthread, &m->m_lock); + + /* + * Make sure the thread is still waiting on the + * mutex: + */ + if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) && + (m == pthread->data.mutex)) { + /* + * The priority for this thread has changed. + * Remove and reinsert this thread into the + * list of waiting threads to preserve + * decreasing priority order. + */ + mutex_queue_remove(m, pthread); + mutex_queue_enq(m, pthread); + + /* + * Grab the waiting thread with highest + * priority: + */ + pthread_next = TAILQ_FIRST(&m->m_queue); + + /* + * Calculate the mutex priority as the maximum + * of the highest active priority of any + * waiting threads and the owning threads + * active priority. + */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, + m->m_owner->base_priority)); + + if (temp_prio != m->m_prio) { + /* + * The priority needs to be propagated + * to the mutex this thread is waiting + * on and up to the owner of that mutex. + */ + m->m_prio = temp_prio; + pthread = m->m_owner; + + /* We're not done yet: */ + done = 0; + } + } + /* Only release the mutex if we're done: */ + if (done != 0) + THR_LOCK_RELEASE(curthread, &m->m_lock); + } + } while (done == 0); +} + +static void +mutex_rescan_owned(struct pthread *curthread, struct pthread *pthread, + struct pthread_mutex *mutex) +{ + struct pthread_mutex *m; + struct pthread *pthread_next; + int active_prio, inherited_prio; + + /* + * Start walking the mutexes the thread has taken since + * taking this mutex. + */ + if (mutex == NULL) { + /* + * A null mutex means start at the beginning of the owned + * mutex list. + */ + m = TAILQ_FIRST(&pthread->pri_mutexq); + + /* There is no inherited priority yet. */ + inherited_prio = 0; + } else { + /* + * The caller wants to start after a specific mutex. It + * is assumed that this mutex is a priority inheritence + * mutex and that its priority has been correctly + * calculated. + */ + m = TAILQ_NEXT(mutex, m_qe); + + /* Start inheriting priority from the specified mutex. */ + inherited_prio = mutex->m_prio; + } + active_prio = MAX(inherited_prio, pthread->base_priority); + + for (; m != NULL; m = TAILQ_NEXT(m, m_qe)) { + /* + * We only want to deal with priority inheritence + * mutexes. This might be optimized by only placing + * priority inheritence mutexes into the owned mutex + * list, but it may prove to be useful having all + * owned mutexes in this list. Consider a thread + * exiting while holding mutexes... + */ + if (m->m_protocol == PTHREAD_PRIO_INHERIT) { + /* + * Fix the owners saved (inherited) priority to + * reflect the priority of the previous mutex. + */ + m->m_saved_prio = inherited_prio; + + if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL) + /* Recalculate the priority of the mutex: */ + m->m_prio = MAX(active_prio, + pthread_next->active_priority); + else + m->m_prio = active_prio; + + /* Recalculate new inherited and active priorities: */ + inherited_prio = m->m_prio; + active_prio = MAX(m->m_prio, pthread->base_priority); + } + } + + /* + * Fix the threads inherited priority and recalculate its + * active priority. + */ + pthread->inherited_priority = inherited_prio; + active_prio = MAX(inherited_prio, pthread->base_priority); + + if (active_prio != pthread->active_priority) { + /* Lock the thread's scheduling queue: */ + THR_THREAD_LOCK(curthread, pthread); + + /* if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) */ + if (1) { + /* + * This thread is not in a run queue. Just set + * its active priority. + */ + pthread->active_priority = active_prio; + } + else { + /* + * This thread is in a run queue. Remove it from + * the queue before changing its priority: + */ + /* THR_RUNQ_REMOVE(pthread);*/ + /* + * POSIX states that if the priority is being + * lowered, the thread must be inserted at the + * head of the queue for its priority if it owns + * any priority protection or inheritence mutexes. + */ + if ((active_prio < pthread->active_priority) && + (pthread->priority_mutex_count > 0)) { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + /* THR_RUNQ_INSERT_HEAD(pthread); */ + } else { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + /* THR_RUNQ_INSERT_TAIL(pthread);*/ + } + } + THR_THREAD_UNLOCK(curthread, pthread); + } +} + +void +_mutex_unlock_private(pthread_t pthread) +{ + struct pthread_mutex *m, *m_next; + + for (m = TAILQ_FIRST(&pthread->pri_mutexq); m != NULL; m = m_next) { + m_next = TAILQ_NEXT(m, m_qe); + if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0) + pthread_mutex_unlock(&m); + } +} + +/* + * Dequeue a waiting thread from the head of a mutex queue in descending + * priority order. + * + * In order to properly dequeue a thread from the mutex queue and + * make it runnable without the possibility of errant wakeups, it + * is necessary to lock the thread's scheduling queue while also + * holding the mutex lock. + */ +static long +mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex) +{ + struct pthread *pthread; + long tid = -1; + + /* Keep dequeueing until we find a valid thread: */ + mutex->m_owner = NULL; + pthread = TAILQ_FIRST(&mutex->m_queue); + while (pthread != NULL) { + /* Take the thread's scheduling lock: */ + THR_THREAD_LOCK(curthread, pthread); + + /* Remove the thread from the mutex queue: */ + TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); + pthread->sflags &= ~THR_FLAGS_IN_SYNCQ; + + /* + * Only exit the loop if the thread hasn't been + * cancelled. + */ + switch (mutex->m_protocol) { + case PTHREAD_PRIO_NONE: + /* + * Assign the new owner and add the mutex to the + * thread's list of owned mutexes. + */ + mutex->m_owner = pthread; + TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe); + break; + + case PTHREAD_PRIO_INHERIT: + /* + * Assign the new owner and add the mutex to the + * thread's list of owned mutexes. + */ + mutex->m_owner = pthread; + TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe); + + /* Track number of priority mutexes owned: */ + pthread->priority_mutex_count++; + + /* + * Set the priority of the mutex. Since our waiting + * threads are in descending priority order, the + * priority of the mutex becomes the active priority + * of the thread we just dequeued. + */ + mutex->m_prio = pthread->active_priority; + + /* Save the owning threads inherited priority: */ + mutex->m_saved_prio = pthread->inherited_priority; + + /* + * The owning threads inherited priority now becomes + * his active priority (the priority of the mutex). + */ + pthread->inherited_priority = mutex->m_prio; + break; + + case PTHREAD_PRIO_PROTECT: + if (pthread->active_priority > mutex->m_prio) { + /* + * Either the mutex ceiling priority has + * been lowered and/or this threads priority + * has been raised subsequent to the thread + * being queued on the waiting list. + */ + pthread->error = EINVAL; + } + else { + /* + * Assign the new owner and add the mutex + * to the thread's list of owned mutexes. + */ + mutex->m_owner = pthread; + TAILQ_INSERT_TAIL(&pthread->pri_mutexq, + mutex, m_qe); + + /* Track number of priority mutexes owned: */ + pthread->priority_mutex_count++; + + /* + * Save the owning threads inherited + * priority: + */ + mutex->m_saved_prio = + pthread->inherited_priority; + + /* + * The owning thread inherits the ceiling + * priority of the mutex and executes at + * that priority: + */ + pthread->inherited_priority = mutex->m_prio; + pthread->active_priority = mutex->m_prio; + + } + break; + } + + /* Make the thread runnable and unlock the scheduling queue: */ + pthread->cycle++; + _thr_umtx_wake(&pthread->cycle, 1); + + THR_THREAD_UNLOCK(curthread, pthread); + if (mutex->m_owner == pthread) + /* We're done; a valid owner was found. */ + break; + else + /* Get the next thread from the waiting queue: */ + pthread = TAILQ_NEXT(pthread, sqe); + } + + if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT)) + /* This mutex has no priority: */ + mutex->m_prio = 0; + return (tid); +} + +#if 0 +/* + * Dequeue a waiting thread from the head of a mutex queue in descending + * priority order. + */ +static pthread_t +mutex_queue_deq(struct pthread_mutex *mutex) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) { + TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); + pthread->sflags &= ~THR_FLAGS_IN_SYNCQ; + } + + return (pthread); +} +#endif + +/* + * Remove a waiting thread from a mutex queue in descending priority order. + */ +static void +mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread) +{ + if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) { + TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); + pthread->sflags &= ~THR_FLAGS_IN_SYNCQ; + } +} + +/* + * Enqueue a waiting thread to a queue in descending priority order. + */ +static void +mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head); + + THR_ASSERT_NOT_IN_SYNCQ(pthread); + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe); + else { + tid = TAILQ_FIRST(&mutex->m_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, sqe); + TAILQ_INSERT_BEFORE(tid, pthread, sqe); + } + pthread->sflags |= THR_FLAGS_IN_SYNCQ; +} diff --git a/lib/libthread_xu/thread/thr_mutex_prioceiling.c b/lib/libthread_xu/thread/thr_mutex_prioceiling.c new file mode 100644 index 0000000000..b847e7ce70 --- /dev/null +++ b/lib/libthread_xu/thread/thr_mutex_prioceiling.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998 Daniel Eischen . + * 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 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 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_mutex_prioceiling.c,v 1.8 2003/07/07 04:28:23 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_mutex_prioceiling.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling); +__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling); +__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling); +__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling); + +int +_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + *prioceiling = (*mattr)->m_ceiling; + + return(ret); +} + +int +_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + (*mattr)->m_ceiling = prioceiling; + + return(ret); +} + +int +_pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) +{ + int ret; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + ret = (*mutex)->m_prio; + + return(ret); +} + +int +_pthread_mutex_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) +{ + int ret = 0; + int tmp; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + /* Lock the mutex: */ + else if ((ret = pthread_mutex_lock(mutex)) == 0) { + tmp = (*mutex)->m_prio; + /* Set the new ceiling: */ + (*mutex)->m_prio = prioceiling; + + /* Unlock the mutex: */ + ret = pthread_mutex_unlock(mutex); + + /* Return the old ceiling: */ + *old_ceiling = tmp; + } + return(ret); +} diff --git a/lib/libthread_xu/thread/thr_mutex_protocol.c b/lib/libthread_xu/thread/thr_mutex_protocol.c new file mode 100644 index 0000000000..d6a8314626 --- /dev/null +++ b/lib/libthread_xu/thread/thr_mutex_protocol.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1998 Daniel Eischen . + * 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 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 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_mutex_protocol.c,v 1.7 2003/04/18 05:04:16 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_mutex_protocol.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol); +__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol); + +int +_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else + *protocol = (*mattr)->m_protocol; + + return(ret); +} + +int +_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL) || + (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT)) + ret = EINVAL; + else { + (*mattr)->m_protocol = protocol; + (*mattr)->m_ceiling = THR_MAX_PRIORITY; + } + return(ret); +} + diff --git a/lib/libthread_xu/thread/thr_mutexattr.c b/lib/libthread_xu/thread/thr_mutexattr.c new file mode 100644 index 0000000000..07d5c5248b --- /dev/null +++ b/lib/libthread_xu/thread/thr_mutexattr.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu . + * 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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_mutexattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* + * Copyright (c) 1997 John Birrell . + * 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 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init); +__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np); +__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np); +__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype); +__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype); +__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy); + +int +_pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + int ret; + pthread_mutexattr_t pattr; + + if ((pattr = (pthread_mutexattr_t) + malloc(sizeof(struct pthread_mutex_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &_pthread_mutexattr_default, + sizeof(struct pthread_mutex_attr)); + *attr = pattr; + ret = 0; + } + return (ret); +} + +int +_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = kind; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr) +{ + int ret; + if (attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + ret = attr->m_type; + } + return(ret); +} + +int +_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + int ret; + if (attr == NULL || *attr == NULL || type >= MUTEX_TYPE_MAX) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = type; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type) +{ + int ret; + + if (attr == NULL || *attr == NULL || (*attr)->m_type >= + MUTEX_TYPE_MAX) { + ret = EINVAL; + } else { + *type = (*attr)->m_type; + ret = 0; + } + return ret; +} + +int +_pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} diff --git a/lib/libthread_xu/thread/thr_once.c b/lib/libthread_xu/thread/thr_once.c new file mode 100644 index 0000000000..92c9e1b01c --- /dev/null +++ b/lib/libthread_xu/thread/thr_once.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_once.c,v 1.9 2003/09/09 22:38:12 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_once.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include "thr_private.h" + +__weak_reference(_pthread_once, pthread_once); + +#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT +#define ONCE_DONE PTHREAD_DONE_INIT +#define ONCE_IN_PROGRESS 0x02 +#define ONCE_MASK 0x03 + +static pthread_mutex_t once_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER; + +/* + * POSIX: + * The pthread_once() function is not a cancellation point. However, + * if init_routine is a cancellation point and is canceled, the effect + * on once_control shall be as if pthread_once() was never called. + */ + +static void +once_cancel_handler(void *arg) +{ + pthread_once_t *once_control = arg; + + _pthread_mutex_lock(&once_lock); + once_control->state = ONCE_NEVER_DONE; + _pthread_mutex_unlock(&once_lock); + _pthread_cond_broadcast(&once_cv); +} + +int +_pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) +{ + int wakeup = 0; + + if (once_control->state == ONCE_DONE) + return (0); + _pthread_mutex_lock(&once_lock); + while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS) + _pthread_cond_wait(&once_cv, &once_lock); + /* + * If previous thread was canceled, then the state still + * could be ONCE_NEVER_DONE, we need to check it again. + */ + if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) { + once_control->state = ONCE_IN_PROGRESS; + _pthread_mutex_unlock(&once_lock); + _pthread_cleanup_push(once_cancel_handler, once_control); + init_routine(); + _pthread_cleanup_pop(0); + _pthread_mutex_lock(&once_lock); + once_control->state = ONCE_DONE; + wakeup = 1; + } + _pthread_mutex_unlock(&once_lock); + if (wakeup) + _pthread_cond_broadcast(&once_cv); + return (0); +} + diff --git a/lib/libthread_xu/thread/thr_printf.c b/lib/libthread_xu/thread/thr_printf.c new file mode 100644 index 0000000000..07e49f88ec --- /dev/null +++ b/lib/libthread_xu/thread/thr_printf.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2002 Jonathan Mini + * 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_printf.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include + +#include "thr_private.h" + +static void pchar(int fd, char c); +static void pstr(int fd, const char *s); + +/* + * Write formatted output to stdout, in a thread-safe manner. + * + * Recognises the following conversions: + * %c -> char + * %d -> signed int (base 10) + * %s -> string + * %u -> unsigned int (base 10) + * %x -> unsigned int (base 16) + * %p -> unsigned int (base 16) + */ +void +_thread_printf(int fd, const char *fmt, ...) +{ + static const char digits[16] = "0123456789abcdef"; + va_list ap; + char buf[20]; + char *s; + unsigned long r, u; + int c; + long d; + int islong; + + va_start(ap, fmt); + while ((c = *fmt++)) { + islong = 0; + if (c == '%') { +next: c = *fmt++; + if (c == '\0') + goto out; + switch (c) { + case 'c': + pchar(fd, va_arg(ap, int)); + continue; + case 's': + pstr(fd, va_arg(ap, char *)); + continue; + case 'l': + islong = 1; + goto next; + case 'p': + islong = 1; + case 'd': + case 'u': + case 'x': + r = ((c == 'u') || (c == 'd')) ? 10 : 16; + if (c == 'd') { + if (islong) + d = va_arg(ap, unsigned long); + else + d = va_arg(ap, unsigned); + if (d < 0) { + pchar(fd, '-'); + u = (unsigned long)(d * -1); + } else + u = (unsigned long)d; + } else { + if (islong) + u = va_arg(ap, unsigned long); + else + u = va_arg(ap, unsigned); + } + s = buf; + do { + *s++ = digits[u % r]; + } while (u /= r); + while (--s >= buf) + pchar(fd, *s); + continue; + } + } + pchar(fd, c); + } +out: + va_end(ap); +} + +/* + * Write a single character to stdout, in a thread-safe manner. + */ +static void +pchar(int fd, char c) +{ + + __sys_write(fd, &c, 1); +} + +/* + * Write a string to stdout, in a thread-safe manner. + */ +static void +pstr(int fd, const char *s) +{ + + __sys_write(fd, s, strlen(s)); +} + diff --git a/lib/libthread_xu/thread/thr_private.h b/lib/libthread_xu/thread/thr_private.h new file mode 100644 index 0000000000..b52fe0429b --- /dev/null +++ b/lib/libthread_xu/thread/thr_private.h @@ -0,0 +1,850 @@ +/* + * Copyright (c) 1995-1998 John Birrell . + * 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 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. + * + * Private thread definitions for the uthread kernel. + * + * $FreeBSD: src/lib/libpthread/thread/thr_private.h,v 1.120 2004/11/01 10:49:34 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_private.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#ifndef _THR_PRIVATE_H +#define _THR_PRIVATE_H + +/* + * Include files. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pthread_md.h" +#include "thr_umtx.h" + +/* + * Evaluate the storage class specifier. + */ +#ifdef GLOBAL_PTHREAD_PRIVATE +#define SCLASS +#define SCLASS_PRESET(x...) = x +#else +#define SCLASS extern +#define SCLASS_PRESET(x...) +#endif + +/* Signal to do cancellation */ +#define SIGCANCEL 32 + +/* + * Kernel fatal error handler macro. + */ +#define PANIC(string) _thread_exit(__FILE__,__LINE__,string) + +/* Output debug messages like this: */ +#define stdout_debug(args...) _thread_printf(STDOUT_FILENO, ##args) +#define stderr_debug(args...) _thread_printf(STDOUT_FILENO, ##args) + +#ifdef __DragonFly__ +#define __predict_true(exp) (exp) +#define __predict_false(exp) (exp) +#endif + +#ifdef _PTHREADS_INVARIANTS +#define THR_ASSERT(cond, msg) do { \ + if (__predict_false(!(cond))) \ + PANIC(msg); \ +} while (0) +#else +#define THR_ASSERT(cond, msg) +#endif + +#define TIMESPEC_ADD(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec + (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec + (val)->tv_nsec; \ + if ((dst)->tv_nsec > 1000000000) { \ + (dst)->tv_sec++; \ + (dst)->tv_nsec -= 1000000000; \ + } \ + } while (0) + +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + +struct pthread_mutex { + /* + * Lock for accesses to this structure. + */ + volatile umtx_t m_lock; + enum pthread_mutextype m_type; + int m_protocol; + TAILQ_HEAD(mutex_head, pthread) m_queue; + struct pthread *m_owner; + long m_flags; + int m_count; + int m_refcount; + + /* + * Used for priority inheritence and protection. + * + * m_prio - For priority inheritence, the highest active + * priority (threads locking the mutex inherit + * this priority). For priority protection, the + * ceiling priority of this mutex. + * m_saved_prio - mutex owners inherited priority before + * taking the mutex, restored when the owner + * unlocks the mutex. + */ + int m_prio; + int m_saved_prio; + + /* + * Link for list of all mutexes a thread currently owns. + */ + TAILQ_ENTRY(pthread_mutex) m_qe; +}; + +#define TAILQ_INITIALIZER { NULL, NULL } + +#define PTHREAD_MUTEX_STATIC_INITIALIZER \ + {0, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \ + NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER } +/* + * Flags for mutexes. + */ +#define MUTEX_FLAGS_PRIVATE 0x01 +#define MUTEX_FLAGS_INITED 0x02 +#define MUTEX_FLAGS_BUSY 0x04 + +struct pthread_mutex_attr { + enum pthread_mutextype m_type; + int m_protocol; + int m_ceiling; + long m_flags; +}; + +#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \ + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE } + +struct pthread_cond { + /* + * Lock for accesses to this structure. + */ + volatile umtx_t c_lock; + volatile umtx_t c_seqno; + volatile int c_waiters; + volatile int c_wakeups; + int c_pshared; + int c_clockid; +}; + +struct pthread_cond_attr { + int c_pshared; + int c_clockid; +}; + +struct pthread_barrier { + volatile umtx_t b_lock; + volatile umtx_t b_cycle; + volatile int b_count; + volatile int b_waiters; +}; + +struct pthread_barrierattr { + int pshared; +}; + +struct pthread_spinlock { + volatile umtx_t s_lock; +}; + +/* + * Flags for condition variables. + */ +#define COND_FLAGS_PRIVATE 0x01 +#define COND_FLAGS_INITED 0x02 +#define COND_FLAGS_BUSY 0x04 + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { + struct pthread_cleanup *next; + void (*routine)(); + void *routine_arg; + int onstack; +}; + +#define THR_CLEANUP_PUSH(td, func, arg) { \ + struct pthread_cleanup __cup; \ + \ + __cup.routine = func; \ + __cup.routine_arg = arg; \ + __cup.onstack = 1; \ + __cup.next = (td)->cleanup; \ + (td)->cleanup = &__cup; + +#define THR_CLEANUP_POP(td, exec) \ + (td)->cleanup = __cup.next; \ + if ((exec) != 0) \ + __cup.routine(__cup.routine_arg); \ +} + +struct pthread_atfork { + TAILQ_ENTRY(pthread_atfork) qe; + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); +}; + +struct pthread_attr { + int sched_policy; + int sched_inherit; + int sched_interval; + int prio; + int suspend; +#define THR_STACK_USER 0x100 /* 0xFF reserved for */ + int flags; + void *arg_attr; + void (*cleanup_attr)(); + void *stackaddr_attr; + size_t stacksize_attr; + size_t guardsize_attr; +}; + +/* + * Thread creation state attributes. + */ +#define THR_CREATE_RUNNING 0 +#define THR_CREATE_SUSPENDED 1 + +/* + * Miscellaneous definitions. + */ +#define THR_STACK_DEFAULT 0x100000 + +/* + * Maximum size of initial thread's stack. This perhaps deserves to be larger + * than the stacks of other threads, since many applications are likely to run + * almost entirely on this stack. + */ +#define THR_STACK_INITIAL 0x200000 + +/* + * Define the different priority ranges. All applications have thread + * priorities constrained within 0-31. The threads library raises the + * priority when delivering signals in order to ensure that signal + * delivery happens (from the POSIX spec) "as soon as possible". + * In the future, the threads library will also be able to map specific + * threads into real-time (cooperating) processes or kernel threads. + * The RT and SIGNAL priorities will be used internally and added to + * thread base priorities so that the scheduling queue can handle both + * normal and RT priority threads with and without signal handling. + * + * The approach taken is that, within each class, signal delivery + * always has priority over thread execution. + */ +#define THR_DEFAULT_PRIORITY 15 +#define THR_MIN_PRIORITY 0 +#define THR_MAX_PRIORITY 31 /* 0x1F */ +#define THR_SIGNAL_PRIORITY 32 /* 0x20 */ +#define THR_RT_PRIORITY 64 /* 0x40 */ +#define THR_FIRST_PRIORITY THR_MIN_PRIORITY +#define THR_LAST_PRIORITY \ + (THR_MAX_PRIORITY + THR_SIGNAL_PRIORITY + THR_RT_PRIORITY) +#define THR_BASE_PRIORITY(prio) ((prio) & THR_MAX_PRIORITY) + +/* + * Time slice period in microseconds. + */ +#define TIMESLICE_USEC 20000 + +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_rwlock { + pthread_mutex_t lock; /* monitor lock */ + pthread_cond_t read_signal; + pthread_cond_t write_signal; + int state; /* 0 = idle >0 = # of readers -1 = writer */ + int blocked_writers; +}; + +/* + * Thread states. + */ +enum pthread_state { + PS_RUNNING, + PS_DEAD +}; + +union pthread_wait_data { + pthread_mutex_t mutex; +}; + +struct pthread_specific_elem { + const void *data; + int seqno; +}; + +struct pthread_key { + volatile int allocated; + volatile int count; + int seqno; + void (*destructor)(void *); +}; + +/* + * Thread structure. + */ +struct pthread { + /* + * Magic value to help recognize a valid thread structure + * from an invalid one: + */ +#define THR_MAGIC ((u_int32_t) 0xd09ba115) + u_int32_t magic; + char *name; + u_int64_t uniqueid; /* for gdb */ + + /* + * Lock for accesses to this thread structure. + */ + umtx_t lock; + + /* Thread is terminated in kernel, written by kernel. */ + long terminated; + + /* Kernel thread id. */ + long tid; + + /* Internal condition variable cycle number. */ + umtx_t cycle; + + /* How many low level locks the thread held. */ + int locklevel; + + /* Signal blocked counter. */ + int sigblock; + + /* Queue entry for list of all threads. */ + TAILQ_ENTRY(pthread) tle; /* link for all threads in process */ + + /* Queue entry for GC lists. */ + TAILQ_ENTRY(pthread) gcle; + + /* Hash queue entry. */ + LIST_ENTRY(pthread) hle; + + /* Threads reference count. */ + int refcount; + + /* + * Thread start routine, argument, stack pointer and thread + * attributes. + */ + void *(*start_routine)(void *); + void *arg; + struct pthread_attr attr; + + /* + * Cancelability flags + */ +#define THR_CANCEL_DISABLE 0x0001 +#define THR_CANCEL_EXITING 0x0002 +#define THR_CANCEL_AT_POINT 0x0004 +#define THR_CANCEL_NEEDED 0x0008 +#define SHOULD_CANCEL(val) \ + (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \ + THR_CANCEL_NEEDED)) == THR_CANCEL_NEEDED) + +#define SHOULD_ASYNC_CANCEL(val) \ + (((val) & (THR_CANCEL_DISABLE | THR_CANCEL_EXITING | \ + THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) == \ + (THR_CANCEL_NEEDED | THR_CANCEL_AT_POINT)) + int cancelflags; + + /* Thread temporary signal mask. */ + sigset_t sigmask; + + /* Thread state: */ + umtx_t state; + + /* + * Error variable used instead of errno. The function __error() + * returns a pointer to this. + */ + int error; + + /* + * The joiner is the thread that is joining to this thread. The + * join status keeps track of a join operation to another thread. + */ + struct pthread *joiner; + + /* + * The current thread can belong to a priority mutex queue. + * This is the synchronization queue link. + */ + TAILQ_ENTRY(pthread) sqe; + + /* Wait data. */ + union pthread_wait_data data; + + int sflags; +#define THR_FLAGS_IN_SYNCQ 0x0001 + + /* Miscellaneous flags; only set with scheduling lock held. */ + int flags; +#define THR_FLAGS_PRIVATE 0x0001 +#define THR_FLAGS_NEED_SUSPEND 0x0002 /* thread should be suspended */ +#define THR_FLAGS_SUSPENDED 0x0004 /* thread is suspended */ + + /* Thread list flags; only set with thread list lock held. */ + int tlflags; +#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */ +#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */ +#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */ +#define TLFLAGS_DETACHED 0x0008 /* thread is detached */ + + /* + * Base priority is the user setable and retrievable priority + * of the thread. It is only affected by explicit calls to + * set thread priority and upon thread creation via a thread + * attribute or default priority. + */ + char base_priority; + + /* + * Inherited priority is the priority a thread inherits by + * taking a priority inheritence or protection mutex. It + * is not affected by base priority changes. Inherited + * priority defaults to and remains 0 until a mutex is taken + * that is being waited on by any other thread whose priority + * is non-zero. + */ + char inherited_priority; + + /* + * Active priority is always the maximum of the threads base + * priority and inherited priority. When there is a change + * in either the base or inherited priority, the active + * priority must be recalculated. + */ + char active_priority; + + /* Number of priority ceiling or protection mutexes owned. */ + int priority_mutex_count; + + /* Queue of currently owned simple type mutexes. */ + TAILQ_HEAD(, pthread_mutex) mutexq; + + /* Queue of currently owned priority type mutexs. */ + TAILQ_HEAD(, pthread_mutex) pri_mutexq; + + void *ret; + struct pthread_specific_elem *specific; + int specific_data_count; + + /* Number rwlocks rdlocks held. */ + int rdlock_count; + + /* + * Current locks bitmap for rtld. */ + int rtld_bits; + + /* Thread control block */ + struct tcb *tcb; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; +}; + +#define THR_UMTX_TRYLOCK(thrd, lck) \ + _thr_umtx_trylock((lck), (thrd)->tid) + +#define THR_UMTX_LOCK(thrd, lck) \ + _thr_umtx_lock((lck), (thrd)->tid) + +#define THR_UMTX_TIMEDLOCK(thrd, lck, timo) \ + _thr_umtx_timedlock((lck), (thrd)->tid, (timo)) + +#define THR_UMTX_UNLOCK(thrd, lck) \ + _thr_umtx_unlock((lck), (thrd)->tid) + +#define THR_LOCK_ACQUIRE(thrd, lck) \ +do { \ + (thrd)->locklevel++; \ + _thr_umtx_lock(lck, (thrd)->tid); \ +} while (0) + +#define THR_LOCK_RELEASE(thrd, lck) \ +do { \ + if ((thrd)->locklevel > 0) { \ + _thr_umtx_unlock((lck), (thrd)->tid); \ + (thrd)->locklevel--; \ + } else { \ + _thr_assert_lock_level(); \ + } \ +} while (0) + +#define THR_LOCK(curthrd) THR_LOCK_ACQUIRE(curthrd, &(curthrd)->lock) +#define THR_UNLOCK(curthrd) THR_LOCK_RELEASE(curthrd, &(curthrd)->lock) +#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock) +#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock) + +#define THREAD_LIST_LOCK(curthrd) \ +do { \ + THR_LOCK_ACQUIRE((curthrd), &_thr_list_lock); \ +} while (0) + +#define THREAD_LIST_UNLOCK(curthrd) \ +do { \ + THR_LOCK_RELEASE((curthrd), &_thr_list_lock); \ +} while (0) + +/* + * Macros to insert/remove threads to the all thread list and + * the gc list. + */ +#define THR_LIST_ADD(thrd) do { \ + if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \ + TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \ + _thr_hash_add(thrd); \ + (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \ + } \ +} while (0) +#define THR_LIST_REMOVE(thrd) do { \ + if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \ + TAILQ_REMOVE(&_thread_list, thrd, tle); \ + _thr_hash_remove(thrd); \ + (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \ + } \ +} while (0) +#define THR_GCLIST_ADD(thrd) do { \ + if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \ + TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\ + (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \ + _gc_count++; \ + } \ +} while (0) +#define THR_GCLIST_REMOVE(thrd) do { \ + if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \ + TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \ + (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \ + _gc_count--; \ + } \ +} while (0) + +#define GC_NEEDED() (_gc_count >= 5) + +#define THR_IN_SYNCQ(thrd) (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0) + +extern int __isthreaded; + +/* + * Global variables for the pthread kernel. + */ + +SCLASS void *_usrstack SCLASS_PRESET(NULL); +SCLASS struct pthread *_thr_initial SCLASS_PRESET(NULL); +/* For debugger */ +SCLASS int _libthread_xu_debug SCLASS_PRESET(0); +SCLASS int _thread_scope_system SCLASS_PRESET(0); + +/* List of all threads: */ +SCLASS TAILQ_HEAD(, pthread) _thread_list + SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_list)); + +/* List of threads needing GC: */ +SCLASS TAILQ_HEAD(, pthread) _thread_gc_list + SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_gc_list)); + +SCLASS int _thread_active_threads SCLASS_PRESET(1); + +SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _thr_atfork_list; +SCLASS umtx_t _thr_atfork_lock; + +/* Default thread attributes: */ +SCLASS struct pthread_attr _pthread_attr_default + SCLASS_PRESET({ + .sched_policy = SCHED_RR, + .sched_inherit = 0, + .sched_interval = TIMESLICE_USEC, + .prio = THR_DEFAULT_PRIORITY, + .suspend = THR_CREATE_RUNNING, + .flags = 0, + .arg_attr = NULL, + .cleanup_attr = NULL, + .stackaddr_attr = NULL, + .stacksize_attr = THR_STACK_DEFAULT, + .guardsize_attr = 0 + }); + +/* Default mutex attributes: */ +SCLASS struct pthread_mutex_attr _pthread_mutexattr_default + SCLASS_PRESET({ + .m_type = PTHREAD_MUTEX_DEFAULT, + .m_protocol = PTHREAD_PRIO_NONE, + .m_ceiling = 0, + .m_flags = 0 + }); + +/* Default condition variable attributes: */ +SCLASS struct pthread_cond_attr _pthread_condattr_default + SCLASS_PRESET({ + .c_pshared = PTHREAD_PROCESS_PRIVATE, + .c_clockid = CLOCK_REALTIME + }); + +SCLASS pid_t _thr_pid SCLASS_PRESET(0); +SCLASS int _thr_guard_default; +SCLASS int _thr_page_size; +/* Garbage thread count. */ +SCLASS int _gc_count SCLASS_PRESET(0); + +SCLASS umtx_t _mutex_static_lock; +SCLASS umtx_t _cond_static_lock; +SCLASS umtx_t _rwlock_static_lock; +SCLASS umtx_t _keytable_lock; +SCLASS umtx_t _thr_list_lock; + +/* Undefine the storage class and preset specifiers: */ +#undef SCLASS +#undef SCLASS_PRESET + +/* + * Function prototype definitions. + */ +__BEGIN_DECLS +int _thr_setthreaded(int); +int _mutex_cv_lock(pthread_mutex_t *); +int _mutex_cv_unlock(pthread_mutex_t *); +void _mutex_notify_priochange(struct pthread *, struct pthread *, int); +int _mutex_reinit(pthread_mutex_t *); +void _mutex_fork(struct pthread *curthread); +void _mutex_unlock_private(struct pthread *); +void _libpthread_init(struct pthread *); +void *_pthread_getspecific(pthread_key_t); +int _pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); +int _pthread_cond_destroy(pthread_cond_t *); +int _pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int _pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, + const struct timespec *); +int _pthread_cond_signal(pthread_cond_t *); +int _pthread_cond_broadcast(pthread_cond_t *); +int _pthread_key_create(pthread_key_t *, void (*) (void *)); +int _pthread_key_delete(pthread_key_t); +int _pthread_mutex_destroy(pthread_mutex_t *); +int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); +int _pthread_mutex_lock(pthread_mutex_t *); +int _pthread_mutex_trylock(pthread_mutex_t *); +int _pthread_mutex_unlock(pthread_mutex_t *); +int _pthread_mutexattr_init(pthread_mutexattr_t *); +int _pthread_mutexattr_destroy(pthread_mutexattr_t *); +int _pthread_mutexattr_settype(pthread_mutexattr_t *, int); +int _pthread_once(pthread_once_t *, void (*) (void)); +int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *); +int _pthread_rwlock_destroy (pthread_rwlock_t *); +struct pthread *_pthread_self(void); +int _pthread_setspecific(pthread_key_t, const void *); +void _pthread_testcancel(void); +void _pthread_yield(void); +void _pthread_cleanup_push(void (*routine) (void *), void *routine_arg); +void _pthread_cleanup_pop(int execute); +struct pthread *_thr_alloc(struct pthread *); +void _thread_exit(char *, int, char *) __dead2; +void _thr_exit_cleanup(void); +int _thr_ref_add(struct pthread *, struct pthread *, int); +void _thr_ref_delete(struct pthread *, struct pthread *); +int _thr_find_thread(struct pthread *, struct pthread *, int); +void _thr_rtld_init(void); +void _thr_rtld_fini(void); +int _thr_stack_alloc(struct pthread_attr *); +void _thr_stack_free(struct pthread_attr *); +void _thr_free(struct pthread *, struct pthread *); +void _thr_gc(struct pthread *); +void _thread_cleanupspecific(void); +void _thread_dump_info(void); +void _thread_printf(int, const char *, ...); +void _thr_spinlock_init(void); +int _thr_cancel_enter(struct pthread *); +void _thr_cancel_leave(struct pthread *, int); +void _thr_signal_block(struct pthread *); +void _thr_signal_unblock(struct pthread *); +void _thr_signal_init(void); +void _thr_signal_deinit(void); +int _thr_send_sig(struct pthread *, int sig); +void _thr_list_init(); +void _thr_hash_add(struct pthread *); +void _thr_hash_remove(struct pthread *); +struct pthread *_thr_hash_find(struct pthread *); +void _thr_link(struct pthread *curthread, struct pthread *thread); +void _thr_unlink(struct pthread *curthread, struct pthread *thread); +void _thr_suspend_check(struct pthread *curthread); +void _thr_assert_lock_level() __dead2; +int _thr_get_tid(void); + +/* + * Aliases for _pthread functions. Should be called instead of + * originals if PLT replocation is unwanted at runtme. + */ +int _thr_cond_broadcast(pthread_cond_t *); +int _thr_cond_signal(pthread_cond_t *); +int _thr_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int _thr_mutex_lock(pthread_mutex_t *); +int _thr_mutex_unlock(pthread_mutex_t *); +int _thr_rwlock_rdlock(pthread_rwlock_t *); +int _thr_rwlock_wrlock(pthread_rwlock_t *); +int _thr_rwlock_unlock(pthread_rwlock_t *); + +/* #include */ +#ifdef _SYS_AIO_H_ +int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); +#endif + +/* #include */ +#ifdef _SYS_FCNTL_H_ +int __sys_fcntl(int, int, ...); +int __sys_open(const char *, int, ...); +#endif + +/* #include */ +#ifdef _SYS_IOCTL_H_ +int __sys_ioctl(int, unsigned long, ...); +#endif + +/* #inclde */ +#ifdef _SCHED_H_ +int __sys_sched_yield(void); +#endif + +/* #include */ +#ifdef _SIGNAL_H_ +int __sys_kill(pid_t, int); +int __sys_sigaction(int, const struct sigaction *, struct sigaction *); +int __sys_sigpending(sigset_t *); +int __sys_sigprocmask(int, const sigset_t *, sigset_t *); +int __sys_sigsuspend(const sigset_t *); +int __sys_sigreturn(ucontext_t *); +int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); +#endif + +/* #include */ +#ifdef _SYS_SOCKET_H_ +int __sys_accept(int, struct sockaddr *, socklen_t *); +int __sys_connect(int, const struct sockaddr *, socklen_t); +ssize_t __sys_recv(int, void *, size_t, int); +ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); +ssize_t __sys_recvmsg(int, struct msghdr *, int); +int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, + off_t *, int); +ssize_t __sys_sendmsg(int, const struct msghdr *, int); +ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); +#endif + +/* #include */ +#ifdef _SYS_UIO_H_ +ssize_t __sys_readv(int, const struct iovec *, int); +ssize_t __sys_writev(int, const struct iovec *, int); +#endif + +/* #include */ +#ifdef _TIME_H_ +int __sys_nanosleep(const struct timespec *, struct timespec *); +#endif + +/* #include */ +#ifdef _UNISTD_H_ +int __sys_close(int); +int __sys_execve(const char *, char * const *, char * const *); +int __sys_fork(void); +int __sys_fsync(int); +pid_t __sys_getpid(void); +int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +ssize_t __sys_read(int, void *, size_t); +ssize_t __sys_write(int, const void *, size_t); +void __sys_exit(int); +int __sys_sigwait(const sigset_t *, int *); +int __sys_sigtimedwait(const sigset_t *, siginfo_t *, + const struct timespec *); +int __sys_sigwaitinfo(const sigset_t *set, siginfo_t *info); +#endif + +/* #include */ +#ifdef _SYS_POLL_H_ +int __sys_poll(struct pollfd *, unsigned, int); +#endif + +/* #include */ +#ifdef _SYS_MMAN_H_ +int __sys_msync(void *, size_t, int); +#endif + +static inline int +_thr_isthreaded(void) +{ + return (__isthreaded != 0); +} + +static inline int +_thr_is_inited(void) +{ + return (_thr_initial != 0); +} + +static inline void +_thr_check_init(void) +{ + if (_thr_initial == 0) + _libpthread_init(0); +} + +__END_DECLS + +#endif /* !_THR_PRIVATE_H */ diff --git a/lib/libthread_xu/thread/thr_pspinlock.c b/lib/libthread_xu/thread/thr_pspinlock.c new file mode 100644 index 0000000000..0d53fc1e5c --- /dev/null +++ b/lib/libthread_xu/thread/thr_pspinlock.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2003 David Xu + * 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_pspinlock.c,v 1.2 2003/11/04 19:56:12 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_pspinlock.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include "thr_private.h" + +#define SPIN_COUNT 100000 + +__weak_reference(_pthread_spin_init, pthread_spin_init); +__weak_reference(_pthread_spin_destroy, pthread_spin_destroy); +__weak_reference(_pthread_spin_trylock, pthread_spin_trylock); +__weak_reference(_pthread_spin_lock, pthread_spin_lock); +__weak_reference(_pthread_spin_unlock, pthread_spin_unlock); + +int +_pthread_spin_init(pthread_spinlock_t *lock, int pshared) +{ + struct pthread_spinlock *lck; + int ret; + + if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE) + ret = EINVAL; + else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL) + ret = ENOMEM; + else { + _thr_umtx_init(&lck->s_lock); + *lock = lck; + ret = 0; + } + + return (ret); +} + +int +_pthread_spin_destroy(pthread_spinlock_t *lock) +{ + int ret; + + if (lock == NULL || *lock == NULL) + ret = EINVAL; + else { + free(*lock); + *lock = NULL; + ret = 0; + } + + return (ret); +} + +int +_pthread_spin_trylock(pthread_spinlock_t *lock) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_spinlock *lck; + int ret; + + if (lock == NULL || (lck = *lock) == NULL) + ret = EINVAL; + else + ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock); + return (ret); +} + +int +_pthread_spin_lock(pthread_spinlock_t *lock) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_spinlock *lck; + int ret, count; + + if (lock == NULL || (lck = *lock) == NULL) + ret = EINVAL; + else { + count = SPIN_COUNT; + while ((ret = THR_UMTX_TRYLOCK(curthread, &lck->s_lock)) != 0) { + while (lck->s_lock) { +#ifdef __i386__ + /* tell cpu we are spinning */ + __asm __volatile("pause"); +#endif + if (--count <= 0) { + count = SPIN_COUNT; + _pthread_yield(); + } + } + } + ret = 0; + } + + return (ret); +} + +int +_pthread_spin_unlock(pthread_spinlock_t *lock) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_spinlock *lck; + int ret; + + if (lock == NULL || (lck = *lock) == NULL) + ret = EINVAL; + else { + ret = THR_UMTX_UNLOCK(curthread, &lck->s_lock); + } + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_resume_np.c b/lib/libthread_xu/thread/thr_resume_np.c new file mode 100644 index 0000000000..c865ea2bf3 --- /dev/null +++ b/lib/libthread_xu/thread/thr_resume_np.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_resume_np.c,v 1.18 2003/07/23 02:11:07 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_resume_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_resume_np, pthread_resume_np); +__weak_reference(_pthread_resume_all_np, pthread_resume_all_np); + +static void resume_common(struct pthread *thread); + +/* Resume a thread: */ +int +_pthread_resume_np(pthread_t thread) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* Add a reference to the thread: */ + if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) == 0) { + /* Lock the threads scheduling queue: */ + THR_THREAD_LOCK(curthread, thread); + resume_common(thread); + THR_THREAD_UNLOCK(curthread, thread); + _thr_ref_delete(curthread, thread); + } + return (ret); +} + +void +_pthread_resume_all_np(void) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *thread; + + /* Take the thread list lock: */ + THREAD_LIST_LOCK(curthread); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != curthread) { + THR_THREAD_LOCK(curthread, thread); + resume_common(thread); + THR_THREAD_UNLOCK(curthread, thread); + } + } + + /* Release the thread list lock: */ + THREAD_LIST_UNLOCK(curthread); +} + +static void +resume_common(struct pthread *thread) +{ + /* Clear the suspend flag: */ + thread->flags &= ~THR_FLAGS_NEED_SUSPEND; + thread->cycle++; + _thr_umtx_wake(&thread->cycle, 1); + _thr_send_sig(thread, SIGCANCEL); +} diff --git a/lib/libthread_xu/thread/thr_rtld.c b/lib/libthread_xu/thread/thr_rtld.c new file mode 100644 index 0000000000..179d75af03 --- /dev/null +++ b/lib/libthread_xu/thread/thr_rtld.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2001 Alexander Kabaev + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_rtld.c,v 1.5 2003/11/05 18:19:24 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_rtld.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include + +#include "rtld_lock.h" +#include "thr_private.h" + +static int _thr_rtld_clr_flag(int); +static void *_thr_rtld_lock_create(void); +static void _thr_rtld_lock_destroy(void *); +static void _thr_rtld_lock_release(void *); +static void _thr_rtld_rlock_acquire(void *); +static int _thr_rtld_set_flag(int); +static void _thr_rtld_wlock_acquire(void *); + +static void * +_thr_rtld_lock_create(void) +{ + pthread_rwlock_t prwlock; + if (_pthread_rwlock_init(&prwlock, NULL)) + return (NULL); + return (prwlock); +} + +static void +_thr_rtld_lock_destroy(void *lock) +{ + pthread_rwlock_t prwlock; + + prwlock = (pthread_rwlock_t)lock; + if (prwlock != NULL) + _pthread_rwlock_destroy(&prwlock); +} + +static void +_thr_rtld_rlock_acquire(void *lock) +{ + pthread_rwlock_t prwlock; + + prwlock = (pthread_rwlock_t)lock; + _thr_rwlock_rdlock(&prwlock); +} + +static void +_thr_rtld_wlock_acquire(void *lock) +{ + pthread_rwlock_t prwlock; + + prwlock = (pthread_rwlock_t)lock; + _thr_rwlock_wrlock(&prwlock); +} + +static void +_thr_rtld_lock_release(void *lock) +{ + pthread_rwlock_t prwlock; + + prwlock = (pthread_rwlock_t)lock; + _thr_rwlock_unlock(&prwlock); +} + + +static int +_thr_rtld_set_flag(int mask) +{ + struct pthread *curthread; + int bits; + + curthread = _get_curthread(); + if (curthread != NULL) { + bits = curthread->rtld_bits; + curthread->rtld_bits |= mask; + } else { + bits = 0; + PANIC("No current thread in rtld call"); + } + + return (bits); +} + +static int +_thr_rtld_clr_flag(int mask) +{ + struct pthread *curthread; + int bits; + + curthread = _get_curthread(); + if (curthread != NULL) { + bits = curthread->rtld_bits; + curthread->rtld_bits &= ~mask; + } else { + bits = 0; + PANIC("No current thread in rtld call"); + } + return (bits); +} + +void +_thr_rtld_init(void) +{ + struct RtldLockInfo li; + + li.lock_create = _thr_rtld_lock_create; + li.lock_destroy = _thr_rtld_lock_destroy; + li.rlock_acquire = _thr_rtld_rlock_acquire; + li.wlock_acquire = _thr_rtld_wlock_acquire; + li.lock_release = _thr_rtld_lock_release; + li.thread_set_flag = _thr_rtld_set_flag; + li.thread_clr_flag = _thr_rtld_clr_flag; + li.at_fork = NULL; + _rtld_thread_init(&li); +} + +void +_thr_rtld_fini(void) +{ + _rtld_thread_init(NULL); +} diff --git a/lib/libthread_xu/thread/thr_rwlock.c b/lib/libthread_xu/thread/thr_rwlock.c new file mode 100644 index 0000000000..4d774597c0 --- /dev/null +++ b/lib/libthread_xu/thread/thr_rwlock.c @@ -0,0 +1,424 @@ +/*- + * 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_rwlock.c,v 1.14 2004/01/08 15:37:09 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_rwlock.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include + +#include +#include "thr_private.h" + +/* maximum number of times a read lock may be obtained */ +#define MAX_READ_LOCKS (INT_MAX - 1) + +__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy); +__weak_reference(_pthread_rwlock_init, pthread_rwlock_init); +__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock); +__weak_reference(_pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock); +__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock); +__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock); +__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock); +__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock); +__weak_reference(_pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock); + +/* + * Prototypes + */ + +static int +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_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); +} + +static int +init_static(struct pthread *thread, pthread_rwlock_t *rwlock) +{ + int ret; + + THR_LOCK_ACQUIRE(thread, &_rwlock_static_lock); + + if (*rwlock == NULL) + ret = rwlock_init(rwlock, NULL); + else + ret = 0; + + THR_LOCK_RELEASE(thread, &_rwlock_static_lock); + + return (ret); +} + +int +_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + *rwlock = NULL; + return (rwlock_init(rwlock, attr)); +} + +static int +rwlock_rdlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime) +{ + struct pthread *curthread = _get_curthread(); + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return (EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(curthread, rwlock)) != 0) + return (ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) { + _thr_mutex_unlock(&prwlock->lock); + return (EAGAIN); + } + + curthread = _get_curthread(); + if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) { + /* + * To avoid having to track all the rdlocks held by + * a thread or all of the threads that hold a rdlock, + * we keep a simple count of all the rdlocks held by + * a thread. If a thread holds any rdlocks it is + * possible that it is attempting to take a recursive + * rdlock. If there are blocked writers and precedence + * is given to them, then that would result in the thread + * deadlocking. So allowing a thread to take the rdlock + * when it already has one or more rdlocks avoids the + * deadlock. I hope the reader can follow that logic ;-) + */ + ; /* nothing needed */ + } else { + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + if (abstime) + ret = _pthread_cond_timedwait + (&prwlock->read_signal, + &prwlock->lock, abstime); + else + ret = _thr_cond_wait(&prwlock->read_signal, + &prwlock->lock); + if (ret != 0) { + /* can't do a whole lot if this fails */ + _thr_mutex_unlock(&prwlock->lock); + return (ret); + } + } + } + + curthread->rdlock_count++; + 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. + */ + _thr_mutex_unlock(&prwlock->lock); + + return (ret); +} + +int +_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + return (rwlock_rdlock_common(rwlock, NULL)); +} + +__strong_reference(_pthread_rwlock_rdlock, _thr_rwlock_rdlock); + +int +_pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + return (rwlock_rdlock_common(rwlock, abstime)); +} + +int +_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + struct pthread *curthread = _get_curthread(); + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return (EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(curthread, rwlock)) != 0) + return (ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = _pthread_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + curthread = _get_curthread(); + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else if ((curthread->rdlock_count > 0) && (prwlock->state > 0)) { + /* see comment for pthread_rwlock_rdlock() */ + curthread->rdlock_count++; + prwlock->state++; + } + /* give writers priority over readers */ + else if (prwlock->blocked_writers || prwlock->state < 0) + ret = EBUSY; + else { + curthread->rdlock_count++; + 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) +{ + struct pthread *curthread = _get_curthread(); + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return (EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(curthread, 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 = EBUSY; + 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) +{ + struct pthread *curthread; + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return (EINVAL); + + prwlock = *rwlock; + + if (prwlock == NULL) + return (EINVAL); + + /* grab the monitor lock */ + if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + curthread = _get_curthread(); + if (prwlock->state > 0) { + curthread->rdlock_count--; + prwlock->state--; + if (prwlock->state == 0 && prwlock->blocked_writers) + ret = _thr_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = _thr_cond_signal(&prwlock->write_signal); + else + ret = _thr_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + _thr_mutex_unlock(&prwlock->lock); + + return (ret); +} + +__strong_reference(_pthread_rwlock_unlock, _thr_rwlock_unlock); + +static int +rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime) +{ + struct pthread *curthread = _get_curthread(); + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return (EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(curthread, rwlock)) != 0) + return (ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = _thr_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + while (prwlock->state != 0) { + prwlock->blocked_writers++; + + if (abstime != NULL) + ret = _pthread_cond_timedwait(&prwlock->write_signal, + &prwlock->lock, abstime); + else + ret = _thr_cond_wait(&prwlock->write_signal, + &prwlock->lock); + if (ret != 0) { + prwlock->blocked_writers--; + _thr_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 */ + _thr_mutex_unlock(&prwlock->lock); + + return (ret); +} + +int +_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + return (rwlock_wrlock_common (rwlock, NULL)); +} +__strong_reference(_pthread_rwlock_wrlock, _thr_rwlock_wrlock); + +int +_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + return (rwlock_wrlock_common (rwlock, abstime)); +} diff --git a/lib/libthread_xu/thread/thr_rwlockattr.c b/lib/libthread_xu/thread/thr_rwlockattr.c new file mode 100644 index 0000000000..5742a888b5 --- /dev/null +++ b/lib/libthread_xu/thread/thr_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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_rwlockattr.c,v 1.8 2002/09/16 08:45:35 mini Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_rwlockattr.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include + +#include +#include "thr_private.h" + +__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy); +__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared); +__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init); +__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared); + +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) +{ + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return(EINVAL); + + (*rwlockattr)->pshared = pshared; + + return(0); +} + diff --git a/lib/libthread_xu/thread/thr_self.c b/lib/libthread_xu/thread/thr_self.c new file mode 100644 index 0000000000..16ce6b9202 --- /dev/null +++ b/lib/libthread_xu/thread/thr_self.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_self.c,v 1.7 2003/04/18 05:04:16 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_self.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "thr_private.h" + +__weak_reference(_pthread_self, pthread_self); + +pthread_t +_pthread_self(void) +{ + _thr_check_init(); + + /* Return the running thread pointer: */ + return (_get_curthread()); +} diff --git a/lib/libthread_xu/thread/thr_sem.c b/lib/libthread_xu/thread/thr_sem.c new file mode 100644 index 0000000000..8ca3d0bf45 --- /dev/null +++ b/lib/libthread_xu/thread/thr_sem.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2005 David Xu . + * Copyright (C) 2000 Jason Evans . + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_sem.c,v 1.16 2004/12/18 18:07:37 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_sem.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "thr_private.h" + +__weak_reference(_sem_close, sem_close); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_getvalue, sem_getvalue); +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_open, sem_open); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_wait, sem_wait); +__weak_reference(_sem_timedwait, sem_timedwait); +__weak_reference(_sem_post, sem_post); +__weak_reference(_sem_unlink, sem_unlink); + +/* + * Semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + volatile umtx_t count; + int semid; /* kernel based semaphore id. */ +}; + +static inline int +sem_check_validity(sem_t *sem) +{ + + if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) + return (0); + else { + errno = EINVAL; + return (-1); + } +} + +static sem_t +sem_alloc(unsigned int value, int semid) +{ + sem_t sem; + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (NULL); + } + + sem = (sem_t)malloc(sizeof(struct sem)); + if (sem == NULL) { + errno = ENOSPC; + return (NULL); + } + sem->magic = SEM_MAGIC; + sem->count = (u_int32_t)value; + sem->semid = semid; + return (sem); +} + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + if (pshared != 0) { + /* + * We really can support pshared, but sem_t was + * defined as a pointer, if it is a structure, + * it will work between processes. + */ + errno = EPERM; + return (-1); + } + + (*sem) = sem_alloc(value, -1); + if ((*sem) == NULL) + return (-1); + return (0); +} + +int +_sem_destroy(sem_t *sem) +{ + if (sem_check_validity(sem) != 0) + return (-1); + + free(*sem); + return (0); +} + +sem_t * +_sem_open(const char *name, int oflag, ...) +{ + errno = ENOSYS; + return SEM_FAILED; +} + +int +_sem_close(sem_t *sem) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + if (sem_check_validity(sem) != 0) + return (-1); + + *sval = (*sem)->count; + return (0); +} + +int +_sem_trywait(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_int(&(*sem)->count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); +} + +int +_sem_wait(sem_t *sem) +{ + struct pthread *curthread; + int val, oldcancel, retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + curthread = _get_curthread(); + _pthread_testcancel(); + do { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + oldcancel = _thr_cancel_enter(curthread); + retval = _thr_umtx_wait(&(*sem)->count, 0, NULL); + _thr_cancel_leave(curthread, oldcancel); + } while (retval == 0); + errno = retval; + return (-1); +} + +int +_sem_timedwait(sem_t * __restrict sem, struct timespec * __restrict abstime) +{ + struct timespec ts, ts2; + struct pthread *curthread; + int val, oldcancel, retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + curthread = _get_curthread(); + + /* + * The timeout argument is only supposed to + * be checked if the thread would have blocked. + */ + _pthread_testcancel(); + do { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + if (abstime == NULL) { + errno = EINVAL; + return (-1); + } + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + oldcancel = _thr_cancel_enter(curthread); + retval = _thr_umtx_wait(&(*sem)->count, 0, &ts2); + _thr_cancel_leave(curthread, oldcancel); + } while (retval == 0); + errno = retval; + return (-1); +} + +int +_sem_post(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + /* + * sem_post() is required to be safe to call from within + * signal handlers, these code should work as that. + */ + do { + val = (*sem)->count; + } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1)); + _thr_umtx_wake(&(*sem)->count, val + 1); + return (0); +} diff --git a/lib/libthread_xu/thread/thr_seterrno.c b/lib/libthread_xu/thread/thr_seterrno.c new file mode 100644 index 0000000000..613b0722fb --- /dev/null +++ b/lib/libthread_xu/thread/thr_seterrno.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_seterrno.c,v 1.7 2003/04/18 05:04:16 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/Attic/thr_seterrno.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "thr_private.h" + +/* + * This function needs to reference the global error variable which is + * normally hidden from the user. + */ +#undef errno +extern int errno; + +void +_thread_seterrno(pthread_t thread, int error) +{ + /* Check for the initial thread: */ + if (thread == NULL || thread == _thr_initial) + /* The initial thread always uses the global error variable: */ + errno = error; + else + /* + * Threads other than the initial thread always use the error + * field in the thread structureL + */ + thread->error = error; +} diff --git a/lib/libthread_xu/thread/thr_setprio.c b/lib/libthread_xu/thread/thr_setprio.c new file mode 100644 index 0000000000..c83962d2cb --- /dev/null +++ b/lib/libthread_xu/thread/thr_setprio.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_setprio.c,v 1.10 2002/09/16 08:45:36 mini Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_setprio.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "thr_private.h" + +__weak_reference(_pthread_setprio, pthread_setprio); + +int +_pthread_setprio(pthread_t pthread, int prio) +{ + int ret, policy; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) { + param.sched_priority = prio; + ret = pthread_setschedparam(pthread, policy, ¶m); + } + + /* Return the error status: */ + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_setschedparam.c b/lib/libthread_xu/thread/thr_setschedparam.c new file mode 100644 index 0000000000..9953cad7aa --- /dev/null +++ b/lib/libthread_xu/thread/thr_setschedparam.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1998 Daniel Eischen . + * 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 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 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_setschedparam.c,v 1.13 2003/04/21 04:02:56 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_setschedparam.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include "thr_private.h" + +__weak_reference(_pthread_setschedparam, pthread_setschedparam); + +int +_pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ + struct pthread *curthread = _get_curthread(); + int in_syncq; + int in_readyq = 0; + int old_prio; + int ret = 0; + + if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) { + /* Return an invalid argument error: */ + ret = EINVAL; + } else if ((param->sched_priority < THR_MIN_PRIORITY) || + (param->sched_priority > THR_MAX_PRIORITY)) { + /* Return an unsupported value error. */ + ret = ENOTSUP; + + /* Find the thread in the list of active threads: */ + } else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0)) + == 0) { + /* + * Lock the threads scheduling queue while we change + * its priority: + */ + THR_THREAD_LOCK(curthread, pthread); + if (pthread->state == PS_DEAD) { + THR_THREAD_UNLOCK(curthread, pthread); + _thr_ref_delete(curthread, pthread); + return (ESRCH); + } + in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ; + + /* Set the scheduling policy: */ + pthread->attr.sched_policy = policy; + + if (param->sched_priority == + THR_BASE_PRIORITY(pthread->base_priority)) + /* + * There is nothing to do; unlock the threads + * scheduling queue. + */ + THR_THREAD_UNLOCK(curthread, pthread); + else { + /* + * Remove the thread from its current priority + * queue before any adjustments are made to its + * active priority: + */ + old_prio = pthread->active_priority; + /* if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) */ { + in_readyq = 1; + /* THR_RUNQ_REMOVE(pthread); */ + } + + /* Set the thread base priority: */ + pthread->base_priority &= + (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY); + pthread->base_priority = param->sched_priority; + + /* Recalculate the active priority: */ + pthread->active_priority = MAX(pthread->base_priority, + pthread->inherited_priority); + + if (in_readyq) { + if ((pthread->priority_mutex_count > 0) && + (old_prio > pthread->active_priority)) { + /* + * POSIX states that if the priority is + * being lowered, the thread must be + * inserted at the head of the queue for + * its priority if it owns any priority + * protection or inheritence mutexes. + */ + /* THR_RUNQ_INSERT_HEAD(pthread); */ + } + else + /* THR_RUNQ_INSERT_TAIL(pthread)*/ ; + } + + /* Unlock the threads scheduling queue: */ + THR_THREAD_UNLOCK(curthread, pthread); + + /* + * Check for any mutex priority adjustments. This + * includes checking for a priority mutex on which + * this thread is waiting. + */ + _mutex_notify_priochange(curthread, pthread, in_syncq); + } + _thr_ref_delete(curthread, pthread); + } + return (ret); +} diff --git a/lib/libthread_xu/thread/thr_sig.c b/lib/libthread_xu/thread/thr_sig.c new file mode 100644 index 0000000000..e13f91ddf6 --- /dev/null +++ b/lib/libthread_xu/thread/thr_sig.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_sig.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thr_private.h" + +/* #define DEBUG_SIGNAL */ +#ifdef DEBUG_SIGNAL +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +static void +sigcancel_handler(int sig, siginfo_t *info, ucontext_t *ucp) +{ + struct pthread *curthread = _get_curthread(); + + if (curthread->cancelflags & THR_CANCEL_AT_POINT) + pthread_testcancel(); + if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { + __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL); + _thr_suspend_check(curthread); + } +} + +void +_thr_suspend_check(struct pthread *curthread) +{ + long cycle; + + /* Async suspend. */ + _thr_signal_block(curthread); + THR_LOCK(curthread); + if ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) + == THR_FLAGS_NEED_SUSPEND) { + curthread->flags |= THR_FLAGS_SUSPENDED; + while (curthread->flags & THR_FLAGS_NEED_SUSPEND) { + cycle = curthread->cycle; + THR_UNLOCK(curthread); + _thr_signal_unblock(curthread); + _thr_umtx_wait(&curthread->cycle, cycle, NULL); + _thr_signal_block(curthread); + THR_LOCK(curthread); + } + curthread->flags &= ~THR_FLAGS_SUSPENDED; + } + THR_UNLOCK(curthread); + _thr_signal_unblock(curthread); +} + +void +_thr_signal_init(void) +{ + struct sigaction act; + + /* Install cancel handler. */ + SIGEMPTYSET(act.sa_mask); + act.sa_flags = SA_SIGINFO | SA_RESTART; + act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; + __sys_sigaction(SIGCANCEL, &act, NULL); +} + +void +_thr_signal_deinit(void) +{ +} + +__weak_reference(_sigaction, sigaction); + +int +_sigaction(int sig, const struct sigaction * act, struct sigaction * oact) +{ + /* Check if the signal number is out of range: */ + if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { + /* Return an invalid argument: */ + errno = EINVAL; + return (-1); + } + + return __sys_sigaction(sig, act, oact); +} + +__weak_reference(_sigprocmask, sigprocmask); + +int +_sigprocmask(int how, const sigset_t *set, sigset_t *oset) +{ + const sigset_t *p = set; + sigset_t newset; + + if (how != SIG_UNBLOCK) { + if (set != NULL) { + newset = *set; + SIGDELSET(newset, SIGCANCEL); + p = &newset; + } + } + return (__sys_sigprocmask(how, p, oset)); +} + +__weak_reference(_pthread_sigmask, pthread_sigmask); + +int +_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + if (_sigprocmask(how, set, oset)) + return (errno); + return (0); +} + +__weak_reference(_sigsuspend, sigsuspend); + +int +_sigsuspend(const sigset_t * set) +{ + struct pthread *curthread = _get_curthread(); + sigset_t newset; + const sigset_t *pset; + int oldcancel; + int ret; + + if (SIGISMEMBER(*set, SIGCANCEL)) { + newset = *set; + SIGDELSET(newset, SIGCANCEL); + pset = &newset; + } else + pset = set; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sigsuspend(pset); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +#if 0 +__weak_reference(__sigwait, sigwait); +__weak_reference(__sigtimedwait, sigtimedwait); +__weak_reference(__sigwaitinfo, sigwaitinfo); + +int +__sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec * timeout) +{ + struct pthread *curthread = _get_curthread(); + sigset_t newset; + const sigset_t *pset; + int oldcancel; + int ret; + + if (SIGISMEMBER(*set, SIGCANCEL)) { + newset = *set; + SIGDELSET(newset, SIGCANCEL); + pset = &newset; + } else + pset = set; + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sigtimedwait(pset, info, timeout); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +int +__sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ + struct pthread *curthread = _get_curthread(); + sigset_t newset; + const sigset_t *pset; + int oldcancel; + int ret; + + if (SIGISMEMBER(*set, SIGCANCEL)) { + newset = *set; + SIGDELSET(newset, SIGCANCEL); + pset = &newset; + } else + pset = set; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sigwaitinfo(pset, info); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +int +__sigwait(const sigset_t *set, int *sig) +{ + struct pthread *curthread = _get_curthread(); + sigset_t newset; + const sigset_t *pset; + int oldcancel; + int ret; + + if (SIGISMEMBER(*set, SIGCANCEL)) { + newset = *set; + SIGDELSET(newset, SIGCANCEL); + pset = &newset; + } else + pset = set; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sigwait(pset, sig); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} +#endif diff --git a/lib/libthread_xu/thread/thr_single_np.c b/lib/libthread_xu/thread/thr_single_np.c new file mode 100644 index 0000000000..074a450f57 --- /dev/null +++ b/lib/libthread_xu/thread/thr_single_np.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1996 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_single_np.c,v 1.6 2002/05/24 04:32:28 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_single_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include + +__weak_reference(_pthread_single_np, pthread_single_np); + +int _pthread_single_np() +{ + + /* Enter single-threaded (non-POSIX) scheduling mode: */ + pthread_suspend_all_np(); + /* + * XXX - Do we want to do this? + * __is_threaded = 0; + */ + return (0); +} diff --git a/lib/libthread_xu/thread/thr_spec.c b/lib/libthread_xu/thread/thr_spec.c new file mode 100644 index 0000000000..d6390f486b --- /dev/null +++ b/lib/libthread_xu/thread/thr_spec.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_spec.c,v 1.22 2004/07/13 22:49:58 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_spec.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include "thr_private.h" + +/* Static variables: */ +struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX]; + +__weak_reference(_pthread_key_create, pthread_key_create); +__weak_reference(_pthread_key_delete, pthread_key_delete); +__weak_reference(_pthread_getspecific, pthread_getspecific); +__weak_reference(_pthread_setspecific, pthread_setspecific); + + +int +_pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) +{ + struct pthread *curthread = _get_curthread(); + int i; + + /* Lock the key table: */ + THR_LOCK_ACQUIRE(curthread, &_keytable_lock); + for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + + if (_thread_keytable[i].allocated == 0) { + _thread_keytable[i].allocated = 1; + _thread_keytable[i].destructor = destructor; + _thread_keytable[i].seqno++; + + /* Unlock the key table: */ + THR_LOCK_RELEASE(curthread, &_keytable_lock); + *key = i; + return (0); + } + + } + /* Unlock the key table: */ + THR_LOCK_RELEASE(curthread, &_keytable_lock); + return (EAGAIN); +} + +int +_pthread_key_delete(pthread_key_t key) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + if ((unsigned int)key < PTHREAD_KEYS_MAX) { + /* Lock the key table: */ + THR_LOCK_ACQUIRE(curthread, &_keytable_lock); + + if (_thread_keytable[key].allocated) + _thread_keytable[key].allocated = 0; + else + ret = EINVAL; + + /* Unlock the key table: */ + THR_LOCK_RELEASE(curthread, &_keytable_lock); + } else + ret = EINVAL; + return (ret); +} + +void +_thread_cleanupspecific(void) +{ + struct pthread *curthread = _get_curthread(); + void (*destructor)( void *); + void *data = NULL; + int key; + int i; + + if (curthread->specific == NULL) + return; + + /* Lock the key table: */ + THR_LOCK_ACQUIRE(curthread, &_keytable_lock); + for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) && + (curthread->specific_data_count > 0); i++) { + for (key = 0; (key < PTHREAD_KEYS_MAX) && + (curthread->specific_data_count > 0); key++) { + destructor = NULL; + + if (_thread_keytable[key].allocated && + (curthread->specific[key].data != NULL)) { + if (curthread->specific[key].seqno == + _thread_keytable[key].seqno) { + data = (void *) + curthread->specific[key].data; + destructor = _thread_keytable[key].destructor; + } + curthread->specific[key].data = NULL; + curthread->specific_data_count--; + } + + /* + * If there is a destructore, call it + * with the key table entry unlocked: + */ + if (destructor != NULL) { + /* + * Don't hold the lock while calling the + * destructor: + */ + THR_LOCK_RELEASE(curthread, &_keytable_lock); + destructor(data); + THR_LOCK_ACQUIRE(curthread, &_keytable_lock); + } + } + } + THR_LOCK_RELEASE(curthread, &_keytable_lock); + free(curthread->specific); + curthread->specific = NULL; + if (curthread->specific_data_count > 0) + stderr_debug("Thread %p has exited with leftover " + "thread-specific data after %d destructor iterations\n", + curthread, PTHREAD_DESTRUCTOR_ITERATIONS); +} + +static inline struct pthread_specific_elem * +pthread_key_allocate_data(void) +{ + struct pthread_specific_elem *new_data; + + new_data = (struct pthread_specific_elem *) + malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX); + if (new_data != NULL) { + memset((void *) new_data, 0, + sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX); + } + return (new_data); +} + +int +_pthread_setspecific(pthread_key_t key, const void *value) +{ + struct pthread *pthread; + int ret = 0; + + /* Point to the running thread: */ + pthread = _get_curthread(); + + if ((pthread->specific) || + (pthread->specific = pthread_key_allocate_data())) { + if ((unsigned int)key < PTHREAD_KEYS_MAX) { + if (_thread_keytable[key].allocated) { + if (pthread->specific[key].data == NULL) { + if (value != NULL) + pthread->specific_data_count++; + } else if (value == NULL) + pthread->specific_data_count--; + pthread->specific[key].data = value; + pthread->specific[key].seqno = + _thread_keytable[key].seqno; + ret = 0; + } else + ret = EINVAL; + } else + ret = EINVAL; + } else + ret = ENOMEM; + return (ret); +} + +void * +_pthread_getspecific(pthread_key_t key) +{ + struct pthread *pthread; + void *data; + + /* Point to the running thread: */ + pthread = _get_curthread(); + + /* Check if there is specific data: */ + if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) { + /* Check if this key has been used before: */ + if (_thread_keytable[key].allocated && + (pthread->specific[key].seqno == _thread_keytable[key].seqno)) { + /* Return the value: */ + data = (void *) pthread->specific[key].data; + } else { + /* + * This key has not been used before, so return NULL + * instead: + */ + data = NULL; + } + } else + /* No specific data has been created, so just return NULL: */ + data = NULL; + return (data); +} diff --git a/lib/libthread_xu/thread/thr_spinlock.c b/lib/libthread_xu/thread/thr_spinlock.c new file mode 100644 index 0000000000..c6daf41c94 --- /dev/null +++ b/lib/libthread_xu/thread/thr_spinlock.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1997 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_spinlock.c,v 1.21 2003/12/09 02:37:40 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_spinlock.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#include +#include +#include "spinlock.h" +#include "thr_private.h" + +#define MAX_SPINLOCKS 20 + +/* + * These data structures are used to trace all spinlocks + * in libc. + */ +struct spinlock_extra { + spinlock_t *owner; +}; + +static umtx_t spinlock_static_lock; +static struct spinlock_extra extra[MAX_SPINLOCKS]; +static int spinlock_count; +static int initialized; + +static void init_spinlock(spinlock_t *lck); + +/* + * These are for compatability only. Spinlocks of this type + * are deprecated. + */ + +void +_spinunlock(spinlock_t *lck) +{ + THR_UMTX_UNLOCK(_get_curthread(), (umtx_t *)&lck->access_lock); +} + +void +_spinlock(spinlock_t *lck) +{ + if (!__isthreaded) + PANIC("Spinlock called when not threaded."); + if (!initialized) + PANIC("Spinlocks not initialized."); + if (lck->fname == NULL) + init_spinlock(lck); + THR_UMTX_LOCK(_get_curthread(), (umtx_t *)&lck->access_lock); +} + +void +_spinlock_debug(spinlock_t *lck, char *fname, int lineno) +{ + _spinlock(lck); +} + +static void +init_spinlock(spinlock_t *lck) +{ + static int count = 0; + + THR_UMTX_LOCK(_get_curthread(), &spinlock_static_lock); + if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) { + lck->fname = (char *)&extra[spinlock_count]; + extra[spinlock_count].owner = lck; + spinlock_count++; + } + THR_UMTX_UNLOCK(_get_curthread(), &spinlock_static_lock); + if (lck->fname == NULL && ++count < 5) + stderr_debug("Warning: exceeded max spinlocks"); +} + +void +_thr_spinlock_init(void) +{ + int i; + + _thr_umtx_init(&spinlock_static_lock); + if (initialized != 0) { + /* + * called after fork() to reset state of libc spin locks, + * it is not quite right since libc may be in inconsistent + * state, resetting the locks to allow current thread to be + * able to hold them may not help things too much, but + * anyway, we do our best. + * it is better to do pthread_atfork in libc. + */ + for (i = 0; i < spinlock_count; i++) + _thr_umtx_init((umtx_t *)&extra[i].owner->access_lock); + } else { + initialized = 1; + } +} diff --git a/lib/libthread_xu/thread/thr_stack.c b/lib/libthread_xu/thread/thr_stack.c new file mode 100644 index 0000000000..927d7350a7 --- /dev/null +++ b/lib/libthread_xu/thread/thr_stack.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2001 Daniel Eischen + * Copyright (c) 2000-2001 Jason Evans + * 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 AUTHORS 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 AUTHORS 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_stack.c,v 1.9 2004/10/06 08:11:07 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_stack.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include +#include +#include "thr_private.h" + +/* Spare thread stack. */ +struct stack { + LIST_ENTRY(stack) qe; /* Stack queue linkage. */ + size_t stacksize; /* Stack size (rounded up). */ + size_t guardsize; /* Guard size. */ + void *stackaddr; /* Stack address. */ +}; + +/* + * Default sized (stack and guard) spare stack queue. Stacks are cached + * to avoid additional complexity managing mmap()ed stack regions. Spare + * stacks are used in LIFO order to increase cache locality. + */ +static LIST_HEAD(, stack) dstackq = LIST_HEAD_INITIALIZER(dstackq); + +/* + * Miscellaneous sized (non-default stack and/or guard) spare stack queue. + * Stacks are cached to avoid additional complexity managing mmap()ed + * stack regions. This list is unordered, since ordering on both stack + * size and guard size would be more trouble than it's worth. Stacks are + * allocated from this cache on a first size match basis. + */ +static LIST_HEAD(, stack) mstackq = LIST_HEAD_INITIALIZER(mstackq); + +/** + * Base address of the last stack allocated (including its red zone, if + * there is one). Stacks are allocated contiguously, starting beyond the + * top of the main stack. When a new stack is created, a red zone is + * typically created (actually, the red zone is mapped with PROT_NONE) above + * the top of the stack, such that the stack will not be able to grow all + * the way to the bottom of the next stack. This isn't fool-proof. It is + * possible for a stack to grow by a large amount, such that it grows into + * the next stack, and as long as the memory within the red zone is never + * accessed, nothing will prevent one thread stack from trouncing all over + * the next. + * + * low memory + * . . . . . . . . . . . . . . . . . . + * | | + * | stack 3 | start of 3rd thread stack + * +-----------------------------------+ + * | | + * | Red Zone (guard page) | red zone for 2nd thread + * | | + * +-----------------------------------+ + * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack + * | | + * | | + * | | + * | | + * | stack 2 | + * +-----------------------------------+ <-- start of 2nd thread stack + * | | + * | Red Zone | red zone for 1st thread + * | | + * +-----------------------------------+ + * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack + * | | + * | | + * | | + * | | + * | stack 1 | + * +-----------------------------------+ <-- start of 1st thread stack + * | | (initial value of last_stack) + * | Red Zone | + * | | red zone for main thread + * +-----------------------------------+ + * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack + * | | ^ + * | | | + * | | | + * | | | stack growth + * | | + * +-----------------------------------+ <-- start of main thread stack + * (USRSTACK) + * high memory + * + */ +static void *last_stack = NULL; + +/* + * Round size up to the nearest multiple of + * _thr_page_size. + */ +static inline size_t +round_up(size_t size) +{ + if (size % _thr_page_size != 0) + size = ((size / _thr_page_size) + 1) * + _thr_page_size; + return size; +} + +int +_thr_stack_alloc(struct pthread_attr *attr) +{ + struct pthread *curthread = _get_curthread(); + struct stack *spare_stack; + size_t stacksize; + size_t guardsize; + char *stackaddr; + + /* + * Round up stack size to nearest multiple of _thr_page_size so + * that mmap() * will work. If the stack size is not an even + * multiple, we end up initializing things such that there is + * unused space above the beginning of the stack, so the stack + * sits snugly against its guard. + */ + stacksize = round_up(attr->stacksize_attr); + guardsize = round_up(attr->guardsize_attr); + + attr->stackaddr_attr = NULL; + attr->flags &= ~THR_STACK_USER; + + /* + * Use the garbage collector lock for synchronization of the + * spare stack lists and allocations from usrstack. + */ + THREAD_LIST_LOCK(curthread); + /* + * If the stack and guard sizes are default, try to allocate a stack + * from the default-size stack cache: + */ + if ((stacksize == THR_STACK_DEFAULT) && + (guardsize == _thr_guard_default)) { + if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) { + /* Use the spare stack. */ + LIST_REMOVE(spare_stack, qe); + attr->stackaddr_attr = spare_stack->stackaddr; + } + } + /* + * The user specified a non-default stack and/or guard size, so try to + * allocate a stack from the non-default size stack cache, using the + * rounded up stack size (stack_size) in the search: + */ + else { + LIST_FOREACH(spare_stack, &mstackq, qe) { + if (spare_stack->stacksize == stacksize && + spare_stack->guardsize == guardsize) { + LIST_REMOVE(spare_stack, qe); + attr->stackaddr_attr = spare_stack->stackaddr; + break; + } + } + } + if (attr->stackaddr_attr != NULL) { + /* A cached stack was found. Release the lock. */ + THREAD_LIST_UNLOCK(curthread); + } + else { + /* Allocate a stack from usrstack. */ + if (last_stack == NULL) + last_stack = _usrstack - THR_STACK_INITIAL - + _thr_guard_default; + + /* Allocate a new stack. */ + stackaddr = last_stack - stacksize - guardsize; + + /* + * Even if stack allocation fails, we don't want to try to + * use this location again, so unconditionally decrement + * last_stack. Under normal operating conditions, the most + * likely reason for an mmap() error is a stack overflow of + * the adjacent thread stack. + */ + last_stack -= (stacksize + guardsize); + + /* Release the lock before mmap'ing it. */ + THREAD_LIST_UNLOCK(curthread); + + /* Map the stack and guard page together, and split guard + page from allocated space: */ + if ((stackaddr = mmap(stackaddr, stacksize+guardsize, + PROT_READ | PROT_WRITE, MAP_STACK, + -1, 0)) != MAP_FAILED && + (guardsize == 0 || + mprotect(stackaddr, guardsize, PROT_NONE) == 0)) { + stackaddr += guardsize; + } else { + if (stackaddr != MAP_FAILED) + munmap(stackaddr, stacksize + guardsize); + stackaddr = NULL; + } + attr->stackaddr_attr = stackaddr; + } + if (attr->stackaddr_attr != NULL) + return (0); + else + return (-1); +} + +/* This function must be called with _thread_list_lock held. */ +void +_thr_stack_free(struct pthread_attr *attr) +{ + struct stack *spare_stack; + + if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0) + && (attr->stackaddr_attr != NULL)) { + spare_stack = (attr->stackaddr_attr + attr->stacksize_attr + - sizeof(struct stack)); + spare_stack->stacksize = round_up(attr->stacksize_attr); + spare_stack->guardsize = round_up(attr->guardsize_attr); + spare_stack->stackaddr = attr->stackaddr_attr; + + if (spare_stack->stacksize == THR_STACK_DEFAULT && + spare_stack->guardsize == _thr_guard_default) { + /* Default stack/guard size. */ + LIST_INSERT_HEAD(&dstackq, spare_stack, qe); + } else { + /* Non-default stack/guard size. */ + LIST_INSERT_HEAD(&mstackq, spare_stack, qe); + } + attr->stackaddr_attr = NULL; + } +} diff --git a/lib/libthread_xu/thread/thr_suspend_np.c b/lib/libthread_xu/thread/thr_suspend_np.c new file mode 100644 index 0000000000..de71e61350 --- /dev/null +++ b/lib/libthread_xu/thread/thr_suspend_np.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1995-1998 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_suspend_np.c,v 1.19 2003/05/04 16:17:01 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_suspend_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include "thr_private.h" + +static void suspend_common(struct pthread *thread); + +__weak_reference(_pthread_suspend_np, pthread_suspend_np); +__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np); + +/* Suspend a thread: */ +int +_pthread_suspend_np(pthread_t thread) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* Suspending the current thread doesn't make sense. */ + if (thread == _get_curthread()) + ret = EDEADLK; + + /* Add a reference to the thread: */ + else if ((ret = _thr_ref_add(curthread, thread, /*include dead*/0)) + == 0) { + /* Lock the threads scheduling queue: */ + THR_THREAD_LOCK(curthread, thread); + suspend_common(thread); + /* Unlock the threads scheduling queue: */ + THR_THREAD_UNLOCK(curthread, thread); + + /* Don't forget to remove the reference: */ + _thr_ref_delete(curthread, thread); + } + return (ret); +} + +void +_pthread_suspend_all_np(void) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *thread; + + /* Take the thread list lock: */ + THREAD_LIST_LOCK(curthread); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != curthread) { + THR_THREAD_LOCK(curthread, thread); + suspend_common(thread); + THR_THREAD_UNLOCK(curthread, thread); + } + } + + /* Release the thread list lock: */ + THREAD_LIST_UNLOCK(curthread); +} + +static void +suspend_common(struct pthread *thread) +{ + if (thread->state != PS_DEAD) { + thread->flags |= THR_FLAGS_NEED_SUSPEND; + _thr_send_sig(thread, SIGCANCEL); + } +} diff --git a/lib/libthread_xu/thread/thr_switch_np.c b/lib/libthread_xu/thread/thr_switch_np.c new file mode 100644 index 0000000000..823dc5f495 --- /dev/null +++ b/lib/libthread_xu/thread/thr_switch_np.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998 Daniel Eischen . + * 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 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 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_switch_np.c,v 1.7 2003/04/18 05:04:16 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_switch_np.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include +#include +#include "thr_private.h" + + +__weak_reference(_pthread_switch_add_np, pthread_switch_add_np); +__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np); + +int +_pthread_switch_add_np(pthread_switch_routine_t routine) +{ + return (ENOTSUP); +} + +int +_pthread_switch_delete_np(pthread_switch_routine_t routine) +{ + return (ENOTSUP); +} diff --git a/lib/libthread_xu/thread/thr_symbols.c b/lib/libthread_xu/thread/thr_symbols.c new file mode 100644 index 0000000000..d38da5462e --- /dev/null +++ b/lib/libthread_xu/thread/thr_symbols.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004 David Xu + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_symbols.c,v 1.1 2004/08/16 03:25:07 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_symbols.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#include +#include +#ifndef __DragonFly__ +#include +#endif + +#include "thr_private.h" + +/* A collection of symbols needed by debugger */ + +int _thread_off_tcb = offsetof(struct pthread, tcb); +int _thread_off_tid = offsetof(struct pthread, tid); +int _thread_off_next = offsetof(struct pthread, tle.tqe_next); +int _thread_off_attr_flags = offsetof(struct pthread, attr.flags); +int _thread_off_thr_locklevel = offsetof(struct pthread, locklevel); +int _thread_off_isdead = offsetof(struct pthread, terminated); +int _thread_size_key = sizeof(struct pthread_key); +int _thread_off_key_allocated = offsetof(struct pthread_key, allocated); +int _thread_off_key_destructor = offsetof(struct pthread_key, destructor); +int _thread_max_keys = PTHREAD_KEYS_MAX; +int _thread_off_dtv = DTV_OFFSET; +int _thread_off_state = offsetof(struct pthread, state); +int _thread_state_running = PS_RUNNING; +int _thread_state_zoombie = PS_DEAD; +#ifndef __DragonFly__ +int _thread_off_linkmap = offsetof(Obj_Entry, linkmap); +int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex); +#endif diff --git a/lib/libthread_xu/thread/thr_syscalls.c b/lib/libthread_xu/thread/thr_syscalls.c new file mode 100644 index 0000000000..577c8bc00b --- /dev/null +++ b/lib/libthread_xu/thread/thr_syscalls.c @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2005 David Xu . + * Copyright (c) 2003 Daniel Eischen . + * Copyright (C) 2000 Jason Evans . + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_syscalls.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* + * Copyright (c) 1995-1998 John Birrell + * 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 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thr_private.h" + +extern int __creat(const char *, mode_t); +extern int __pause(void); +extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timespec *timo, const sigset_t *mask); +extern unsigned int __sleep(unsigned int); +extern int __system(const char *); +extern int __tcdrain(int); +extern pid_t __wait(int *); +extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *); +extern pid_t __waitpid(pid_t, int *, int); + +__weak_reference(__accept, accept); +int +__accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + struct pthread *curthread; + int oldcancel; + int ret; + + curthread = _get_curthread(); + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_accept(s, addr, addrlen); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(_aio_suspend, aio_suspend); + +int +_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct + timespec *timeout) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_aio_suspend(iocbs, niocb, timeout); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(__close, close); + +int +__close(int fd) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_close(fd); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(__connect, connect); + +int +__connect(int fd, const struct sockaddr *name, socklen_t namelen) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + curthread = _get_curthread(); + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_connect(fd, name, namelen); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(___creat, creat); + +int +___creat(const char *path, mode_t mode) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __creat(path, mode); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__fcntl, fcntl); + +int +__fcntl(int fd, int cmd,...) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + va_list ap; + + oldcancel = _thr_cancel_enter(curthread); + + va_start(ap, cmd); + switch (cmd) { + case F_DUPFD: + ret = __sys_fcntl(fd, cmd, va_arg(ap, int)); + break; + case F_SETFD: + case F_SETFL: + ret = __sys_fcntl(fd, cmd, va_arg(ap, int)); + break; + case F_GETFD: + case F_GETFL: + ret = __sys_fcntl(fd, cmd); + break; + default: + ret = __sys_fcntl(fd, cmd, va_arg(ap, void *)); + } + va_end(ap); + + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(__fsync, fsync); + +int +__fsync(int fd) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_fsync(fd); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(__msync, msync); + +int +__msync(void *addr, size_t len, int flags) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_msync(addr, len, flags); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__nanosleep, nanosleep); + +int +__nanosleep(const struct timespec *time_to_sleep, + struct timespec *time_remaining) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_nanosleep(time_to_sleep, time_remaining); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(___open, open); + +int +___open(const char *path, int flags,...) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + int mode = 0; + va_list ap; + + _thread_printf(1, "%s %s\n", __func__, path); + oldcancel = _thr_cancel_enter(curthread); + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + ret = __sys_open(path, flags, mode); + + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(_pause, pause); + +int +_pause(void) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __pause(); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__poll, poll); + +int +__poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_poll(fds, nfds, timeout); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +#if 0 +__weak_reference(_pselect, pselect); + +int +_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timespec *timo, const sigset_t *mask) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __pselect(count, rfds, wfds, efds, timo, mask); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} +#endif + +__weak_reference(_raise, raise); + +int +_raise(int sig) +{ + int ret; + + if (!_thr_isthreaded()) + ret = kill(getpid(), sig); + else { + ret = pthread_kill(pthread_self(), sig); + if (ret != 0) { + errno = ret; + ret = -1; + } + } + return (ret); +} + +__weak_reference(__read, read); + +ssize_t +__read(int fd, void *buf, size_t nbytes) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + ssize_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_read(fd, buf, nbytes); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__readv, readv); + +ssize_t +__readv(int fd, const struct iovec *iov, int iovcnt) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + ssize_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_readv(fd, iov, iovcnt); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__recvfrom, recvfrom); + +ssize_t +__recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from, + socklen_t *fl) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + ssize_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_recvfrom(s, b, l, f, from, fl); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +__weak_reference(__recvmsg, recvmsg); + +ssize_t +__recvmsg(int s, struct msghdr *m, int f) +{ + struct pthread *curthread = _get_curthread(); + ssize_t ret; + int oldcancel; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_recvmsg(s, m, f); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +__weak_reference(__select, select); + +int +__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout); + _thr_cancel_leave(curthread, oldcancel); + return ret; +} + +__weak_reference(__sendmsg, sendmsg); + +ssize_t +__sendmsg(int s, const struct msghdr *m, int f) +{ + struct pthread *curthread = _get_curthread(); + ssize_t ret; + int oldcancel; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sendmsg(s, m, f); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +__weak_reference(__sendto, sendto); + +ssize_t +__sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t, + socklen_t tl) +{ + struct pthread *curthread = _get_curthread(); + ssize_t ret; + int oldcancel; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_sendto(s, m, l, f, t, tl); + _thr_cancel_leave(curthread, oldcancel); + return (ret); +} + +unsigned int +_sleep(unsigned int seconds) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + unsigned int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sleep(seconds); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(_system, system); + +int +_system(const char *string) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __system(string); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(_tcdrain, tcdrain); + +int +_tcdrain(int fd) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __tcdrain(fd); + _thr_cancel_leave(curthread, oldcancel); + + return (ret); +} + +__weak_reference(_vfork, vfork); + +int +_vfork(void) +{ + return (fork()); +} + +__weak_reference(_wait, wait); + +pid_t +_wait(int *istat) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + pid_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __wait(istat); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__wait4, wait4); + +pid_t +__wait4(pid_t pid, int *istat, int options, struct rusage *rusage) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + pid_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_wait4(pid, istat, options, rusage); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(_waitpid, waitpid); + +pid_t +_waitpid(pid_t wpid, int *status, int options) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + pid_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __waitpid(wpid, status, options); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__write, write); + +ssize_t +__write(int fd, const void *buf, size_t nbytes) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + ssize_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_write(fd, buf, nbytes); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__weak_reference(__writev, writev); + +ssize_t +__writev(int fd, const struct iovec *iov, int iovcnt) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + ssize_t ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __sys_writev(fd, iov, iovcnt); + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} diff --git a/lib/libthread_xu/thread/thr_umtx.c b/lib/libthread_xu/thread/thr_umtx.c new file mode 100644 index 0000000000..5b6d74e0b8 --- /dev/null +++ b/lib/libthread_xu/thread/thr_umtx.c @@ -0,0 +1,242 @@ +/*- + * Copyright (c) 2005 David Xu + * Copyright (c) 2005 Matthew Dillon + * + * 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_umtx.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +/* + * Part of these code is derived from /usr/src/test/debug/umtx.c. + */ + +#include +#include +#include +#include + +#include "thr_private.h" + +static int get_contested(volatile umtx_t *mtx, int timo); + +int +__thr_umtx_lock(volatile umtx_t *mtx, int timo) +{ + int v; + int ret; + + for (;;) { + v = *mtx; + if ((v & UMTX_LOCKED) == 0) { + /* not locked, attempt to lock. */ + if (atomic_cmpset_acq_int(mtx, v, v | UMTX_LOCKED)) { + ret = 0; + break; + } + } else { + /* + * Locked, bump the contested count and obtain + * the contested mutex. + */ + if (atomic_cmpset_acq_int(mtx, v, v + 1)) { + ret = get_contested(mtx, timo); + break; + } + } + } + + return (ret); +} + +static int +get_contested(volatile umtx_t *mtx, int timo) +{ + int ret = 0; + int v; + + for (;;) { + v = *mtx; + assert(v & ~UMTX_LOCKED); /* our contesting count still there */ + if ((v & UMTX_LOCKED) == 0) { + /* + * Not locked, attempt to remove our contested + * count and lock at the same time. + */ + if (atomic_cmpset_acq_int(mtx, v, (v - 1) | UMTX_LOCKED)) { + ret = 0; + break; + } + } else { + /* + * Retried after resuming from umtx_sleep, try to leave if there + * was error, e.g, timeout. + */ + if (ret) { + if (atomic_cmpset_acq_int(mtx, v, v - 1)) + break; + else + continue; + } + + /* + * Still locked, sleep and try again. + */ + if (timo == 0) { + umtx_sleep(mtx, v, 0); + } else { + if (umtx_sleep(mtx, v, timo) < 0) { + if (errno == EAGAIN) + ret = ETIMEDOUT; + } + } + } + } + + return (ret); +} + +void +__thr_umtx_unlock(volatile umtx_t *mtx) +{ + int v; + + for (;;) { + v = *mtx; + assert(v & UMTX_LOCKED); /* we still have it locked */ + if (v == UMTX_LOCKED) { + /* + * We hold an uncontested lock, try to set to an unlocked + * state. + */ + if (atomic_cmpset_acq_int(mtx, UMTX_LOCKED, 0)) + return; + } else { + /* + * We hold a contested lock, unlock and wakeup exactly + * one sleeper. It is possible for this to race a new + * thread obtaining a lock, in which case any contested + * sleeper we wake up will simply go back to sleep. + */ + if (atomic_cmpset_acq_int(mtx, v, v & ~UMTX_LOCKED)) { + umtx_wakeup(mtx, 1); + return; + } + } + } +} + +int +__thr_umtx_timedlock(volatile umtx_t *mtx, const struct timespec *timeout) +{ + struct timespec ts, ts2, ts3; + int timo, ret; + + if ((timeout->tv_sec < 0) || + (timeout->tv_sec == 0 && timeout->tv_nsec <= 0)) + return (ETIMEDOUT); + + /* XXX there should have MONO timer! */ + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_ADD(&ts, &ts, timeout); + ts2 = *timeout; + + for (;;) { + if (ts2.tv_nsec) { + timo = (int)(ts2.tv_nsec / 1000); + if (timo == 0) + timo = 1; + } else { + timo = 1000000; + } + ret = __thr_umtx_lock(mtx, timo); + if (ret != ETIMEDOUT) + break; + clock_gettime(CLOCK_REALTIME, &ts3); + TIMESPEC_SUB(&ts2, &ts, &ts3); + if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { + ret = ETIMEDOUT; + break; + } + } + return (ret); +} + +int +_thr_umtx_wait(volatile umtx_t *mtx, int exp, const struct timespec *timeout) +{ + struct timespec ts, ts2, ts3; + int timo, ret = 0; + + if (*mtx != exp) + return (0); + + if (timeout == NULL) { + if (umtx_sleep(mtx, exp, 0) < 0) { + if (errno == EINTR) + ret = EINTR; + } + return (ret); + } + + if ((timeout->tv_sec < 0) || + (timeout->tv_sec == 0 && timeout->tv_nsec <= 0)) + return (ETIMEDOUT); + + /* XXX there should have MONO timer! */ + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_ADD(&ts, &ts, timeout); + ts2 = *timeout; + + for (;;) { + if (ts2.tv_nsec) { + timo = (int)(ts2.tv_nsec / 1000); + if (timo == 0) + timo = 1; + } else { + timo = 1000000; + } + if (umtx_sleep(mtx, exp, timo) < 0) { + if (errno == EBUSY) { + ret = 0; + break; + } else if (errno == EINTR) { + ret = EINTR; + break; + } + } + clock_gettime(CLOCK_REALTIME, &ts3); + TIMESPEC_SUB(&ts2, &ts, &ts3); + if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { + ret = ETIMEDOUT; + break; + } + } + return (ret); +} + +void _thr_umtx_wake(volatile umtx_t *mtx, int count) +{ + umtx_wakeup(mtx, count); +} diff --git a/lib/libthread_xu/thread/thr_umtx.h b/lib/libthread_xu/thread/thr_umtx.h new file mode 100644 index 0000000000..e6a8b94954 --- /dev/null +++ b/lib/libthread_xu/thread/thr_umtx.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2003 David Xu + * 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. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_umtx.h,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ + +#ifndef _THR_DFLY_UMTX_H_ +#define _THR_DFLY_UMTX_H_ + +#include + +#define UMTX_LOCKED 0x80000000 + +typedef int umtx_t; + +int __thr_umtx_lock(volatile umtx_t *mtx, int timo); +int __thr_umtx_timedlock(volatile umtx_t *mtx, + const struct timespec *timeout); +void __thr_umtx_unlock(volatile umtx_t *mtx); + +static inline void +_thr_umtx_init(volatile umtx_t *mtx) +{ + *mtx = 0; +} + +static inline int +_thr_umtx_trylock(volatile umtx_t *mtx, long id) +{ + if (atomic_cmpset_acq_int(mtx, 0, UMTX_LOCKED)) + return (0); + return (EBUSY); +} + +static inline int +_thr_umtx_lock(volatile umtx_t *mtx, long id) +{ + if (atomic_cmpset_acq_int(mtx, 0, UMTX_LOCKED)) + return (0); + return (__thr_umtx_lock(mtx, 0)); +} + +static inline int +_thr_umtx_timedlock(volatile umtx_t *mtx, long id, + const struct timespec *timeout) +{ + if (atomic_cmpset_acq_int(mtx, 0, UMTX_LOCKED)) + return (0); + return (__thr_umtx_timedlock(mtx, timeout)); +} + +static inline void +_thr_umtx_unlock(volatile umtx_t *mtx, long id) +{ + if (atomic_cmpset_acq_int(mtx, UMTX_LOCKED, 0)) + return; + __thr_umtx_unlock(mtx); +} + +int _thr_umtx_wait(volatile umtx_t *mtx, umtx_t exp, + const struct timespec *timeout); +void _thr_umtx_wake(volatile umtx_t *mtx, int count); + +#endif diff --git a/lib/libthread_xu/thread/thr_yield.c b/lib/libthread_xu/thread/thr_yield.c new file mode 100644 index 0000000000..999be9ae91 --- /dev/null +++ b/lib/libthread_xu/thread/thr_yield.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1995 John Birrell . + * 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 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. + * + * $FreeBSD: src/lib/libpthread/thread/thr_yield.c,v 1.15 2003/08/18 03:58:29 davidxu Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_yield.c,v 1.1 2005/02/01 12:38:27 davidxu Exp $ + */ +#include +#include "thr_private.h" + +__weak_reference(_pthread_yield, pthread_yield); + +/* Draft 4 yield */ +void +_pthread_yield(void) +{ + __sys_sched_yield(); +} -- 2.41.0