diff options
Diffstat (limited to 'lib/libthr')
84 files changed, 11659 insertions, 0 deletions
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile new file mode 100644 index 0000000..37073ea --- /dev/null +++ b/lib/libthr/Makefile @@ -0,0 +1,55 @@ +# $FreeBSD$ +# +# 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 <sys/cdefs.h>) 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. + +.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64" +SHLIBDIR?= /lib +.endif + +.include <bsd.own.mk> + +LIB=thr +SHLIB_MAJOR= 2 +CFLAGS+=-DPTHREAD_KERNEL +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+=-I${.CURDIR}/../libthread_db +CFLAGS+=-Winline + +# CFLAGS+=-DSYSTEM_SCOPE_ONLY + +LDFLAGS= -Wl,--version-script=${.CURDIR}/pthread.map + +MAN= libthr.3 + +# enable extra internal consistancy checks +CFLAGS+=-D_PTHREADS_INVARIANTS -Wall +#CFLAGS+=-g + +PRECIOUSLIB= + +.include "${.CURDIR}/arch/${MACHINE_ARCH}/Makefile.inc" +.include "${.CURDIR}/sys/Makefile.inc" +.include "${.CURDIR}/thread/Makefile.inc" + +.if ${MACHINE_ARCH} == "alpha" || ${MACHINE_ARCH} == "sparc64" +SYMLINKS+=lib${LIB}.a ${LIBDIR}/libpthread.a +.if !defined(NO_PIC) +SYMLINKS+=lib${LIB}.so ${LIBDIR}/libpthread.so +.endif +.if ${MK_PROFILE} != "no" +SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a +.endif +.endif + +.include <bsd.lib.mk> diff --git a/lib/libthr/arch/alpha/Makefile.inc b/lib/libthr/arch/alpha/Makefile.inc new file mode 100644 index 0000000..508d2b4 --- /dev/null +++ b/lib/libthr/arch/alpha/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/alpha/alpha/pthread_md.c b/lib/libthr/arch/alpha/alpha/pthread_md.c new file mode 100644 index 0000000..1a82341 --- /dev/null +++ b/lib/libthr/arch/alpha/alpha/pthread_md.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <stdlib.h> +#include <string.h> + +#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) { + memset(tcb, 0, sizeof(struct tcb)); + tcb->tcb_thread = thread; + } + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + free(tcb); +} diff --git a/lib/libthr/arch/alpha/include/pthread_md.h b/lib/libthr/arch/alpha/include/pthread_md.h new file mode 100644 index 0000000..003cba0 --- /dev/null +++ b/lib/libthr/arch/alpha/include/pthread_md.h @@ -0,0 +1,75 @@ +/* + * 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$ + */ + +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> +#include <sys/types.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant I tcb. The structure layout is fixed, don't blindly + * change it! + */ +struct tcb { + void *tcb_dtv; + struct pthread *tcb_thread; +}; + +#define _tp __builtin_thread_pointer() +#define _tcb ((struct tcb *)_tp) + +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) +{ + __builtin_set_thread_pointer(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/libthr/arch/amd64/Makefile.inc b/lib/libthr/arch/amd64/Makefile.inc new file mode 100644 index 0000000..6e6d577 --- /dev/null +++ b/lib/libthr/arch/amd64/Makefile.inc @@ -0,0 +1,5 @@ +#$FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/amd64/amd64/pthread_md.c b/lib/libthr/arch/amd64/amd64/pthread_md.c new file mode 100644 index 0000000..b661657 --- /dev/null +++ b/lib/libthr/arch/amd64/amd64/pthread_md.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#include <rtld_tls.h> + +#include "pthread_md.h" + +/* + * The constructors. + */ +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + + if (initial) + __asm __volatile("movq %%fs:0, %0" : "=r" (tcb)); + else + tcb = _rtld_allocate_tls(NULL, 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/libthr/arch/amd64/include/pthread_md.h b/lib/libthr/arch/amd64/include/pthread_md.h new file mode 100644 index 0000000..30f63ca --- /dev/null +++ b/lib/libthr/arch/amd64/include/pthread_md.h @@ -0,0 +1,99 @@ +/*- + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +/* + * Machine-dependent thread prototypes/definitions. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> +#include <sys/types.h> +#include <machine/sysarch.h> +#include <ucontext.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant II tcb, first two members are required by rtld, + * %fs points to the structure. + */ +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; + void *tcb_spare[1]; +}; + +/* + * Evaluates to the byte offset of the per-tcb variable name. + */ +#define __tcb_offset(name) __offsetof(struct tcb, name) + +/* + * Evaluates to the type of the per-tcb variable name. + */ +#define __tcb_type(name) __typeof(((struct tcb *)0)->name) + +/* + * Evaluates to the value of the per-tcb 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; \ +}) + +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *tcb); + +static __inline void +_tcb_set(struct tcb *tcb) +{ + amd64_set_fsbase(tcb); +} + +static __inline struct tcb * +_tcb_get(void) +{ + return (TCB_GET64(tcb_self)); +} + +static __inline struct pthread * +_get_curthread(void) +{ + return (TCB_GET64(tcb_thread)); +} +#endif diff --git a/lib/libthr/arch/arm/Makefile.inc b/lib/libthr/arch/arm/Makefile.inc new file mode 100644 index 0000000..508d2b4 --- /dev/null +++ b/lib/libthr/arch/arm/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/arm/arm/pthread_md.c b/lib/libthr/arch/arm/arm/pthread_md.c new file mode 100644 index 0000000..7ca2b25 --- /dev/null +++ b/lib/libthr/arch/arm/arm/pthread_md.c @@ -0,0 +1,50 @@ +/*- + * Copyright (C) 2005 David Xu <davidxu@freebsd.org> + * 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$ + */ + +#include <stdlib.h> +#include <sys/types.h> +#include <rtld_tls.h> + +#include "pthread_md.h" + +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + + tcb = malloc(sizeof(struct tcb)); + if (tcb) + tcb->tcb_thread = thread; + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + free(tcb); +} diff --git a/lib/libthr/arch/arm/include/pthread_md.h b/lib/libthr/arch/arm/include/pthread_md.h new file mode 100644 index 0000000..30f9f86 --- /dev/null +++ b/lib/libthr/arch/arm/include/pthread_md.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2005 David Xu <davidxu@freebsd.org>. + * 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$ + */ + +/* + * Machine-dependent thread prototypes/definitions. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <sys/types.h> +#include <machine/sysarch.h> +#include <stddef.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant II tcb, first two members are required by rtld. + */ +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; /* our hook */ + void *tcb_spare[1]; +}; + +/* + * The tcb 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) +{ + *((struct tcb **)ARM_TP_ADDRESS) = tcb; +} + +/* + * Get the current tcb. + */ +static __inline struct tcb * +_tcb_get(void) +{ + return (*((struct tcb **)ARM_TP_ADDRESS)); +} + +extern struct pthread *_thr_initial; + +static __inline struct pthread * +_get_curthread(void) +{ + if (_thr_initial) + return (_tcb_get()->tcb_thread); + return (NULL); +} + +#endif /* _PTHREAD_MD_H_ */ diff --git a/lib/libthr/arch/i386/Makefile.inc b/lib/libthr/arch/i386/Makefile.inc new file mode 100644 index 0000000..508d2b4 --- /dev/null +++ b/lib/libthr/arch/i386/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/i386/i386/pthread_md.c b/lib/libthr/arch/i386/i386/pthread_md.c new file mode 100644 index 0000000..a8b31d5 --- /dev/null +++ b/lib/libthr/arch/i386/i386/pthread_md.c @@ -0,0 +1,57 @@ +/*- + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001,2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#include <machine/segments.h> +#include <machine/sysarch.h> +#include <string.h> +#include <rtld_tls.h> + +#include "pthread_md.h" + +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + + if (initial) + __asm __volatile("movl %%gs:0, %0" : "=r" (tcb)); + else + tcb = _rtld_allocate_tls(NULL, 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/libthr/arch/i386/include/pthread_md.h b/lib/libthr/arch/i386/include/pthread_md.h new file mode 100644 index 0000000..4140b9c --- /dev/null +++ b/lib/libthr/arch/i386/include/pthread_md.h @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>. + * Copyright (c) 2005 David Xu <davidxu@freebsd.org>. + * 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$ + */ + +/* + * Machine-dependent thread prototypes/definitions. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> +#include <sys/types.h> +#include <machine/sysarch.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant II tcb, first two members are required by rtld, + * %gs points to the structure. + */ +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; +}; + +/* + * Evaluates to the byte offset of the per-tcb variable name. + */ +#define __tcb_offset(name) __offsetof(struct tcb, name) + +/* + * Evaluates to the type of the per-tcb variable name. + */ +#define __tcb_type(name) __typeof(((struct tcb *)0)->name) + +/* + * Evaluates to the value of the per-tcb 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; \ +}) + +/* + * 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) +{ + i386_set_gsbase(tcb); +} + +/* Get the current kcb. */ +static __inline struct tcb * +_tcb_get(void) +{ + return (TCB_GET32(tcb_self)); +} + +/* Get the current thread. */ +static __inline struct pthread * +_get_curthread(void) +{ + return (TCB_GET32(tcb_thread)); +} +#endif diff --git a/lib/libthr/arch/ia64/Makefile.inc b/lib/libthr/arch/ia64/Makefile.inc new file mode 100644 index 0000000..c07c097 --- /dev/null +++ b/lib/libthr/arch/ia64/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/ia64/ia64/pthread_md.c b/lib/libthr/arch/ia64/ia64/pthread_md.c new file mode 100644 index 0000000..a6f7def --- /dev/null +++ b/lib/libthr/arch/ia64/ia64/pthread_md.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#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) + oldtls = _tp; + 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(tcb), 16); +} diff --git a/lib/libthr/arch/ia64/include/pthread_md.h b/lib/libthr/arch/ia64/include/pthread_md.h new file mode 100644 index 0000000..aee5dd2 --- /dev/null +++ b/lib/libthr/arch/ia64/include/pthread_md.h @@ -0,0 +1,78 @@ +/* + * 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$ + */ + +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant I tcb. The structure layout is fixed, don't blindly + * change it! + */ +struct tcb { + void *tcb_dtv; + struct pthread *tcb_thread; +}; + +register struct tcb *_tp __asm("%r13"); + +#define _tcb _tp + +/* + * The tcb 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) +{ + _tp = 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/libthr/arch/powerpc/Makefile.inc b/lib/libthr/arch/powerpc/Makefile.inc new file mode 100644 index 0000000..508d2b4 --- /dev/null +++ b/lib/libthr/arch/powerpc/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/powerpc/include/pthread_md.h b/lib/libthr/arch/powerpc/include/pthread_md.h new file mode 100644 index 0000000..008c4cd --- /dev/null +++ b/lib/libthr/arch/powerpc/include/pthread_md.h @@ -0,0 +1,80 @@ +/* + * Copyright 2004 by Peter Grehan. 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. 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$ + */ + +/* + * Machine-dependent thread prototypes/definitions. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> +#include <sys/types.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant I tcb. The structure layout is fixed, don't blindly + * change it. + * %r2 points to end of the structure. + */ +struct tcb { + void *tcb_dtv; + struct pthread *tcb_thread; +}; + +register uint8_t *_tp __asm("%r2"); + +#define _tcb ((struct tcb *)(_tp - sizeof(struct tcb))) + +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *); + +static __inline void +_tcb_set(struct tcb *tcb) +{ + _tp = (uint8_t *)tcb + sizeof(struct 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/libthr/arch/powerpc/powerpc/pthread_md.c b/lib/libthr/arch/powerpc/powerpc/pthread_md.c new file mode 100644 index 0000000..aa02a8d --- /dev/null +++ b/lib/libthr/arch/powerpc/powerpc/pthread_md.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#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) + oldtls = _tp; + 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(tcb), 16); +} diff --git a/lib/libthr/arch/sparc64/Makefile.inc b/lib/libthr/arch/sparc64/Makefile.inc new file mode 100644 index 0000000..508d2b4 --- /dev/null +++ b/lib/libthr/arch/sparc64/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c diff --git a/lib/libthr/arch/sparc64/include/pthread_md.h b/lib/libthr/arch/sparc64/include/pthread_md.h new file mode 100644 index 0000000..054c2be --- /dev/null +++ b/lib/libthr/arch/sparc64/include/pthread_md.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>. + * 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$ + */ + +/* + * Machine-dependent thread prototypes/definitions. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> + +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +/* + * Variant II tcb, first two members are required by rtld. + * %g7 points to the structure. + */ +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; /* our hook */ + void *tcb_spare[1]; +}; + +register struct tcb *_tp __asm("%g7"); + +#define _tcb (_tp) + +/* + * The tcb 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) +{ + _tp = 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/libthr/arch/sparc64/sparc64/pthread_md.c b/lib/libthr/arch/sparc64/sparc64/pthread_md.c new file mode 100644 index 0000000..3f8e105 --- /dev/null +++ b/lib/libthr/arch/sparc64/sparc64/pthread_md.c @@ -0,0 +1,56 @@ +/*- + * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org> + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001,2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#include <rtld_tls.h> + +#include "pthread_md.h" + +struct tcb * +_tcb_ctor(struct pthread *thread, int initial) +{ + struct tcb *tcb; + void *oldtls; + + if (initial) + oldtls = _tp; + 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/libthr/libthr.3 b/lib/libthr/libthr.3 new file mode 100644 index 0000000..356edd9 --- /dev/null +++ b/lib/libthr/libthr.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 2005 Robert N. M. Watson +.\" 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$ +.\" +.Dd June 11, 2005 +.Os +.Dt LIBTHR 3 +.Sh NAME +.Nm libthr +.Nd "alternative POSIX threads library" +.Sh LIBRARY +.Lb libthr +.Sh SYNOPSIS +.In pthread.h +.Sh DESCRIPTION +The +.Nm +library provides an alternative 1:1 implementation of the +.Xr pthread 3 +library interfaces for application threading. +While applications may be linked directly against +.Nm , +system administrators are offered maximum flexibility by linking against +.Xr pthread 3 , +as they can then use +.Xr libmap.conf 5 +to select the threading implementation on a per-application basis. +.Pp +The +.Nm +library +has been optimized for use by applications expecting system scope thread +semantics, and can provide significant performance improvements. +.Sh SEE ALSO +.Xr pthread 3 +.Sh AUTHORS +.An -nosplit +The +.Nm +library +was originally created by +.An "Jeff Roberson" Aq jeff@FreeBSD.org , +and enhanced by +.An "Jonathan Mini" Aq mini@FreeBSD.org +and +.An "Mike Makonnen" Aq mtm@FreeBSD.org . +It has been substantially rewritten and optimized by +.An "David Xu" Aq davidxu@FreeBSD.org . diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map new file mode 100644 index 0000000..66ebf44 --- /dev/null +++ b/lib/libthr/pthread.map @@ -0,0 +1,761 @@ +# $FreeBSD$ +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_timedlock; + __pthread_mutex_trylock; + __read; + __readv; + __recvfrom; + __recvmsg; + __select; + __sendmsg; + __sendto; + __sigsuspend; + __sigtimedwait; + __sigwait; + __sigwaitinfo; + __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_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_getpshared; + _pthread_mutexattr_gettype; + _pthread_mutexattr_init; + _pthread_mutexattr_setkind_np; + _pthread_mutexattr_setprioceiling; + _pthread_mutexattr_setprotocol; + _pthread_mutexattr_setpshared; + _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_timedjoin_np; + _pthread_yield; + _raise; + _sem_destroy; + _sem_getvalue; + _sem_init; + _sem_post; + _sem_timedwait; + _sem_trywait; + _sem_wait; + _sigaction; + _sigprocmask; + _sigsuspend; + _sigtimedwait; + _sigwait; + _sigwaitinfo; + _sleep; + _spinlock; + _spinlock_debug; + _spinunlock; + _system; + _tcdrain; + _usleep; + _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_getpshared; + pthread_mutexattr_getprotocol; + pthread_mutexattr_gettype; + pthread_mutexattr_init; + pthread_mutexattr_setkind_np; + pthread_mutexattr_setprioceiling; + pthread_mutexattr_setprotocol; + pthread_mutexattr_setpshared; + 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_timedjoin_np; + pthread_yield; + raise; + read; + readv; + recvfrom; + recvmsg; + select; + sem_destroy; + sem_getvalue; + sem_init; + sem_post; + sem_timedwait; + sem_trywait; + sem_wait; + sendmsg; + sendto; + sigaction; + sigprocmask; + sigsuspend; + sigwait; + sigwaitinfo; + sigtimedwait; + sleep; + system; + tcdrain; + usleep; + vfork; + wait; + wait4; + waitpid; + write; + writev; + + # Debugger needs these. + _libthr_debug; + _thread_active_threads; + _thread_bp_create; + _thread_bp_death; + _thread_event_mask; + _thread_keytable; + _thread_last_event; + _thread_list; + _thread_max_keys; + _thread_off_attr_flags; + _thread_off_dtv; + _thread_off_event_buf; + _thread_off_event_mask; + _thread_off_key_allocated; + _thread_off_key_destructor; + _thread_off_linkmap; + _thread_off_next; + _thread_off_report_events; + _thread_off_state; + _thread_off_tcb; + _thread_off_tid; + _thread_off_tlsindex; + _thread_size_key; + _thread_state_running; + _thread_state_zoombie; +local: + *; +}; + +# +# Use the same naming scheme as libc. +# +FBSD_1.0 { +global: + __error; + 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_getpshared; + pthread_mutexattr_getprotocol; + pthread_mutexattr_gettype; + pthread_mutexattr_init; + pthread_mutexattr_setkind_np; + pthread_mutexattr_setprioceiling; + pthread_mutexattr_setprotocol; + pthread_mutexattr_setpshared; + 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_timedjoin_np; + pthread_yield; + raise; + read; + readv; + recvfrom; + recvmsg; + select; + sem_destroy; + sem_getvalue; + sem_init; + sem_post; + sem_timedwait; + sem_trywait; + sem_wait; + sendmsg; + sendto; + sigaction; + sigprocmask; + sigsuspend; + sigwait; + sigwaitinfo; + sigtimedwait; + sleep; + system; + tcdrain; + usleep; + vfork; + wait; + wait4; + waitpid; + write; + writev; +local: + *; +}; + +# +# List the private interfaces reserved for use in FreeBSD libraries. +# These are not part of our application ABI. +# +FBSDprivate { +global: + ___creat; + __accept; + __close; + __connect; + __fcntl; + __fsync; + __msync; + __nanosleep; + __open; + __poll; + __pthread_cond_timedwait; + __pthread_cond_wait; + __pthread_mutex_init; + __pthread_mutex_lock; + __pthread_mutex_timedlock; + __pthread_mutex_trylock; + __read; + __readv; + __recvfrom; + __recvmsg; + __select; + __sendmsg; + __sendto; + __sigsuspend; + __sigtimedwait; + __sigwait; + __sigwaitinfo; + __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_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_getpshared; + _pthread_mutexattr_gettype; + _pthread_mutexattr_init; + _pthread_mutexattr_setkind_np; + _pthread_mutexattr_setprioceiling; + _pthread_mutexattr_setprotocol; + _pthread_mutexattr_setpshared; + _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_timedjoin_np; + _pthread_yield; + _raise; + _sem_destroy; + _sem_getvalue; + _sem_init; + _sem_post; + _sem_timedwait; + _sem_trywait; + _sem_wait; + _sigaction; + _sigprocmask; + _sigsuspend; + _sigtimedwait; + _sigwait; + _sigwaitinfo; + _sleep; + _spinlock; + _spinlock_debug; + _spinunlock; + _system; + _tcdrain; + _usleep; + _vfork; + _wait; + _waitpid; + + # Debugger needs these. + _libthr_debug; + _thread_active_threads; + _thread_bp_create; + _thread_bp_death; + _thread_event_mask; + _thread_keytable; + _thread_last_event; + _thread_list; + _thread_max_keys; + _thread_off_attr_flags; + _thread_off_dtv; + _thread_off_event_buf; + _thread_off_event_mask; + _thread_off_key_allocated; + _thread_off_key_destructor; + _thread_off_linkmap; + _thread_off_next; + _thread_off_report_events; + _thread_off_state; + _thread_off_tcb; + _thread_off_tid; + _thread_off_tlsindex; + _thread_size_key; + _thread_state_running; + _thread_state_zoombie; +local: + *; +}; diff --git a/lib/libthr/support/Makefile.inc b/lib/libthr/support/Makefile.inc new file mode 100644 index 0000000..bcf4393 --- /dev/null +++ b/lib/libthr/support/Makefile.inc @@ -0,0 +1,22 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/support ${.CURDIR}/../libc/gen ${.CURDIR}/../libc/string +.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sys + +CFLAGS+= -I${.CURDIR}/../libc/${MACHINE_ARCH} + +SYSCALLS= thr_new + +SYSCALL_SRC= ${SYSCALLS:S/$/.S/} +SYSCALL_OBJ= ${SYSCALLS:S/$/.So/} + +${SYSCALL_SRC}: + printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' > ${.TARGET} + +LIBC_OBJS= + +SOBJS+= thr_libc.So +CLEANFILES+= ${SYSCALL_SRC} ${SYSCALL_OBJ} ${LIBC_OBJS} + +thr_libc.So: ${SYSCALL_OBJ} ${LIBC_OBJS} + ${CC} -fPIC -nostdlib -o ${.TARGET} -r ${.ALLSRC} diff --git a/lib/libthr/sys/Makefile.inc b/lib/libthr/sys/Makefile.inc new file mode 100644 index 0000000..70c6dda --- /dev/null +++ b/lib/libthr/sys/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/sys + +SRCS+= thr_error.c diff --git a/lib/libthr/sys/thr_error.c b/lib/libthr/sys/thr_error.c new file mode 100644 index 0000000..902c054 --- /dev/null +++ b/lib/libthr/sys/thr_error.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * 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$ + */ + +#include <pthread.h> + +#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/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc new file mode 100644 index 0000000..bdae92e --- /dev/null +++ b/lib/libthr/thread/Makefile.inc @@ -0,0 +1,54 @@ +# $FreeBSD$ + +# thr sources +.PATH: ${.CURDIR}/thread + +SRCS+= \ + thr_attr.c \ + thr_barrier.c \ + thr_barrierattr.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_event.c \ + thr_exit.c \ + thr_fork.c \ + thr_getprio.c \ + thr_getschedparam.c \ + thr_info.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_once.c \ + thr_printf.c \ + thr_pspinlock.c \ + thr_resume_np.c \ + thr_rtld.c \ + thr_rwlock.c \ + thr_rwlockattr.c \ + thr_self.c \ + thr_sem.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/libthr/thread/thr_atfork.c b/lib/libthr/thread/thr_atfork.c new file mode 100644 index 0000000..370623a --- /dev/null +++ b/lib/libthr/thread/thr_atfork.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/queue.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); +} diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c new file mode 100644 index 0000000..24dd064 --- /dev/null +++ b/lib/libthr/thread/thr_attr.c @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by 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 <eischen@vigrid.com>. + * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. + * Copyright (c) 2002,2003 Alexey Zelkin <phantom@FreeBSD.org> + * 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 <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#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; + if (pid->tlflags & TLFLAGS_DETACHED) + attr.flags |= PTHREAD_DETACHED; + _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; + + _thr_check_init(); + + /* 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)); + + /* 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 policy; + + if ((attr == NULL) || (*attr == NULL)) + return (EINVAL); + + if (param == NULL) + return (ENOTSUP); + + policy = (*attr)->sched_policy; + + if (param->sched_priority < _thr_priorities[policy-1].pri_min || + param->sched_priority > _thr_priorities[policy-1].pri_max) + return (ENOTSUP); + + (*attr)->prio = param->sched_priority; + + return (0); +} + +__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; + (*attr)->prio = _thr_priorities[policy-1].pri_default; + } + 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/libthr/thread/thr_autoinit.c b/lib/libthr/thread/thr_autoinit.c new file mode 100644 index 0000000..c425569 --- /dev/null +++ b/lib/libthr/thread/thr_autoinit.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002 Alfred Perlstein <alfred@freebsd.org>. + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <pthread.h> + +#include "thr_private.h" + +/* + * This module uses GCC extentions to initialize the + * threads package at program start-up time. + */ + +void _thread_init_hack(void) __attribute__ ((constructor)); + +void +_thread_init_hack(void) +{ + + _thread_init(); +} + +/* + * For the shared version of the threads library, the above is sufficient. + * But for the archive version of the library, we need a little bit more. + * Namely, we must arrange for this particular module to be pulled in from + * the archive library at link time. To accomplish that, we define and + * initialize a variable, "_thread_autoinit_dummy_decl". This variable is + * referenced (as an extern) from libc/stdlib/exit.c. This will always + * create a need for this module, ensuring that it is present in the + * executable. + */ +extern int _thread_autoinit_dummy_decl; +int _thread_autoinit_dummy_decl = 0; diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c new file mode 100644 index 0000000..8d65d9f --- /dev/null +++ b/lib/libthr/thread/thr_barrier.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2003 David Xu <davidxu@freebsd.org> + * 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$ + */ + +#include "namespace.h" +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "un-namespace.h" + +#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, unsigned count) +{ + pthread_barrier_t bar; + + (void)attr; + + 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, bar->b_count - 1); + 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/libthr/thread/thr_barrierattr.c b/lib/libthr/thread/thr_barrierattr.c new file mode 100644 index 0000000..32b9723 --- /dev/null +++ b/lib/libthr/thread/thr_barrierattr.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003 David Xu <davidxu@freebsd.org>. + * 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$ + */ + +#include "namespace.h" +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c new file mode 100644 index 0000000..1047eb2 --- /dev/null +++ b/lib/libthr/thread/thr_cancel.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2005, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" + +#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_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) && !THR_IN_CRITICAL(curthread)) + _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/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c new file mode 100644 index 0000000..a5e9378 --- /dev/null +++ b/lib/libthr/thread/thr_clean.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <signal.h> +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_concurrency.c b/lib/libthr/thread/thr_concurrency.c new file mode 100644 index 0000000..61f0c4a --- /dev/null +++ b/lib/libthr/thread/thr_concurrency.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003 Sergey Osokin <osa@FreeBSD.org.ru>. + * 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 Sergey Osokin. + * 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 SERGEY OSOKIN 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 "namespace.h" +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +static int current_concurrency = 0; + +__weak_reference(_pthread_getconcurrency, pthread_getconcurrency); +__weak_reference(_pthread_setconcurrency, pthread_setconcurrency); + +int +_pthread_getconcurrency(void) +{ + return current_concurrency; +} + +int +_pthread_setconcurrency(int new_level) +{ + int ret; + + if (new_level < 0) { + ret = EINVAL; + } else { + current_concurrency = new_level; + ret = 0; + } + return (ret); +} diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c new file mode 100644 index 0000000..f786062 --- /dev/null +++ b/lib/libthr/thread/thr_cond.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + */ + +#include "namespace.h" +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include <limits.h> +#include "un-namespace.h" + +#include "thr_private.h" + +/* + * Prototypes + */ +int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime); +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; + int count; +}; + +static void +cond_cancel_handler(void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct cond_cancel_info *info = (struct cond_cancel_info *)arg; + pthread_cond_t cv; + + cv = *(info->cond); + THR_LOCK_ACQUIRE(curthread, &cv->c_lock); + if (cv->c_seqno != info->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(info->mutex, info->count); +} + +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 info; + 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, &info.count); + if (ret) { + THR_LOCK_RELEASE(curthread, &cv->c_lock); + return (ret); + } + oldseq = seq = cv->c_seqno; + info.mutex = mutex; + info.cond = cond; + info.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, &info); + 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, info.count); + return (ret); +} + +int +_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + + return (cond_wait_common(cond, mutex, NULL, 0)); +} + +int +__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + + return (cond_wait_common(cond, mutex, NULL, 1)); +} + +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)); +} + +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, oldwaiters; + + /* + * 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 { + oldwaiters = cv->c_waiters; + cv->c_wakeups += cv->c_waiters; + cv->c_waiters = 0; + cv->c_seqno++; + _thr_umtx_wake(&cv->c_seqno, oldwaiters); + } + } + THR_LOCK_RELEASE(curthread, &cv->c_lock); + return (ret); +} + +int +_pthread_cond_signal(pthread_cond_t * cond) +{ + + return (cond_signal_common(cond, 0)); +} + +int +_pthread_cond_broadcast(pthread_cond_t * cond) +{ + + return (cond_signal_common(cond, 1)); +} diff --git a/lib/libthr/thread/thr_condattr.c b/lib/libthr/thread/thr_condattr.c new file mode 100644 index 0000000..9e14dc2 --- /dev/null +++ b/lib/libthr/thread/thr_condattr.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#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(pthread_condattr_t *attr, + clockid_t clock_id) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + if (clock_id != CLOCK_REALTIME && + clock_id != CLOCK_VIRTUAL && + clock_id != CLOCK_PROF && + clock_id != CLOCK_MONOTONIC) { + 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/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c new file mode 100644 index 0000000..bb5724a --- /dev/null +++ b/lib/libthr/thread/thr_create.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com> + * Copyright (c) 2005, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/signalvar.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +static int create_stack(struct pthread_attr *pattr); +static void thread_start(struct pthread *curthread); + +__weak_reference(_pthread_create, pthread_create); + +int +_pthread_create(pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + struct pthread *curthread, *new_thread; + struct thr_param param; + int ret = 0, locked, create_suspended; + sigset_t set, oset; + + _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); + + memset(¶m, 0, sizeof(param)); + + 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 (_thr_scope_system > 0) + new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM; + else if (_thr_scope_system < 0) + new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM; + + new_thread->tid = TID_TERMINATED; + + if (create_stack(&new_thread->attr) != 0) { + /* Insufficient memory to create a stack: */ + _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); + + /* Initialise hooks in the thread structure: */ + if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) { + new_thread->flags = THR_FLAGS_NEED_SUSPEND; + create_suspended = 1; + } else { + create_suspended = 0; + } + + new_thread->state = PS_RUNNING; + + if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) + new_thread->tlflags |= TLFLAGS_DETACHED; + + /* Add the new thread. */ + new_thread->refcount = 1; + _thr_link(curthread, new_thread); + /* Return thread pointer eariler so that new thread can use it. */ + (*thread) = new_thread; + if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) { + THR_THREAD_LOCK(curthread, new_thread); + locked = 1; + } else + locked = 0; + param.start_func = (void (*)(void *)) thread_start; + param.arg = new_thread; + param.stack_base = new_thread->attr.stackaddr_attr; + param.stack_size = new_thread->attr.stacksize_attr; + param.tls_base = (char *)new_thread->tcb; + param.tls_size = sizeof(struct tcb); + param.child_tid = &new_thread->tid; + param.parent_tid = &new_thread->tid; + param.flags = 0; + if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) + param.flags |= THR_SYSTEM_SCOPE; + + /* Schedule the new thread. */ + if (create_suspended) { + SIGFILLSET(set); + SIGDELSET(set, SIGTRAP); + __sys_sigprocmask(SIG_SETMASK, &set, &oset); + new_thread->sigmask = oset; + } + + ret = thr_new(¶m, sizeof(param)); + + if (create_suspended) + __sys_sigprocmask(SIG_SETMASK, &oset, NULL); + + if (ret != 0) { + if (!locked) + THR_THREAD_LOCK(curthread, new_thread); + new_thread->state = PS_DEAD; + new_thread->tid = TID_TERMINATED; + if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) { + new_thread->cycle++; + _thr_umtx_wake(&new_thread->cycle, INT_MAX); + } + THR_THREAD_UNLOCK(curthread, new_thread); + THREAD_LIST_LOCK(curthread); + _thread_active_threads--; + new_thread->tlflags |= TLFLAGS_DETACHED; + _thr_ref_delete_unlocked(curthread, new_thread); + THREAD_LIST_UNLOCK(curthread); + (*thread) = 0; + ret = EAGAIN; + } else if (locked) { + _thr_report_creation(curthread, new_thread); + THR_THREAD_UNLOCK(curthread, new_thread); + } + return (ret); +} + +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 +thread_start(struct pthread *curthread) +{ + if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { + sigset_t set = curthread->sigmask; + + _thr_ast(curthread); + + /* + * Parent thread have stored signal mask for us, + * we should restore it now. + */ + sigprocmask(SIG_SETMASK, &set, NULL); + } + + /* + * This is used as a serialization point to allow parent + * to report 'new thread' event to debugger before the thread + * does real work. + */ + THR_LOCK(curthread); + THR_UNLOCK(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/libthr/thread/thr_detach.c b/lib/libthr/thread/thr_detach.c new file mode 100644 index 0000000..bfcb6e6 --- /dev/null +++ b/lib/libthr/thread/thr_detach.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + +#include "namespace.h" +#include <sys/types.h> +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_equal.c b/lib/libthr/thread/thr_equal.c new file mode 100644 index 0000000..f9f4916 --- /dev/null +++ b/lib/libthr/thread/thr_equal.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include "un-namespace.h" +#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/libthr/thread/thr_event.c b/lib/libthr/thread/thr_event.c new file mode 100644 index 0000000..6a64cf9 --- /dev/null +++ b/lib/libthr/thread/thr_event.c @@ -0,0 +1,65 @@ +/* + * 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. 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$ + */ + +#include "thr_private.h" + +void +_thread_bp_create(void) +{ +} + +void +_thread_bp_death(void) +{ +} + +void +_thr_report_creation(struct pthread *curthread, struct pthread *newthread) +{ + curthread->event_buf.event = TD_CREATE; + curthread->event_buf.th_p = (td_thrhandle_t *)newthread; + curthread->event_buf.data = 0; + THR_UMTX_LOCK(curthread, &_thr_event_lock); + _thread_last_event = curthread; + _thread_bp_create(); + _thread_last_event = NULL; + THR_UMTX_UNLOCK(curthread, &_thr_event_lock); +} + +void +_thr_report_death(struct pthread *curthread) +{ + curthread->event_buf.event = TD_DEATH; + curthread->event_buf.th_p = (td_thrhandle_t *)curthread; + curthread->event_buf.data = 0; + THR_UMTX_LOCK(curthread, &_thr_event_lock); + _thread_last_event = curthread; + _thread_bp_death(); + _thread_last_event = NULL; + THR_UMTX_UNLOCK(curthread, &_thr_event_lock); +} diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c new file mode 100644 index 0000000..d438ac5 --- /dev/null +++ b/lib/libthr/thread/thr_exit.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +#include "thr_private.h" + +void _pthread_exit(void *status); + +__weak_reference(_pthread_exit, pthread_exit); + +void +_thread_exit(const char *fname, int lineno, const 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); + } + + /* 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! */ + } + THR_LOCK(curthread); + curthread->state = PS_DEAD; + THR_UNLOCK(curthread); + /* + * Thread was created with initial refcount 1, we drop the + * reference count to allow it to be garbage collected. + */ + curthread->refcount--; + if (curthread->tlflags & TLFLAGS_DETACHED) + THR_GCLIST_ADD(curthread); + THREAD_LIST_UNLOCK(curthread); + if (SHOULD_REPORT_EVENT(curthread, TD_DEATH)) + _thr_report_death(curthread); + + /* + * Kernel will do wakeup at the address, so joiner thread + * will be resumed if it is sleeping at the address. + */ + thr_exit(&curthread->tid); + PANIC("thr_exit() returned"); + /* Never reach! */ +} diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c new file mode 100644 index 0000000..558a036 --- /dev/null +++ b/lib/libthr/thread/thr_fork.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org> + * 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$ + */ + +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include <spinlock.h> +#include "un-namespace.h" + +#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); +} + +__weak_reference(_fork, fork); + +pid_t _fork(void); + +pid_t +_fork(void) +{ + struct pthread *curthread; + struct pthread_atfork *af; + pid_t ret; + int errsave; + int unlock_malloc; + + if (!_thr_is_inited()) + return (__sys_fork()); + + curthread = _get_curthread(); + + THR_UMTX_LOCK(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(); + } + + /* + * 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) { + unlock_malloc = 1; + _malloc_prefork(); + } else { + unlock_malloc = 0; + } + + /* + * 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; + 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. */ + thr_self(&curthread->tid); + + /* clear other threads locked us. */ + _thr_umtx_init(&curthread->lock); + _thr_umtx_init(&_thr_atfork_lock); + _thr_setthreaded(0); + + /* reinitialize libc spinlocks. */ + _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; + + /* Ready to continue, unblock signals. */ + _thr_signal_unblock(curthread); + + if (unlock_malloc) + _malloc_postfork(); + + /* Run down atfork parent handlers. */ + TAILQ_FOREACH(af, &_thr_atfork_list, qe) { + if (af->parent != NULL) + af->parent(); + } + + THR_UMTX_UNLOCK(curthread, &_thr_atfork_lock); + } + errno = errsave; + + /* Return the process ID: */ + return (ret); +} diff --git a/lib/libthr/thread/thr_getprio.c b/lib/libthr/thread/thr_getprio.c new file mode 100644 index 0000000..e2cac2f --- /dev/null +++ b/lib/libthr/thread/thr_getprio.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" +#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/libthr/thread/thr_getschedparam.c b/lib/libthr/thread/thr_getschedparam.c new file mode 100644 index 0000000..31b3268 --- /dev/null +++ b/lib/libthr/thread/thr_getschedparam.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel 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$ + */ + +#include "namespace.h" +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#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 = 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 = 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/libthr/thread/thr_info.c b/lib/libthr/thread/thr_info.c new file mode 100644 index 0000000..804ce98 --- /dev/null +++ b/lib/libthr/thread/thr_info.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#include "thr_private.h" + +__weak_reference(_pthread_set_name_np, pthread_set_name_np); + +/* Set the thread name for debug. */ +void +_pthread_set_name_np(pthread_t thread, const char *name) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + if (curthread == thread) { + if (thr_set_name(thread->tid, name)) + ret = errno; + } else { + if (_thr_ref_add(curthread, thread, 0) == 0) { + THR_LOCK(thread); + if (thread->state != PS_DEAD) { + if (thr_set_name(thread->tid, name)) + ret = errno; + } + THR_UNLOCK(thread); + _thr_ref_delete(curthread, thread); + } else { + ret = ESRCH; + } + } +#if 0 + /* XXX should return error code. */ + return (ret); +#endif +} diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c new file mode 100644 index 0000000..40365a0 --- /dev/null +++ b/lib/libthr/thread/thr_init.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org> + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <sys/types.h> +#include <sys/signalvar.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> +#include <sys/ttycom.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pthread.h> +#include <pthread_np.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "thr_private.h" + +char *_usrstack; +struct pthread *_thr_initial; +int _thr_scope_system; +int _libthr_debug; +int _thread_event_mask; +struct pthread *_thread_last_event; +pthreadlist _thread_list = TAILQ_HEAD_INITIALIZER(_thread_list); +pthreadlist _thread_gc_list = TAILQ_HEAD_INITIALIZER(_thread_gc_list); +int _thread_active_threads = 1; +atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list); +umtx_t _thr_atfork_lock; + +/* + * XXX these values should be updated from kernel at startup, + * but current they are same. + */ +struct pthread_prio _thr_priorities[3] = { + {0, 31, 0}, /* FIF0 */ + {-20, 20, 0}, /* OTHER */ + {0, 31, 0} /* RR */ +}; + +struct pthread_attr _pthread_attr_default = { + .sched_policy = SCHED_OTHER, + .sched_inherit = 0, + .prio = 0, + .suspend = THR_CREATE_RUNNING, + .flags = PTHREAD_SCOPE_SYSTEM, + .stackaddr_attr = NULL, + .stacksize_attr = THR_STACK_DEFAULT, + .guardsize_attr = 0 +}; + +struct pthread_mutex_attr _pthread_mutexattr_default = { + .m_type = PTHREAD_MUTEX_DEFAULT, + .m_protocol = PTHREAD_PRIO_NONE, + .m_ceiling = 0, + .m_flags = 0 +}; + +/* Default condition variable attributes: */ +struct pthread_cond_attr _pthread_condattr_default = { + .c_pshared = PTHREAD_PROCESS_PRIVATE, + .c_clockid = CLOCK_REALTIME +}; + +pid_t _thr_pid; +size_t _thr_guard_default; +size_t _thr_stack_default = THR_STACK_DEFAULT; +size_t _thr_stack_initial = THR_STACK_INITIAL; +int _thr_page_size; +int _gc_count; +umtx_t _mutex_static_lock; +umtx_t _cond_static_lock; +umtx_t _rwlock_static_lock; +umtx_t _keytable_lock; +umtx_t _thr_list_lock; +umtx_t _thr_event_lock; + +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_hack(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_LIB_REQUIRE(_accept); +STATIC_LIB_REQUIRE(_close); +STATIC_LIB_REQUIRE(_connect); +STATIC_LIB_REQUIRE(_fcntl); +STATIC_LIB_REQUIRE(_fsync); +STATIC_LIB_REQUIRE(_nanosleep); +STATIC_LIB_REQUIRE(_open); +STATIC_LIB_REQUIRE(_pthread_getspecific); +STATIC_LIB_REQUIRE(_pthread_key_create); +STATIC_LIB_REQUIRE(_pthread_key_delete); +STATIC_LIB_REQUIRE(_pthread_mutex_destroy); +STATIC_LIB_REQUIRE(_pthread_mutex_init); +STATIC_LIB_REQUIRE(_pthread_mutex_lock); +STATIC_LIB_REQUIRE(_pthread_mutex_trylock); +STATIC_LIB_REQUIRE(_pthread_mutex_unlock); +STATIC_LIB_REQUIRE(_pthread_mutexattr_init); +STATIC_LIB_REQUIRE(_pthread_mutexattr_destroy); +STATIC_LIB_REQUIRE(_pthread_mutexattr_settype); +STATIC_LIB_REQUIRE(_pthread_once); +STATIC_LIB_REQUIRE(_pthread_setspecific); +STATIC_LIB_REQUIRE(_read); +STATIC_LIB_REQUIRE(_readv); +STATIC_LIB_REQUIRE(_recvfrom); +STATIC_LIB_REQUIRE(_recvmsg); +STATIC_LIB_REQUIRE(_select); +STATIC_LIB_REQUIRE(_sendmsg); +STATIC_LIB_REQUIRE(_sendto); +STATIC_LIB_REQUIRE(_sigaction); +STATIC_LIB_REQUIRE(_sigprocmask); +STATIC_LIB_REQUIRE(_sigsuspend); +STATIC_LIB_REQUIRE(_socket); +STATIC_LIB_REQUIRE(_socketpair); +STATIC_LIB_REQUIRE(_thread_init_hack); +STATIC_LIB_REQUIRE(_wait4); +STATIC_LIB_REQUIRE(_write); +STATIC_LIB_REQUIRE(_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_LIB_REQUIRE(_pthread_once); +STATIC_LIB_REQUIRE(_pthread_key_create); +STATIC_LIB_REQUIRE(_pthread_key_delete); +STATIC_LIB_REQUIRE(_pthread_getspecific); +STATIC_LIB_REQUIRE(_pthread_setspecific); +STATIC_LIB_REQUIRE(_pthread_mutex_init); +STATIC_LIB_REQUIRE(_pthread_mutex_destroy); +STATIC_LIB_REQUIRE(_pthread_mutex_lock); +STATIC_LIB_REQUIRE(_pthread_mutex_trylock); +STATIC_LIB_REQUIRE(_pthread_mutex_unlock); +STATIC_LIB_REQUIRE(_pthread_create); + +/* Pull in all symbols required by libthread_db */ +STATIC_LIB_REQUIRE(_thread_state_running); + +#define DUAL_ENTRY(entry) \ + (pthread_func_t)entry, (pthread_func_t)entry + +static pthread_func_t jmp_table[][2] = { + {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */ + {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */ + {DUAL_ENTRY(_pthread_attr_getdetachstate)}, /* PJT_ATTR_GETDETACHSTATE */ + {DUAL_ENTRY(_pthread_attr_getguardsize)}, /* PJT_ATTR_GETGUARDSIZE */ + {DUAL_ENTRY(_pthread_attr_getinheritsched)}, /* PJT_ATTR_GETINHERITSCHED */ + {DUAL_ENTRY(_pthread_attr_getschedparam)}, /* PJT_ATTR_GETSCHEDPARAM */ + {DUAL_ENTRY(_pthread_attr_getschedpolicy)}, /* PJT_ATTR_GETSCHEDPOLICY */ + {DUAL_ENTRY(_pthread_attr_getscope)}, /* PJT_ATTR_GETSCOPE */ + {DUAL_ENTRY(_pthread_attr_getstackaddr)}, /* PJT_ATTR_GETSTACKADDR */ + {DUAL_ENTRY(_pthread_attr_getstacksize)}, /* PJT_ATTR_GETSTACKSIZE */ + {DUAL_ENTRY(_pthread_attr_init)}, /* PJT_ATTR_INIT */ + {DUAL_ENTRY(_pthread_attr_setdetachstate)}, /* PJT_ATTR_SETDETACHSTATE */ + {DUAL_ENTRY(_pthread_attr_setguardsize)}, /* PJT_ATTR_SETGUARDSIZE */ + {DUAL_ENTRY(_pthread_attr_setinheritsched)}, /* PJT_ATTR_SETINHERITSCHED */ + {DUAL_ENTRY(_pthread_attr_setschedparam)}, /* PJT_ATTR_SETSCHEDPARAM */ + {DUAL_ENTRY(_pthread_attr_setschedpolicy)}, /* PJT_ATTR_SETSCHEDPOLICY */ + {DUAL_ENTRY(_pthread_attr_setscope)}, /* PJT_ATTR_SETSCOPE */ + {DUAL_ENTRY(_pthread_attr_setstackaddr)}, /* PJT_ATTR_SETSTACKADDR */ + {DUAL_ENTRY(_pthread_attr_setstacksize)}, /* PJT_ATTR_SETSTACKSIZE */ + {DUAL_ENTRY(_pthread_cancel)}, /* PJT_CANCEL */ + {DUAL_ENTRY(_pthread_cleanup_pop)}, /* PJT_CLEANUP_POP */ + {DUAL_ENTRY(_pthread_cleanup_push)}, /* PJT_CLEANUP_PUSH */ + {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 */ + {DUAL_ENTRY(_pthread_cond_timedwait)}, /* PJT_COND_TIMEDWAIT */ + {(pthread_func_t)__pthread_cond_wait, + (pthread_func_t)_pthread_cond_wait}, /* PJT_COND_WAIT */ + {DUAL_ENTRY(_pthread_detach)}, /* PJT_DETACH */ + {DUAL_ENTRY(_pthread_equal)}, /* PJT_EQUAL */ + {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */ + {DUAL_ENTRY(_pthread_getspecific)}, /* PJT_GETSPECIFIC */ + {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */ + {DUAL_ENTRY(_pthread_key_create)}, /* PJT_KEY_CREATE */ + {DUAL_ENTRY(_pthread_key_delete)}, /* PJT_KEY_DELETE*/ + {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */ + {DUAL_ENTRY(_pthread_main_np)}, /* PJT_MAIN_NP */ + {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_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_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_setcancelstate)}, /* PJT_SETCANCELSTATE */ + {DUAL_ENTRY(_pthread_setcanceltype)}, /* PJT_SETCANCELTYPE */ + {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */ + {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */ + {DUAL_ENTRY(_pthread_testcancel)} /* PJT_TESTCANCEL */ +}; + +static int init_once = 0; + +/* + * For the shared version of the threads library, the above is sufficient. + * But for the archive version of the library, we need a little bit more. + * Namely, we must arrange for this particular module to be pulled in from + * the archive library at link time. To accomplish that, we define and + * initialize a variable, "_thread_autoinit_dummy_decl". This variable is + * referenced (as an extern) from libc/stdlib/exit.c. This will always + * create a need for this module, ensuring that it is present in the + * executable. + */ +extern int _thread_autoinit_dummy_decl; +int _thread_autoinit_dummy_decl = 0; + +void +_thread_init_hack(void) +{ + + _libpthread_init(NULL); +} + + +/* + * 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; + + /* + * 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)); + + /* + * 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 (_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); + SIGDELSET(sigset, SIGTRAP); + __sys_sigprocmask(SIG_SETMASK, &sigset, &oldset); + _thr_signal_init(); + _thr_initial = curthread; + SIGDELSET(oldset, SIGCANCEL); + __sys_sigprocmask(SIG_SETMASK, &oldset, NULL); + if (_thread_event_mask & TD_CREATE) + _thr_report_creation(curthread, curthread); + } +} + +/* + * 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. */ + thr_self(&thread->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(_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 = _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; + thr_set_name(thread->tid, "initial thread"); + + /* Default the priority of the initial thread: */ + thread->base_priority = THR_DEF_PRIORITY; + thread->active_priority = THR_DEF_PRIORITY; + thread->inherited_priority = 0; + + /* Initialize the mutex queue: */ + TAILQ_INIT(&thread->mutexq); + + thread->state = PS_RUNNING; + + /* 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_umtx_init(&_thr_event_lock); + _thr_once_init(); + _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; + _pthread_attr_default.stacksize_attr = _thr_stack_default; + + TAILQ_INIT(&_thr_atfork_list); +#ifdef SYSTEM_SCOPE_ONLY + _thr_scope_system = 1; +#else + if (getenv("LIBPTHREAD_SYSTEM_SCOPE") != NULL) + _thr_scope_system = 1; + else if (getenv("LIBPTHREAD_PROCESS_SCOPE") != NULL) + _thr_scope_system = -1; +#endif + } + init_once = 1; +} diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c new file mode 100644 index 0000000..de27074 --- /dev/null +++ b/lib/libthr/thread/thr_join.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + +#include "namespace.h" +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +int _pthread_timedjoin_np(pthread_t pthread, void **thread_return, + const struct timespec *abstime); +static int join_common(pthread_t, void **, const struct timespec *); + +__weak_reference(_pthread_join, pthread_join); +__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); + +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) +{ + return (join_common(pthread, thread_return, NULL)); +} + +int +_pthread_timedjoin_np(pthread_t pthread, void **thread_return, + const struct timespec *abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + + return (join_common(pthread, thread_return, abstime)); +} + +static int +join_common(pthread_t pthread, void **thread_return, + const struct timespec *abstime) +{ + struct pthread *curthread = _get_curthread(); + struct timespec ts, ts2, *tsp; + void *tmp; + long tid; + 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); + + tid = pthread->tid; + while (pthread->tid != TID_TERMINATED) { + if (abstime != NULL) { + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + if (ts2.tv_sec < 0) { + ret = ETIMEDOUT; + break; + } + tsp = &ts2; + } else + tsp = NULL; + ret = _thr_umtx_wait(&pthread->tid, tid, tsp); + if (ret == ETIMEDOUT) + break; + } + + _thr_cancel_leave(curthread, oldcancel); + THR_CLEANUP_POP(curthread, 0); + + if (ret == ETIMEDOUT) { + THREAD_LIST_LOCK(curthread); + pthread->joiner = NULL; + THREAD_LIST_UNLOCK(curthread); + } else { + ret = 0; + tmp = pthread->ret; + THREAD_LIST_LOCK(curthread); + pthread->tlflags |= TLFLAGS_DETACHED; + pthread->joiner = NULL; + THR_GCLIST_ADD(pthread); + THREAD_LIST_UNLOCK(curthread); + + if (thread_return != NULL) + *thread_return = tmp; + } + return (ret); +} diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c new file mode 100644 index 0000000..aa7dce6 --- /dev/null +++ b/lib/libthr/thread/thr_kern.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org> + * 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/signalvar.h> +#include <pthread.h> + +#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 (threaded != 0) { + _thr_rtld_init(); + } else { + _thr_rtld_fini(); + } + 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); +} + +int +_thr_send_sig(struct pthread *thread, int sig) +{ + return thr_kill(thread->tid, sig); +} + +void +_thr_assert_lock_level() +{ + PANIC("locklevel <= 0"); +} diff --git a/lib/libthr/thread/thr_kill.c b/lib/libthr/thread/thr_kill.c new file mode 100644 index 0000000..e55681a --- /dev/null +++ b/lib/libthr/thread/thr_kill.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c new file mode 100644 index 0000000..d46b5ea --- /dev/null +++ b/lib/libthr/thread/thr_list.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org> + * 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/queue.h> + +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#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 MAX_THREADS 100000 + +/* + * 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 int total_threads; + +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 >> 8) % HASH_QUEUES) + +static void thr_destroy(struct pthread *curthread, struct pthread *thread); + +void +_thr_list_init(void) +{ + int i; + + _gc_count = 0; + total_threads = 1; + _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->tid != TID_TERMINATED) { + /* 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; + } + + _thr_free(curthread, td); + } +} + +struct pthread * +_thr_alloc(struct pthread *curthread) +{ + struct pthread *thread = NULL; + struct tcb *tcb; + + 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); + free_thread_count--; + } + THR_LOCK_RELEASE(curthread, &free_thread_lock); + } + } + if (thread == NULL) { + if (total_threads > MAX_THREADS) + return (NULL); + atomic_fetchadd_int(&total_threads, 1); + thread = malloc(sizeof(struct pthread)); + if (thread == NULL) { + atomic_fetchadd_int(&total_threads, -1); + return (NULL); + } + } + if (curthread != NULL) { + 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) { + memset(thread, 0, sizeof(*thread)); + thread->tcb = tcb; + } else { + thr_destroy(curthread, thread); + atomic_fetchadd_int(&total_threads, -1); + thread = NULL; + } + return (thread); +} + +void +_thr_free(struct pthread *curthread, struct pthread *thread) +{ + DBG_MSG("Freeing thread %p\n", thread); + + /* + * Always free tcb, as we only know it is part of RTLD TLS + * block, but don't know its detail and can not assume how + * it works, so better to avoid caching it here. + */ + if (curthread != NULL) { + THR_LOCK_ACQUIRE(curthread, &tcb_lock); + _tcb_dtor(thread->tcb); + THR_LOCK_RELEASE(curthread, &tcb_lock); + } else { + _tcb_dtor(thread->tcb); + } + thread->tcb = NULL; + if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) { + thr_destroy(curthread, thread); + atomic_fetchadd_int(&total_threads, -1); + } else { + /* + * Add the thread to the free thread list, this also avoids + * pthread id is reused too quickly, may help some buggy apps. + */ + 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 __unused, struct pthread *thread) +{ + free(thread); +} + +/* + * 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); + THR_LIST_ADD(thread); + _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) +{ + THREAD_LIST_LOCK(curthread); + _thr_ref_delete_unlocked(curthread, thread); + THREAD_LIST_UNLOCK(curthread); +} + +void +_thr_ref_delete_unlocked(struct pthread *curthread __unused, + struct pthread *thread) +{ + if (thread != NULL) { + thread->refcount--; + if ((thread->refcount == 0) && thread->state == PS_DEAD && + (thread->tlflags & TLFLAGS_DETACHED) != 0) + THR_GCLIST_ADD(thread); + } +} + +int +_thr_find_thread(struct pthread *curthread __unused, 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/libthr/thread/thr_main_np.c b/lib/libthr/thread/thr_main_np.c new file mode 100644 index 0000000..bfa8b87 --- /dev/null +++ b/lib/libthr/thread/thr_main_np.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein <alfred@FreeBSD.org> + * 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$ + */ + +#include "namespace.h" +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_multi_np.c b/lib/libthr/thread/thr_multi_np.c new file mode 100644 index 0000000..3ea2cb4 --- /dev/null +++ b/lib/libthr/thread/thr_multi_np.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +__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/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c new file mode 100644 index 0000000..e79e014 --- /dev/null +++ b/lib/libthr/thread/thr_mutex.c @@ -0,0 +1,669 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 2006 David Xu <davidxu@freebsd.org>. + * 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 "namespace.h" +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <pthread.h> +#include "un-namespace.h" + +#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) +#else +#define MUTEX_INIT_LINK(m) +#define MUTEX_ASSERT_IS_OWNED(m) +#define MUTEX_ASSERT_NOT_OWNED(m) +#endif + +/* + * Prototypes + */ +int __pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr); +int __pthread_mutex_trylock(pthread_mutex_t *mutex); +int __pthread_mutex_lock(pthread_mutex_t *mutex); +int __pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime); + +static int mutex_self_trylock(pthread_mutex_t); +static int mutex_self_lock(pthread_mutex_t, + const struct timespec *abstime); +static int mutex_unlock_common(pthread_mutex_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); + +__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling); +__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling); + +static int +mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *mutex_attr, int private) +{ + const struct pthread_mutex_attr *attr; + struct pthread_mutex *pmutex; + + if (mutex_attr == NULL) { + attr = &_pthread_mutexattr_default; + } else { + attr = *mutex_attr; + if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK || + attr->m_type >= PTHREAD_MUTEX_TYPE_MAX) + return (EINVAL); + if (attr->m_protocol < PTHREAD_PRIO_NONE || + attr->m_protocol > PTHREAD_PRIO_PROTECT) + return (EINVAL); + } + + if ((pmutex = (pthread_mutex_t) + malloc(sizeof(struct pthread_mutex))) == NULL) + return (ENOMEM); + + _thr_umtx_init(&pmutex->m_lock); + pmutex->m_type = attr->m_type; + pmutex->m_protocol = attr->m_protocol; + TAILQ_INIT(&pmutex->m_queue); + pmutex->m_owner = NULL; + pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED; + if (private) + pmutex->m_flags |= MUTEX_FLAGS_PRIVATE; + pmutex->m_count = 0; + pmutex->m_refcount = 0; + if (attr->m_protocol == PTHREAD_PRIO_PROTECT) + pmutex->m_prio = attr->m_ceiling; + else + pmutex->m_prio = -1; + pmutex->m_saved_prio = 0; + MUTEX_INIT_LINK(pmutex); + *mutex = pmutex; + return (0); +} + +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; + + /* + * Fix mutex ownership for child process. + * note that process shared mutex should not + * be inherited because owner is forking thread + * which is in parent process, they should be + * removed from the owned mutex list, current, + * process shared mutex is not supported, so I + * am not worried. + */ + TAILQ_FOREACH(m, &curthread->mutexq, m_qe) + m->m_lock = (umtx_t)curthread->tid; +} + +int +_pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + pthread_mutex_t m; + int ret = 0; + + if (__predict_false(*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; + + THR_UMTX_UNLOCK(curthread, &m->m_lock); + + MUTEX_ASSERT_NOT_OWNED(m); + free(m); + } + } + + return (ret); +} + +static int +mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex) +{ + struct pthread_mutex *m; + int ret; + + m = *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_trylock(m); + } /* else {} */ + + return (ret); +} + +int +__pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if (__predict_false(*mutex == NULL)) { + ret = init_static(curthread, mutex); + if (__predict_false(ret)) + return (ret); + } + return (mutex_trylock_common(curthread, mutex)); +} + +int +_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking the mutex private (delete safe): + */ + if (__predict_false(*mutex == NULL)) { + ret = init_static_private(curthread, mutex); + if (__predict_false(ret)) + return (ret); + } + return (mutex_trylock_common(curthread, mutex)); +} + +static int +mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + struct timespec ts, ts2; + struct pthread_mutex *m; + int ret; + + m = *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(m, abstime); + } else { + if (abstime == NULL) { + THR_UMTX_LOCK(curthread, &m->m_lock); + ret = 0; + } else if (__predict_false( + abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000)) { + ret = EINVAL; + } 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); +} + +int +__pthread_mutex_lock(pthread_mutex_t *m) +{ + struct pthread *curthread; + int ret; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if (__predict_false(*m == NULL)) { + ret = init_static(curthread, m); + if (__predict_false(ret)) + return (ret); + } + return (mutex_lock_common(curthread, m, NULL)); +} + +int +_pthread_mutex_lock(pthread_mutex_t *m) +{ + struct pthread *curthread; + int ret; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + if (__predict_false(*m == NULL)) { + ret = init_static_private(curthread, m); + if (__predict_false(ret)) + return (ret); + } + return (mutex_lock_common(curthread, m, NULL)); +} + +int +__pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime) +{ + struct pthread *curthread; + int ret; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if (__predict_false(*m == NULL)) { + ret = init_static(curthread, m); + if (__predict_false(ret)) + return (ret); + } + return (mutex_lock_common(curthread, m, abstime)); +} + +int +_pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime) +{ + struct pthread *curthread; + int ret; + + _thr_check_init(); + + curthread = _get_curthread(); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + if (__predict_false(*m == NULL)) { + ret = init_static_private(curthread, m); + if (__predict_false(ret)) + return (ret); + } + return (mutex_lock_common(curthread, m, abstime)); +} + +int +_pthread_mutex_unlock(pthread_mutex_t *m) +{ + return (mutex_unlock_common(m)); +} + +int +_mutex_cv_lock(pthread_mutex_t *m, int count) +{ + int ret; + + ret = mutex_lock_common(_get_curthread(), m, NULL); + if (ret == 0) { + (*m)->m_refcount--; + (*m)->m_count += count; + } + return (ret); +} + +static int +mutex_self_trylock(pthread_mutex_t m) +{ + int ret; + + switch (m->m_type) { + 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(pthread_mutex_t m, const struct timespec *abstime) +{ + struct timespec ts1, ts2; + int ret; + + switch (m->m_type) { + 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 (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 *mutex) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_mutex *m; + + if (__predict_false((m = *mutex) == NULL)) + return (EINVAL); + + /* + * Check if the running thread is not the owner of the mutex. + */ + if (__predict_false(m->m_owner != curthread)) + return (EPERM); + + if (__predict_false( + m->m_type == PTHREAD_MUTEX_RECURSIVE && + m->m_count > 0)) { + m->m_count--; + } else { + 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); + THR_UMTX_UNLOCK(curthread, &m->m_lock); + } + return (0); +} + +int +_mutex_cv_unlock(pthread_mutex_t *mutex, int *count) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_mutex *m; + + if (__predict_false((m = *mutex) == NULL)) + return (EINVAL); + + /* + * Check if the running thread is not the owner of the mutex. + */ + if (__predict_false(m->m_owner != curthread)) + return (EPERM); + + /* + * Clear the count in case this is a recursive mutex. + */ + *count = m->m_count; + m->m_refcount++; + 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); + THR_UMTX_UNLOCK(curthread, &m->m_lock); + return (0); +} + +void +_mutex_unlock_private(pthread_t pthread) +{ + struct pthread_mutex *m, *m_next; + + for (m = TAILQ_FIRST(&pthread->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); + } +} + +int +_pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) +{ + int ret; + + if (*mutex == NULL) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else { + *prioceiling = (*mutex)->m_prio; + ret = 0; + } + + return(ret); +} + +int +_pthread_mutex_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) +{ + int ret = 0; + int tmp; + + if (*mutex == NULL) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else if ((ret = _pthread_mutex_lock(mutex)) == 0) { + tmp = (*mutex)->m_prio; + (*mutex)->m_prio = prioceiling; + ret = _pthread_mutex_unlock(mutex); + + /* Return the old ceiling. */ + *old_ceiling = tmp; + } + return(ret); +} diff --git a/lib/libthr/thread/thr_mutex_prioceiling.c b/lib/libthr/thread/thr_mutex_prioceiling.c new file mode 100644 index 0000000..edea124 --- /dev/null +++ b/lib/libthr/thread/thr_mutex_prioceiling.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel 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$ + */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#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/libthr/thread/thr_mutex_protocol.c b/lib/libthr/thread/thr_mutex_protocol.c new file mode 100644 index 0000000..526cbe0 --- /dev/null +++ b/lib/libthr/thread/thr_mutex_protocol.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel 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$ + */ + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#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/libthr/thread/thr_mutexattr.c b/lib/libthr/thread/thr_mutexattr.c new file mode 100644 index 0000000..7244c58 --- /dev/null +++ b/lib/libthr/thread/thr_mutexattr.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu <hsu@freebsd.org>. + * 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$ + */ + +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#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); +__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared); +__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared); +__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol); +__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol); +__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling); +__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling); + +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 >= PTHREAD_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 >= + PTHREAD_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); +} + +int +_pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, + int *pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + *pshared = PTHREAD_PROCESS_PRIVATE; + return (0); +} + +int +_pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (EINVAL); + + return (0); +} + +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_RR_PRIORITY; + } + return(ret); +} + +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); +} + diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c new file mode 100644 index 0000000..4fe392c --- /dev/null +++ b/lib/libthr/thread/thr_once.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2005, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" + +#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 _thr_once_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _thr_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(&_thr_once_lock); + once_control->state = ONCE_NEVER_DONE; + _pthread_mutex_unlock(&_thr_once_lock); + _pthread_cond_broadcast(&_thr_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(&_thr_once_lock); + while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS) + _pthread_cond_wait(&_thr_once_cv, &_thr_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(&_thr_once_lock); + _pthread_cleanup_push(once_cancel_handler, once_control); + init_routine(); + _pthread_cleanup_pop(0); + _pthread_mutex_lock(&_thr_once_lock); + once_control->state = ONCE_DONE; + wakeup = 1; + } + _pthread_mutex_unlock(&_thr_once_lock); + if (wakeup) + _pthread_cond_broadcast(&_thr_once_cv); + return (0); +} + +void +_thr_once_init() +{ + _thr_once_lock = PTHREAD_MUTEX_INITIALIZER; + _thr_once_cv = PTHREAD_COND_INITIALIZER; +} diff --git a/lib/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c new file mode 100644 index 0000000..7d32ae7 --- /dev/null +++ b/lib/libthr/thread/thr_printf.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org> + * 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$ + */ + +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> + +#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/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h new file mode 100644 index 0000000..0453864 --- /dev/null +++ b/lib/libthr/thread/thr_private.h @@ -0,0 +1,741 @@ +/* + * Copyright (C) 2005 Daniel M. Eischen <deischen@freebsd.org> + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice 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. + * + * $FreeBSD$ + */ + +#ifndef _THR_PRIVATE_H +#define _THR_PRIVATE_H + +/* + * Include files. + */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/cdefs.h> +#include <sys/queue.h> +#include <machine/atomic.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <unistd.h> +#include <ucontext.h> +#include <sys/thr.h> +#include <pthread.h> + +#ifndef __hidden +#define __hidden __attribute__((visibility("hidden"))) +#endif + +#include "pthread_md.h" +#include "thr_umtx.h" +#include "thread_db.h" + +typedef TAILQ_HEAD(pthreadlist, pthread) pthreadlist; +typedef TAILQ_HEAD(atfork_head, pthread_atfork) atfork_head; + +/* 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 _PTHREADS_INVARIANTS +#define THR_ASSERT(cond, msg) do { \ + if (__predict_false(!(cond))) \ + PANIC(msg); \ +} while (0) +#else +#define THR_ASSERT(cond, msg) +#endif + +#ifdef PIC +# define STATIC_LIB_REQUIRE(name) +#else +# define STATIC_LIB_REQUIRE(name) __asm (".globl " #name) +#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; + int 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; +}; + +/* + * 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; + int 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 *args); + 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 prio; + int suspend; +#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */ + int flags; + 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 (sizeof(void *) / 4 * 1024 * 1024) + +/* + * 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 (THR_STACK_DEFAULT * 2) + +/* + * Define priorities returned by kernel. + */ +#define THR_MIN_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min) +#define THR_MAX_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min) +#define THR_DEF_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_default) + +#define THR_MIN_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_min) +#define THR_MAX_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_max) +#define THR_DEF_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_default) + +/* XXX The SCHED_FIFO should have same priority range as SCHED_RR */ +#define THR_MIN_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO_1].pri_min) +#define THR_MAX_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_min) +#define THR_DEF_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_default) + +struct pthread_prio { + int pri_min; + int pri_max; + int pri_default; +}; + +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 +}; + +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 { + /* Kernel thread id. */ + long tid; +#define TID_TERMINATED 1 + + /* + * Lock for accesses to this thread structure. + */ + umtx_t lock; + + /* Internal condition variable cycle number. */ + umtx_t cycle; + + /* How many low level locks the thread held. */ + int locklevel; + + /* + * Set to non-zero when this thread has entered a critical + * region. We allow for recursive entries into critical regions. + */ + int critical_count; + + /* 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; + + /* 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; + + /* Queue of currently owned simple type mutexes. */ + TAILQ_HEAD(, pthread_mutex) 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; + + /* + * Magic value to help recognize a valid thread structure + * from an invalid one: + */ +#define THR_MAGIC ((u_int32_t) 0xd09ba115) + u_int32_t magic; + + /* Enable event reporting */ + int report_events; + + /* Event mask */ + int event_mask; + + /* Event */ + td_event_msg_t event_buf; +}; + +#define THR_IN_CRITICAL(thrd) \ + (((thrd)->locklevel > 0) || \ + ((thrd)->critical_count > 0)) + +#define THR_CRITICAL_ENTER(thrd) \ + (thrd)->critical_count++ + +#define THR_CRITICAL_LEAVE(thrd) \ + (thrd)->critical_count--; \ + _thr_ast(thrd); + +#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) + +#ifdef _PTHREADS_INVARIANTS +#define THR_ASSERT_LOCKLEVEL(thrd) \ +do { \ + if (__predict_false((thrd)->locklevel <= 0)) \ + _thr_assert_lock_level(); \ +} while (0) +#else +#define THR_ASSERT_LOCKLEVEL(thrd) +#endif + +#define THR_LOCK_RELEASE(thrd, lck) \ +do { \ + THR_ASSERT_LOCKLEVEL(thrd); \ + _thr_umtx_unlock((lck), (thrd)->tid); \ + (thrd)->locklevel--; \ + _thr_ast(thrd); \ +} 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 SHOULD_REPORT_EVENT(curthr, e) \ + (curthr->report_events && \ + (((curthr)->event_mask | _thread_event_mask ) & e) != 0) + +extern int __isthreaded; + +/* + * Global variables for the pthread kernel. + */ + +extern char *_usrstack __hidden; +extern struct pthread *_thr_initial __hidden; +extern int _thr_scope_system __hidden; + +/* For debugger */ +extern int _libthr_debug; +extern int _thread_event_mask; +extern struct pthread *_thread_last_event; + +/* List of all threads: */ +extern pthreadlist _thread_list; + +/* List of threads needing GC: */ +extern pthreadlist _thread_gc_list __hidden; + +extern int _thread_active_threads; +extern atfork_head _thr_atfork_list __hidden; +extern umtx_t _thr_atfork_lock __hidden; + +/* Default thread attributes: */ +extern struct pthread_attr _pthread_attr_default __hidden; + +/* Default mutex attributes: */ +extern struct pthread_mutex_attr _pthread_mutexattr_default __hidden; + +/* Default condition variable attributes: */ +extern struct pthread_cond_attr _pthread_condattr_default __hidden; + +extern struct pthread_prio _thr_priorities[] __hidden; + +extern pid_t _thr_pid __hidden; +extern size_t _thr_guard_default __hidden; +extern size_t _thr_stack_default __hidden; +extern size_t _thr_stack_initial __hidden; +extern int _thr_page_size __hidden; +/* Garbage thread count. */ +extern int _gc_count __hidden; + +extern umtx_t _mutex_static_lock __hidden; +extern umtx_t _cond_static_lock __hidden; +extern umtx_t _rwlock_static_lock __hidden; +extern umtx_t _keytable_lock __hidden; +extern umtx_t _thr_list_lock __hidden; +extern umtx_t _thr_event_lock __hidden; + +/* + * Function prototype definitions. + */ +__BEGIN_DECLS +int _thr_setthreaded(int) __hidden; +int _mutex_cv_lock(pthread_mutex_t *, int count) __hidden; +int _mutex_cv_unlock(pthread_mutex_t *, int *count) __hidden; +int _mutex_reinit(pthread_mutex_t *) __hidden; +void _mutex_fork(struct pthread *curthread) __hidden; +void _mutex_unlock_private(struct pthread *) __hidden; +void _libpthread_init(struct pthread *) __hidden; +struct pthread *_thr_alloc(struct pthread *) __hidden; +void _thread_exit(const char *, int, const char *) __hidden __dead2; +void _thr_exit_cleanup(void) __hidden; +int _thr_ref_add(struct pthread *, struct pthread *, int) __hidden; +void _thr_ref_delete(struct pthread *, struct pthread *) __hidden; +void _thr_ref_delete_unlocked(struct pthread *, struct pthread *) __hidden; +int _thr_find_thread(struct pthread *, struct pthread *, int) __hidden; +void _thr_rtld_init(void) __hidden; +void _thr_rtld_fini(void) __hidden; +int _thr_stack_alloc(struct pthread_attr *) __hidden; +void _thr_stack_free(struct pthread_attr *) __hidden; +void _thr_free(struct pthread *, struct pthread *) __hidden; +void _thr_gc(struct pthread *) __hidden; +void _thread_cleanupspecific(void) __hidden; +void _thread_dump_info(void) __hidden; +void _thread_printf(int, const char *, ...) __hidden; +void _thr_spinlock_init(void) __hidden; +int _thr_cancel_enter(struct pthread *) __hidden; +void _thr_cancel_leave(struct pthread *, int) __hidden; +void _thr_signal_block(struct pthread *) __hidden; +void _thr_signal_unblock(struct pthread *) __hidden; +void _thr_signal_init(void) __hidden; +void _thr_signal_deinit(void) __hidden; +int _thr_send_sig(struct pthread *, int sig) __hidden; +void _thr_list_init(void) __hidden; +void _thr_hash_add(struct pthread *) __hidden; +void _thr_hash_remove(struct pthread *) __hidden; +struct pthread *_thr_hash_find(struct pthread *) __hidden; +void _thr_link(struct pthread *, struct pthread *) __hidden; +void _thr_unlink(struct pthread *, struct pthread *) __hidden; +void _thr_suspend_check(struct pthread *) __hidden; +void _thr_assert_lock_level(void) __hidden __dead2; +void _thr_ast(struct pthread *) __hidden; +void _thr_once_init(void) __hidden; +void _thr_report_creation(struct pthread *curthread, + struct pthread *newthread) __hidden; +void _thr_report_death(struct pthread *curthread) __hidden; +void _thread_bp_create(void); +void _thread_bp_death(void); + +/* #include <fcntl.h> */ +#ifdef _SYS_FCNTL_H_ +int __sys_fcntl(int, int, ...); +int __sys_open(const char *, int, ...); +#endif + +/* #include <signal.h> */ +#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 *); +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 <time.h> */ +#ifdef _TIME_H_ +int __sys_nanosleep(const struct timespec *, struct timespec *); +#endif + +/* #include <unistd.h> */ +#ifdef _UNISTD_H_ +int __sys_close(int); +int __sys_fork(void); +pid_t __sys_getpid(void); +ssize_t __sys_read(int, void *, size_t); +ssize_t __sys_write(int, const void *, size_t); +void __sys_exit(int); +#endif + +static inline int +_thr_isthreaded(void) +{ + return (__isthreaded != 0); +} + +static inline int +_thr_is_inited(void) +{ + return (_thr_initial != NULL); +} + +static inline void +_thr_check_init(void) +{ + if (_thr_initial == NULL) + _libpthread_init(NULL); +} + +__END_DECLS + +#endif /* !_THR_PRIVATE_H */ diff --git a/lib/libthr/thread/thr_pspinlock.c b/lib/libthr/thread/thr_pspinlock.c new file mode 100644 index 0000000..ec3d68b --- /dev/null +++ b/lib/libthr/thread/thr_pspinlock.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 2003 David Xu <davidxu@freebsd.org> + * 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$ + */ + +#include "namespace.h" +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_resume_np.c b/lib/libthr/thread/thr_resume_np.c new file mode 100644 index 0000000..7fd3733 --- /dev/null +++ b/lib/libthr/thread/thr_resume_np.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#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); +} diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c new file mode 100644 index 0000000..827b962 --- /dev/null +++ b/lib/libthr/thread/thr_rtld.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2006, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + + /* + * A lockless rwlock for rtld. + */ +#include <sys/cdefs.h> +#include <stdlib.h> + +#include "rtld_lock.h" +#include "thr_private.h" + +#define CACHE_LINE_SIZE 64 +#define WAFLAG 0x1 +#define RC_INCR 0x2 + +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 *); + +struct rtld_lock { + volatile int lock; + volatile int rd_waiters; + volatile int wr_waiters; + volatile umtx_t rd_cv; + volatile umtx_t wr_cv; + void *base; +}; + +static void * +_thr_rtld_lock_create(void) +{ + void *base; + char *p; + uintptr_t r; + struct rtld_lock *l; + + THR_ASSERT(sizeof(struct rtld_lock) <= CACHE_LINE_SIZE, + "rtld_lock too large"); + base = calloc(1, CACHE_LINE_SIZE); + p = (char *)base; + if ((uintptr_t)p % CACHE_LINE_SIZE != 0) { + free(base); + base = calloc(1, 2 * CACHE_LINE_SIZE); + p = (char *)base; + if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0) + p += CACHE_LINE_SIZE - r; + } + l = (struct rtld_lock *)p; + l->base = base; + return (l); +} + +static void +_thr_rtld_lock_destroy(void *lock) +{ + struct rtld_lock *l = (struct rtld_lock *)lock; + free(l->base); +} + +static void +_thr_rtld_rlock_acquire(void *lock) +{ + struct pthread *curthread; + struct rtld_lock *l; + umtx_t v; + + curthread = _get_curthread(); + l = (struct rtld_lock *)lock; + + THR_CRITICAL_ENTER(curthread); + atomic_add_acq_int(&l->lock, RC_INCR); + if (!(l->lock & WAFLAG)) + return; + v = l->rd_cv; + atomic_add_int(&l->rd_waiters, 1); + while (l->lock & WAFLAG) { + _thr_umtx_wait(&l->rd_cv, v, NULL); + v = l->rd_cv; + } + atomic_add_int(&l->rd_waiters, -1); +} + +static void +_thr_rtld_wlock_acquire(void *lock) +{ + struct pthread *curthread; + struct rtld_lock *l; + umtx_t v; + + curthread = _get_curthread(); + l = (struct rtld_lock *)lock; + + _thr_signal_block(curthread); + for (;;) { + if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) + return; + v = l->wr_cv; + atomic_add_int(&l->wr_waiters, 1); + while (l->lock != 0) { + _thr_umtx_wait(&l->wr_cv, v, NULL); + v = l->wr_cv; + } + atomic_add_int(&l->wr_waiters, -1); + } +} + +static void +_thr_rtld_lock_release(void *lock) +{ + struct pthread *curthread; + struct rtld_lock *l; + + curthread = _get_curthread(); + l = (struct rtld_lock *)lock; + + if ((l->lock & WAFLAG) == 0) { + atomic_add_rel_int(&l->lock, -RC_INCR); + if (l->lock == 0 && l->wr_waiters) { + atomic_add_long(&l->wr_cv, 1); + _thr_umtx_wake(&l->wr_cv, l->wr_waiters); + } + THR_CRITICAL_LEAVE(curthread); + } else { + atomic_add_rel_int(&l->lock, -WAFLAG); + if (l->lock == 0 && l->wr_waiters) { + atomic_add_long(&l->wr_cv, 1); + _thr_umtx_wake(&l->wr_cv, l->wr_waiters); + } else if (l->rd_waiters) { + atomic_add_long(&l->rd_cv, 1); + _thr_umtx_wake(&l->rd_cv, l->rd_waiters); + } + _thr_signal_unblock(curthread); + } +} + +static int +_thr_rtld_set_flag(int mask __unused) +{ + /* + * The caller's code in rtld-elf is broken, it is not signal safe, + * just return zero to fool it. + */ + return (0); +} + +static int +_thr_rtld_clr_flag(int mask __unused) +{ + return (0); +} + +void +_thr_rtld_init(void) +{ + struct RtldLockInfo li; + struct pthread *curthread; + umtx_t dummy; + + curthread = _get_curthread(); + + /* force to resolve _umtx_op PLT */ + _umtx_op((struct umtx *)&dummy, UMTX_OP_WAKE, 1, 0, 0); + + 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; + + /* mask signals, also force to resolve __sys_sigprocmask PLT */ + _thr_signal_block(curthread); + _rtld_thread_init(&li); + _thr_signal_unblock(curthread); +} + +void +_thr_rtld_fini(void) +{ + struct pthread *curthread; + + curthread = _get_curthread(); + _thr_signal_block(curthread); + _rtld_thread_init(NULL); + _thr_signal_unblock(curthread); +} diff --git a/lib/libthr/thread/thr_rwlock.c b/lib/libthr/thread/thr_rwlock.c new file mode 100644 index 0000000..81d1459 --- /dev/null +++ b/lib/libthr/thread/thr_rwlock.c @@ -0,0 +1,417 @@ +/*- + * 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$ + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" +#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 __unused) +{ + 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 = _pthread_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) { + _pthread_mutex_unlock(&prwlock->lock); + return (EAGAIN); + } + + 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 = _pthread_cond_wait(&prwlock->read_signal, + &prwlock->lock); + if (ret != 0) { + /* can't do a whole lot if this fails */ + _pthread_mutex_unlock(&prwlock->lock); + return (ret); + } + } + } + + 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. + */ + _pthread_mutex_unlock(&prwlock->lock); + + return (ret); +} + +int +_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + return (rwlock_rdlock_common(rwlock, NULL)); +} + +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); + + 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 = _get_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 = _pthread_mutex_lock(&prwlock->lock)) != 0) + return (ret); + + if (prwlock->state > 0) { + curthread->rdlock_count--; + prwlock->state--; + if (prwlock->state == 0 && prwlock->blocked_writers) + ret = _pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = _pthread_cond_signal(&prwlock->write_signal); + else + ret = _pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + _pthread_mutex_unlock(&prwlock->lock); + + return (ret); +} + +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 = _pthread_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 = _pthread_cond_wait(&prwlock->write_signal, + &prwlock->lock); + if (ret != 0) { + prwlock->blocked_writers--; + _pthread_mutex_unlock(&prwlock->lock); + return (ret); + } + + prwlock->blocked_writers--; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + _pthread_mutex_unlock(&prwlock->lock); + + return (ret); +} + +int +_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + return (rwlock_wrlock_common (rwlock, NULL)); +} + +int +_pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + return (rwlock_wrlock_common (rwlock, abstime)); +} diff --git a/lib/libthr/thread/thr_rwlockattr.c b/lib/libthr/thread/thr_rwlockattr.c new file mode 100644 index 0000000..b47d167 --- /dev/null +++ b/lib/libthr/thread/thr_rwlockattr.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1998 Alex Nash + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "namespace.h" +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_self.c b/lib/libthr/thread/thr_self.c new file mode 100644 index 0000000..85fb54e --- /dev/null +++ b/lib/libthr/thread/thr_self.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_sem.c b/lib/libthr/thread/thr_sem.c new file mode 100644 index 0000000..88a3cbd --- /dev/null +++ b/lib/libthr/thread/thr_sem.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2005 David Xu <davidxu@freebsd.org>. + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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$ + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdlib.h> +#include <time.h> +#include <_semaphore.h> +#include "un-namespace.h" + +#include "thr_private.h" + + +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_getvalue, sem_getvalue); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_wait, sem_wait); +__weak_reference(_sem_timedwait, sem_timedwait); +__weak_reference(_sem_post, sem_post); + + +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, semid_t semid, int system_sem) +{ + 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); + } + _thr_umtx_init((umtx_t *)&sem->lock); + /* + * Fortunatly count and nwaiters are adjacency, so we can + * use umtx_wait to wait on it, umtx_wait needs an address + * can be accessed as a long interger. + */ + sem->count = (u_int32_t)value; + sem->nwaiters = 0; + sem->magic = SEM_MAGIC; + sem->semid = semid; + sem->syssem = system_sem; + return (sem); +} + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + semid_t semid; + + semid = (semid_t)SEM_USER; + if ((pshared != 0) && (ksem_init(&semid, value) != 0)) + return (-1); + + (*sem) = sem_alloc(value, semid, pshared); + if ((*sem) == NULL) { + if (pshared != 0) + ksem_destroy(semid); + return (-1); + } + return (0); +} + +int +_sem_destroy(sem_t *sem) +{ + int retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + /* + * If this is a system semaphore let the kernel track it otherwise + * make sure there are no waiters. + */ + if ((*sem)->syssem != 0) + retval = ksem_destroy((*sem)->semid); + else { + retval = 0; + (*sem)->magic = 0; + } + if (retval == 0) + free(*sem); + return (retval); +} + +int +_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + int retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + retval = ksem_getvalue((*sem)->semid, sval); + else { + *sval = (int)(*sem)->count; + retval = 0; + } + return (retval); +} + +int +_sem_trywait(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + return (ksem_trywait((*sem)->semid)); + + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_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(); + if ((*sem)->syssem != 0) { + oldcancel = _thr_cancel_enter(curthread); + retval = ksem_wait((*sem)->semid); + _thr_cancel_leave(curthread, oldcancel); + return (retval); + } + + _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((umtx_t *)&(*sem)->count, 0, NULL); + _thr_cancel_leave(curthread, oldcancel); + } while (retval == 0); + errno = retval; + return (-1); +} + +int +_sem_timedwait(sem_t * __restrict sem, + const 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(); + if ((*sem)->syssem != 0) { + oldcancel = _thr_cancel_enter(curthread); + retval = ksem_timedwait((*sem)->semid, abstime); + _thr_cancel_leave(curthread, oldcancel); + return (retval); + } + + /* + * 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((umtx_t *)&(*sem)->count, 0, &ts2); + _thr_cancel_leave(curthread, oldcancel); + } while (retval == 0); + errno = retval; + return (-1); +} + +int +_sem_post(sem_t *sem) +{ + int val, retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + return (ksem_post((*sem)->semid)); + + /* + * 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)); + retval = _thr_umtx_wake((umtx_t *)&(*sem)->count, val + 1); + if (retval > 0) + retval = 0; + return (retval); +} diff --git a/lib/libthr/thread/thr_seterrno.c b/lib/libthr/thread/thr_seterrno.c new file mode 100644 index 0000000..f481799 --- /dev/null +++ b/lib/libthr/thread/thr_seterrno.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <pthread.h> + +#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/libthr/thread/thr_setprio.c b/lib/libthr/thread/thr_setprio.c new file mode 100644 index 0000000..bb9a9bf --- /dev/null +++ b/lib/libthr/thread/thr_setprio.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include "un-namespace.h" + +#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/libthr/thread/thr_setschedparam.c b/lib/libthr/thread/thr_setschedparam.c new file mode 100644 index 0000000..eba5017 --- /dev/null +++ b/lib/libthr/thread/thr_setschedparam.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel 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$ + */ + +#include "namespace.h" +#include <sys/param.h> +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +__weak_reference(_pthread_setschedparam, pthread_setschedparam); + +/* + * Set a thread's scheduling parameters, this should be done + * in kernel, doing it in userland is no-op. + */ +int +_pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) { + ret = EINVAL; + } else if (param->sched_priority < _thr_priorities[policy-1].pri_min || + param->sched_priority > _thr_priorities[policy-1].pri_max) { + ret = ENOTSUP; + } 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); + } + + /* Set the scheduling policy: */ + pthread->attr.sched_policy = policy; + + if (param->sched_priority == pthread->base_priority) + /* + * There is nothing to do; unlock the threads + * scheduling queue. + */ + THR_THREAD_UNLOCK(curthread, pthread); + else { + pthread->base_priority = param->sched_priority; + + /* Recalculate the active priority: */ + pthread->active_priority = MAX(pthread->base_priority, + pthread->inherited_priority); + + THR_THREAD_UNLOCK(curthread, pthread); + } + _thr_ref_delete(curthread, pthread); + } + return (ret); +} diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c new file mode 100644 index 0000000..865fb72 --- /dev/null +++ b/lib/libthr/thread/thr_sig.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2005, David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +/* #define DEBUG_SIGNAL */ +#ifdef DEBUG_SIGNAL +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +int __sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec * timeout); +int __sigwaitinfo(const sigset_t *set, siginfo_t *info); +int __sigwait(const sigset_t *set, int *sig); + +static void +sigcancel_handler(int sig __unused, + siginfo_t *info __unused, ucontext_t *ucp __unused) +{ + struct pthread *curthread = _get_curthread(); + + _thr_ast(curthread); +} + +void +_thr_ast(struct pthread *curthread) +{ + if (!THR_IN_CRITICAL(curthread)) { + if (__predict_false( + SHOULD_ASYNC_CANCEL(curthread->cancelflags))) + _pthread_testcancel(); + if (__predict_false((curthread->flags & + (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) + == THR_FLAGS_NEED_SUSPEND)) + _thr_suspend_check(curthread); + } +} + +void +_thr_suspend_check(struct pthread *curthread) +{ + umtx_t cycle; + int err; + + err = errno; + /* + * Blocks SIGCANCEL which other threads must send. + */ + _thr_signal_block(curthread); + + /* + * Increase critical_count, here we don't use THR_LOCK/UNLOCK + * because we are leaf code, we don't want to recursively call + * ourself. + */ + curthread->critical_count++; + THR_UMTX_LOCK(curthread, &(curthread)->lock); + while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | + THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { + curthread->cycle++; + cycle = curthread->cycle; + + /* Wake the thread suspending us. */ + _thr_umtx_wake(&curthread->cycle, INT_MAX); + + /* + * if we are from pthread_exit, we don't want to + * suspend, just go and die. + */ + if (curthread->state == PS_DEAD) + break; + curthread->flags |= THR_FLAGS_SUSPENDED; + THR_UMTX_UNLOCK(curthread, &(curthread)->lock); + _thr_umtx_wait(&curthread->cycle, cycle, NULL); + THR_UMTX_LOCK(curthread, &(curthread)->lock); + curthread->flags &= ~THR_FLAGS_SUSPENDED; + } + THR_UMTX_UNLOCK(curthread, &(curthread)->lock); + curthread->critical_count--; + + /* + * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and + * a new signal frame will nest us, this seems a problem because + * stack will grow and overflow, but because kernel will automatically + * mask the SIGCANCEL when delivering the signal, so we at most only + * have one nesting signal frame, this should be fine. + */ + _thr_signal_unblock(curthread); + errno = err; +} + +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); +} + +__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); +} diff --git a/lib/libthr/thread/thr_sigmask.c b/lib/libthr/thread/thr_sigmask.c new file mode 100644 index 0000000..2024cc0 --- /dev/null +++ b/lib/libthr/thread/thr_sigmask.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <errno.h> +#include <signal.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_sigmask, pthread_sigmask); + +extern int +_sigprocmask(int how, const sigset_t *set, sigset_t *oset); + +int +_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + /* use our overridden verion of _sigprocmask */ + if (_sigprocmask(how, set, oset)) + return (errno); + return (0); +} diff --git a/lib/libthr/thread/thr_single_np.c b/lib/libthr/thread/thr_single_np.c new file mode 100644 index 0000000..c74fc55 --- /dev/null +++ b/lib/libthr/thread/thr_single_np.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +__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/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c new file mode 100644 index 0000000..cd4d49f --- /dev/null +++ b/lib/libthr/thread/thr_spec.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include "un-namespace.h" + +#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 *); + const 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 = 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(__DECONST(void *, 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; + const 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 = 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 (__DECONST(void *, data)); +} diff --git a/lib/libthr/thread/thr_spinlock.c b/lib/libthr/thread/thr_spinlock.c new file mode 100644 index 0000000..b9d2279 --- /dev/null +++ b/lib/libthr/thread/thr_spinlock.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <sys/types.h> +#include <pthread.h> +#include <libc_private.h> +#include <spinlock.h> + +#include "thr_private.h" + +#define MAX_SPINLOCKS 72 + +/* + * 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(), (volatile 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(), (volatile umtx_t *)&lck->access_lock); +} + +void +_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused) +{ + _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((volatile umtx_t *) + &extra[i].owner->access_lock); + } else { + initialized = 1; + } +} diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c new file mode 100644 index 0000000..9376086 --- /dev/null +++ b/lib/libthr/thread/thr_stack.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org> + * Copyright (c) 2000-2001 Jason Evans <jasone@freebsd.org> + * 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$ + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/queue.h> +#include <stdlib.h> +#include <pthread.h> + +#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 - _thr_stack_default | top of 2nd thread stack + * | | + * | | + * | | + * | | + * | stack 2 | + * +-----------------------------------+ <-- start of 2nd thread stack + * | | + * | Red Zone | red zone for 1st thread + * | | + * +-----------------------------------+ + * | stack 1 - _thr_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 - _thr_stack_initial | top of main thread stack + * | | ^ + * | | | + * | | | + * | | | stack growth + * | | + * +-----------------------------------+ <-- start of main thread stack + * (USRSTACK) + * high memory + * + */ +static char *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 = (struct stack *) + ((char *)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/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c new file mode 100644 index 0000000..ec34029 --- /dev/null +++ b/lib/libthr/thread/thr_suspend_np.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#include "thr_private.h" + +static int suspend_common(struct pthread *, struct pthread *, + int); + +__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(curthread, thread, 1); + /* 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; + int ret; + + THREAD_LIST_LOCK(curthread); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != curthread) { + THR_THREAD_LOCK(curthread, thread); + if (thread->state != PS_DEAD && + !(thread->flags & THR_FLAGS_SUSPENDED)) + thread->flags |= THR_FLAGS_NEED_SUSPEND; + THR_THREAD_UNLOCK(curthread, thread); + } + } + thr_kill(-1, SIGCANCEL); + +restart: + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != curthread) { + /* First try to suspend the thread without waiting */ + THR_THREAD_LOCK(curthread, thread); + ret = suspend_common(curthread, thread, 0); + if (ret == 0) { + /* Can not suspend, try to wait */ + thread->refcount++; + THREAD_LIST_UNLOCK(curthread); + suspend_common(curthread, thread, 1); + THR_THREAD_UNLOCK(curthread, thread); + THREAD_LIST_LOCK(curthread); + _thr_ref_delete_unlocked(curthread, thread); + /* + * Because we were blocked, things may have + * been changed, we have to restart the + * process. + */ + goto restart; + } + THR_THREAD_UNLOCK(curthread, thread); + } + } + + THREAD_LIST_UNLOCK(curthread); +} + +static int +suspend_common(struct pthread *curthread, struct pthread *thread, + int waitok) +{ + umtx_t tmp; + + while (thread->state != PS_DEAD && + !(thread->flags & THR_FLAGS_SUSPENDED)) { + thread->flags |= THR_FLAGS_NEED_SUSPEND; + tmp = thread->cycle; + THR_THREAD_UNLOCK(curthread, thread); + _thr_send_sig(thread, SIGCANCEL); + if (waitok) { + _thr_umtx_wait(&thread->cycle, tmp, NULL); + THR_THREAD_LOCK(curthread, thread); + } else { + THR_THREAD_LOCK(curthread, thread); + return (0); + } + } + + return (1); +} diff --git a/lib/libthr/thread/thr_switch_np.c b/lib/libthr/thread/thr_switch_np.c new file mode 100644 index 0000000..f6ffb07 --- /dev/null +++ b/lib/libthr/thread/thr_switch_np.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Daniel 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$ + */ + +#include "namespace.h" +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include "un-namespace.h" + +#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 __unused) +{ + return (ENOTSUP); +} + +int +_pthread_switch_delete_np(pthread_switch_routine_t routine __unused) +{ + return (ENOTSUP); +} diff --git a/lib/libthr/thread/thr_symbols.c b/lib/libthr/thread/thr_symbols.c new file mode 100644 index 0000000..ca6606a --- /dev/null +++ b/lib/libthr/thread/thr_symbols.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004 David Xu <davidxu@freebsd.org> + * 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 <sys/types.h> +#include <stddef.h> +#include <pthread.h> +#include <rtld.h> + +#include "thr_private.h" + +/* A collection of symbols needed by debugger */ + +/* int _libthr_debug */ +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_linkmap = offsetof(Obj_Entry, linkmap); +int _thread_off_tlsindex = offsetof(Obj_Entry, tlsindex); +int _thread_off_report_events = offsetof(struct pthread, report_events); +int _thread_off_event_mask = offsetof(struct pthread, event_mask); +int _thread_off_event_buf = offsetof(struct pthread, event_buf); +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; diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c new file mode 100644 index 0000000..a36849a --- /dev/null +++ b/lib/libthr/thread/thr_syscalls.c @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2005 David Xu <davidxu@freebsd.org>. + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>. + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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$ + */ + +/* + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/select.h> +#include <sys/signalvar.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <aio.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "thr_private.h" + +extern int __creat(const char *, mode_t); +extern int __pause(void); +extern int __pselect(int, fd_set *, fd_set *, fd_set *, + const struct timespec *, const sigset_t *); +extern unsigned __sleep(unsigned int); +extern int __system(const char *); +extern int __tcdrain(int); +extern int __usleep(useconds_t); +extern pid_t __wait(int *); +extern pid_t __waitpid(pid_t, int *, int); +extern int __sys_aio_suspend(const struct aiocb * const[], int, + const struct timespec *); +extern int __sys_accept(int, struct sockaddr *, socklen_t *); +extern int __sys_connect(int, const struct sockaddr *, socklen_t); +extern int __sys_fsync(int); +extern int __sys_msync(void *, size_t, int); +extern int __sys_poll(struct pollfd *, unsigned, int); +extern ssize_t __sys_recv(int, void *, size_t, int); +extern ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); +extern ssize_t __sys_recvmsg(int, struct msghdr *, int); +extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, + off_t *, int); +extern ssize_t __sys_sendmsg(int, const struct msghdr *, int); +extern ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); +extern ssize_t __sys_readv(int, const struct iovec *, int); +extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *); +extern ssize_t __sys_writev(int, const struct iovec *, int); + +int ___creat(const char *, mode_t); +int __accept(int, struct sockaddr *, socklen_t *); +int __close(int); +int __connect(int, const struct sockaddr *, socklen_t); +int __fcntl(int, int,...); +int __fsync(int); +int __msync(void *, size_t, int); +int __nanosleep(const struct timespec *, struct timespec *); +int __open(const char *, int,...); +int __poll(struct pollfd *, unsigned int, int); +ssize_t __read(int, void *buf, size_t); +ssize_t __readv(int, const struct iovec *, int); +ssize_t __recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *); +ssize_t __recvmsg(int, struct msghdr *, int); +int __select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +ssize_t __sendmsg(int, const struct msghdr *, int); +ssize_t __sendto(int, const void *, size_t, int, + const struct sockaddr *, socklen_t); +pid_t __wait4(pid_t, int *, int, struct rusage *); +ssize_t __write(int, const void *, size_t); +ssize_t __writev(int, const struct iovec *, int); +int _aio_suspend(const struct aiocb * const iocbs[], int, + const struct timespec *); +int _pause(void); +int _pselect(int, fd_set *, fd_set *, fd_set *, + const struct timespec *, const sigset_t *); +int _raise(int); +unsigned _sleep(unsigned); +int _system(const char *); +int _tcdrain(int); +int _vfork(void); +pid_t _wait(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; + + 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; + + 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; +} + +__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); +} + +__weak_reference(_raise, raise); + +int +_raise(int sig) +{ + int ret; + + if (!_thr_isthreaded()) + ret = kill(getpid(), sig); + else + ret = _thr_send_sig(_get_curthread(), sig); + 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); +} + +__weak_reference(_sleep, sleep); + +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(_usleep, usleep); + +int +_usleep(useconds_t useconds) +{ + struct pthread *curthread = _get_curthread(); + int oldcancel; + int ret; + + oldcancel = _thr_cancel_enter(curthread); + ret = __usleep(useconds); + _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/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c new file mode 100644 index 0000000..cba6942 --- /dev/null +++ b/lib/libthr/thread/thr_umtx.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * 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. + * + * $FreeBSD$ + * + */ + +#include "thr_private.h" +#include "thr_umtx.h" + +int +__thr_umtx_lock(volatile umtx_t *mtx, long id) +{ + while (_umtx_op(__DEVOLATILE(struct umtx *, mtx), + UMTX_OP_LOCK, id, 0, 0)) + ; + return (0); +} + +int +__thr_umtx_timedlock(volatile umtx_t *mtx, long id, + const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) + return (ETIMEDOUT); + if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_LOCK, id, 0, + __DECONST(void *, timeout)) == 0) + return (0); + return (errno); +} + +int +__thr_umtx_unlock(volatile umtx_t *mtx, long id) +{ + if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_UNLOCK, + id, 0, 0) == 0) + return (0); + return (errno); +} + +int +_thr_umtx_wait(volatile umtx_t *mtx, long id, const struct timespec *timeout) +{ + if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && + timeout->tv_nsec <= 0))) + return (ETIMEDOUT); + if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAIT, id, 0, + __DECONST(void*, timeout)) == 0) + return (0); + return (errno); +} + +int +_thr_umtx_wake(volatile umtx_t *mtx, int nr_wakeup) +{ + if (_umtx_op(__DEVOLATILE(struct umtx *, mtx), UMTX_OP_WAKE, + nr_wakeup, 0, 0) == 0) + return (0); + return (errno); +} diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h new file mode 100644 index 0000000..1fbf534 --- /dev/null +++ b/lib/libthr/thread/thr_umtx.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2005 David Xu <davidxu@freebsd.org> + * 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$ + */ + +#ifndef _THR_FBSD_UMTX_H_ +#define _THR_FBSD_UMTX_H_ + +#include <sys/umtx.h> + +typedef long umtx_t; + +int __thr_umtx_lock(volatile umtx_t *mtx, long id) __hidden; +int __thr_umtx_timedlock(volatile umtx_t *mtx, long id, + const struct timespec *timeout) __hidden; +int __thr_umtx_unlock(volatile umtx_t *mtx, long id) __hidden; + +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_ptr((volatile uintptr_t *)mtx, + (uintptr_t)UMTX_UNOWNED, (uintptr_t)id)) + return (0); + return (EBUSY); +} + +static inline int +_thr_umtx_lock(volatile umtx_t *mtx, long id) +{ + if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx, + (uintptr_t)UMTX_UNOWNED, (uintptr_t)id)) + return (0); + return (__thr_umtx_lock(mtx, id)); +} + +static inline int +_thr_umtx_timedlock(volatile umtx_t *mtx, long id, + const struct timespec *timeout) +{ + if (atomic_cmpset_acq_ptr((volatile uintptr_t *)mtx, + (uintptr_t)UMTX_UNOWNED, (uintptr_t)id)) + return (0); + return (__thr_umtx_timedlock(mtx, id, timeout)); +} + +static inline int +_thr_umtx_unlock(volatile umtx_t *mtx, long id) +{ + if (atomic_cmpset_rel_ptr((volatile uintptr_t *)mtx, + (uintptr_t)id, (uintptr_t)UMTX_UNOWNED)) + return (0); + return __thr_umtx_unlock(mtx, id); +} + +int _thr_umtx_wait(volatile umtx_t *mtx, umtx_t exp, + const struct timespec *timeout) __hidden; +int _thr_umtx_wake(volatile umtx_t *mtx, int count) __hidden; +#endif diff --git a/lib/libthr/thread/thr_yield.c b/lib/libthr/thread/thr_yield.c new file mode 100644 index 0000000..300504b --- /dev/null +++ b/lib/libthr/thread/thr_yield.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 "namespace.h" +#include <pthread.h> +#include <sched.h> +#include "un-namespace.h" + +__weak_reference(_pthread_yield, pthread_yield); + +/* Draft 4 yield */ +void +_pthread_yield(void) +{ + + sched_yield(); +} |