diff options
Diffstat (limited to 'lib')
49 files changed, 7686 insertions, 0 deletions
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile new file mode 100644 index 0000000..7bd4c63 --- /dev/null +++ b/lib/libthr/Makefile @@ -0,0 +1,26 @@ +# $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. +LIB=thr +SHLIB_MAJOR= 1 +DEBUG_FLAGS=-g +CFLAGS+=-DPTHREAD_KERNEL -D_THREAD_SAFE +CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}/thread \ + -I${.CURDIR}/../../include + +# enable extra internal consistancy checks +CFLAGS+=-D_PTHREADS_INVARIANTS + +AINC= -I${.CURDIR}/../libc/${MACHINE_ARCH} -I${.CURDIR}/thread +PRECIOUSLIB= yes + +.include "${.CURDIR}/thread/Makefile.inc" +.include "${.CURDIR}/sys/Makefile.inc" + +.include <bsd.lib.mk> diff --git a/lib/libthr/arch/i386/i386/_curthread.S b/lib/libthr/arch/i386/i386/_curthread.S new file mode 100644 index 0000000..7e8dbd9 --- /dev/null +++ b/lib/libthr/arch/i386/i386/_curthread.S @@ -0,0 +1,17 @@ +# $FreeBSD$ + +#include <machine/asm.h> + +ENTRY(_get_curthread) + cmpl $0, _thread_initial + je nothreads + movl %gs:0, %eax + ret +nothreads: + xor %eax, %eax + ret + +ENTRY(_set_gs) + movl 4(%esp), %eax + movl %eax, %gs + ret diff --git a/lib/libthr/arch/i386/i386/_setcurthread.c b/lib/libthr/arch/i386/i386/_setcurthread.c new file mode 100644 index 0000000..2e8150f --- /dev/null +++ b/lib/libthr/arch/i386/i386/_setcurthread.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2003, Jeffrey Roberson <jeff@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 <stdio.h> + +#include <machine/sysarch.h> +#include <machine/segments.h> + +#define MAXTHR 128 + +#define LDT_INDEX(x) (((long)(x) - (long)ldt_entries) / sizeof(ldt_entries[0])) + +void **ldt_free = NULL; +static int ldt_inited = 0; +void *ldt_entries[MAXTHR]; + +static void ldt_init(void); + +static void +ldt_init(void) +{ + int i; + + ldt_free = &ldt_entries[NLDT]; + + for (i = 0; i < MAXTHR; i++) + ldt_entries[i] = (void *)&ldt_entries[i + 1]; + + ldt_entries[MAXTHR] = NULL; + + ldt_inited = 1; +} + +void +_retire_thread(void *entry) +{ + *(void **)entry = *ldt_free; + ldt_free = entry; +} + +void * +_set_curthread(void *thr) +{ + union descriptor desc; + void **ldt_entry; + int ldt_index; + int error; + + if (ldt_inited == NULL) + ldt_init(); + + if (ldt_free == NULL) + abort(); + + /* + * Pull one off of the free list and update the free list pointer. + */ + ldt_entry = ldt_free; + ldt_free = (void **)*ldt_entry; + + /* + * Cache the address of the thread structure here. This is + * what the gs register will point to. + */ + *ldt_entry = thr; + ldt_index = LDT_INDEX(ldt_entry); + + bzero(&desc, sizeof(desc)); + + /* + * Set up the descriptor to point into the ldt table which contains + * only a pointer to the thread. + */ + desc.sd.sd_lolimit = sizeof(*ldt_entry); + desc.sd.sd_lobase = (unsigned int)ldt_entry & 0xFFFFFF; + desc.sd.sd_type = SDT_MEMRO; + desc.sd.sd_dpl = SEL_UPL; + desc.sd.sd_p = 1; + desc.sd.sd_hilimit = 0; + desc.sd.sd_xx = 0; + desc.sd.sd_def32 = 1; + desc.sd.sd_gran = 0; + desc.sd.sd_hibase = (unsigned int)ldt_entry >> 24; + + error = i386_set_ldt(ldt_index, &desc, 1); + if (error == -1) + abort(); + + /* + * Set up our gs with the index into the ldt for this entry. + */ + _set_gs(LSEL(ldt_index, SEL_UPL)); + + return (ldt_entry); +} diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc new file mode 100644 index 0000000..a8c9177 --- /dev/null +++ b/lib/libthr/thread/Makefile.inc @@ -0,0 +1,50 @@ +# $FreeBSD$ + +# thr sources +.PATH: ${.CURDIR}/thread + +SRCS+= \ + thr_attr.c \ + thr_autoinit.c \ + thr_cancel.c \ + thr_clean.c \ + thr_cond.c \ + thr_condattr_destroy.c \ + thr_condattr_init.c \ + thr_create.c \ + thr_detach.c \ + thr_equal.c \ + thr_exit.c \ + thr_find_thread.c \ + thr_gc.c \ + thr_getprio.c \ + thr_getschedparam.c \ + thr_info.c \ + thr_init.c \ + thr_join.c \ + thr_kern.c \ + thr_main_np.c \ + thr_mattr_init.c \ + thr_mattr_kind_np.c \ + thr_multi_np.c \ + thr_mutex.c \ + thr_mutex_prioceiling.c \ + thr_mutex_protocol.c \ + thr_mutexattr_destroy.c \ + thr_once.c \ + thr_printf.c \ + thr_resume_np.c \ + thr_rwlock.c \ + thr_rwlockattr.c \ + thr_self.c \ + thr_sem.c \ + thr_seterrno.c \ + thr_setprio.c \ + thr_setschedparam.c \ + thr_sig.c \ + thr_spec.c \ + thr_spinlock.c \ + thr_stack.c \ + thr_suspend_np.c \ + thr_syscalls.c \ + thr_yield.c diff --git a/lib/libthr/thread/thr_attr.c b/lib/libthr/thread/thr_attr.c new file mode 100644 index 0000000..1b25b10 --- /dev/null +++ b/lib/libthr/thread/thr_attr.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 1995-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$ + */ + +/* + * 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> + * Copyright (c) 2003 Jeff Roberson <jeff@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. + */ + +/* XXXTHR I rewrote the entire file, can we lose some of the copyrights? */ + +#include <sys/param.h> + +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include <stdlib.h> +#include <string.h> + +#include "thr_private.h" + +__weak_reference(_pthread_attr_init, pthread_attr_init); + +int +_pthread_attr_init(pthread_attr_t *attr) +{ + pthread_attr_t pattr; + + if ((pattr = (pthread_attr_t) + malloc(sizeof(struct pthread_attr))) == NULL) + return (ENOMEM); + + memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr)); + *attr = pattr; + + return (0); +} + +__weak_reference(_pthread_attr_destroy, pthread_attr_destroy); + +int +_pthread_attr_destroy(pthread_attr_t *attr) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + free(*attr); + *attr = NULL; + + return (0); +} + +__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np); + +int +_pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) +{ + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + return (-1); + } + (*attr)->suspend = PTHREAD_CREATE_SUSPENDED; + + return (0); +} + +__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate); + +int +_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + if (attr == NULL || *attr == NULL || + (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE)) + return (EINVAL); + + if (detachstate == PTHREAD_CREATE_DETACHED) + (*attr)->flags |= PTHREAD_DETACHED; + else + (*attr)->flags &= ~PTHREAD_DETACHED; + + return (0); +} + + +__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize); + +int +_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + (*attr)->guardsize_attr = roundup(guardsize, _pthread_page_size); + + return (0); +} + +__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched); + +int +_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + (*attr)->sched_inherit = sched_inherit; + + return (0); +} + +__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam); + +int +_pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *param) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + if (param == NULL) + return (ENOTSUP); + + if (param->sched_priority < PTHREAD_MIN_PRIORITY || + param->sched_priority > PTHREAD_MAX_PRIORITY) + 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) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + if (policy < SCHED_FIFO || policy > SCHED_RR) + return (ENOTSUP); + + (*attr)->sched_policy = policy; + + return (0); +} + +__weak_reference(_pthread_attr_setscope, pthread_attr_setscope); + +int +_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + if (contentionscope != PTHREAD_SCOPE_PROCESS || + contentionscope == PTHREAD_SCOPE_SYSTEM) + /* We don't support PTHREAD_SCOPE_SYSTEM. */ + return (ENOTSUP); + + (*attr)->flags |= contentionscope; + + return (0); +} + +__weak_reference(_pthread_attr_setstack, pthread_attr_setstack); + +int +_pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, + size_t stacksize) +{ + if (attr == NULL || *attr == NULL || stackaddr == NULL + || stacksize < PTHREAD_STACK_MIN) + return (EINVAL); + + (*attr)->stackaddr_attr = stackaddr; + (*attr)->stacksize_attr = stacksize; + + return (0); +} + +__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr); + +int +_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + return (EINVAL); + + (*attr)->stackaddr_attr = stackaddr; + + return (0); +} + +__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize); + +int +_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) + return (EINVAL); + + (*attr)->stacksize_attr = stacksize; + + return (0); +} + +__weak_reference(_pthread_attr_get_np, pthread_attr_get_np); + +int +_pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst) +{ + int ret; + + if (pid == NULL || dst == NULL || *dst == NULL) + return (EINVAL); + + if ((ret = _find_thread(pid)) != 0) + return (ret); + + memcpy(*dst, &pid->attr, sizeof(struct pthread_attr)); + + /* + * Special case, if stack address was not provided by caller + * of pthread_create(), then return address allocated internally + */ + if ((*dst)->stackaddr_attr == NULL) + (*dst)->stackaddr_attr = pid->stack; + + return (0); +} + +__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate); + +int +_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + + if (attr == NULL || *attr == NULL || detachstate == NULL) + return (EINVAL); + + /* Check if the detached flag is set: */ + if ((*attr)->flags & PTHREAD_DETACHED) + *detachstate = PTHREAD_CREATE_DETACHED; + else + *detachstate = PTHREAD_CREATE_JOINABLE; + + return (0); +} + +__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize); + +int +_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) +{ + if (attr == NULL || *attr == NULL || guardsize == NULL) + return (EINVAL); + + *guardsize = (*attr)->guardsize_attr; + + return (0); +} + +__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched); + +int +_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + *sched_inherit = (*attr)->sched_inherit; + + return (0); +} + +__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam); + +int +_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) +{ + if (attr == NULL || *attr == NULL || param == NULL) + return (EINVAL); + + param->sched_priority = (*attr)->prio; + + return (0); +} + +__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); + +int +_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + if (attr == NULL || *attr == NULL || policy == NULL) + return (EINVAL); + + *policy = (*attr)->sched_policy; + + return (0); +} + +__weak_reference(_pthread_attr_getscope, pthread_attr_getscope); + +int +_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope) +{ + if (attr == NULL || *attr == NULL || contentionscope == NULL) + return (EINVAL); + + *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ? + PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; + + return (0); +} + +__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) +{ + if (attr == NULL || *attr == NULL || stackaddr == NULL + || stacksize == NULL) + return (EINVAL); + + *stackaddr = (*attr)->stackaddr_attr; + *stacksize = (*attr)->stacksize_attr; + + return (0); +} + +__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr); + +int +_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + return (EINVAL); + + *stackaddr = (*attr)->stackaddr_attr; + + return (0); +} + +__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize); + +int +_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + if (attr == NULL || *attr == NULL || stacksize == NULL) + return (EINVAL); + + *stacksize = (*attr)->stacksize_attr; + + return (0); +} diff --git a/lib/libthr/thread/thr_autoinit.c b/lib/libthr/thread/thr_autoinit.c new file mode 100644 index 0000000..31e2d48 --- /dev/null +++ b/lib/libthr/thread/thr_autoinit.c @@ -0,0 +1,61 @@ +/* + * 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$ + */ + +/* + * 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_cancel.c b/lib/libthr/thread/thr_cancel.c new file mode 100644 index 0000000..0695fbc --- /dev/null +++ b/lib/libthr/thread/thr_cancel.c @@ -0,0 +1,205 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public domain. + * $FreeBSD$ + */ +#include <sys/errno.h> +#include <pthread.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) +{ + int ret; + pthread_t curthread; + + if ((ret = _find_thread(pthread)) != 0) { + /* NOTHING */ + } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK + || (pthread->flags & PTHREAD_EXITING) != 0) { + ret = 0; + } else { + curthread = _get_curthread(); + GIANT_LOCK(curthread); + + if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || + (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && + ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) + /* Just mark it for cancellation: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + else { + /* + * Check if we need to kick it back into the + * run queue: + */ + switch (pthread->state) { + case PS_RUNNING: + /* No need to resume: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + break; + + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + break; + + case PS_JOIN: + /* + * Disconnect the thread from the joinee: + */ + if (pthread->join_status.thread != NULL) { + pthread->join_status.thread->joiner + = NULL; + pthread->join_status.thread = NULL; + } + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + break; + + case PS_MUTEX_WAIT: + case PS_COND_WAIT: + /* + * Threads in these states may be in queues. + * In order to preserve queue integrity, the + * cancelled thread must remove itself from the + * queue. When the thread resumes, it will + * remove itself from the queue and call the + * cancellation routine. + */ + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + break; + + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + /* Ignore - only here to silence -Wall: */ + break; + } + } + + /* Unprotect the scheduling queues: */ + GIANT_UNLOCK(curthread); + + ret = 0; + } + return (ret); +} + +int +_pthread_setcancelstate(int state, int *oldstate) +{ + struct pthread *curthread = _get_curthread(); + int ostate; + + GIANT_LOCK(curthread); + ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; + + switch (state) { + case PTHREAD_CANCEL_ENABLE: + if (oldstate != NULL) + *oldstate = ostate; + curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; + if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) + break; + GIANT_UNLOCK(curthread); + pthread_testcancel(); + break; + case PTHREAD_CANCEL_DISABLE: + if (oldstate != NULL) + *oldstate = ostate; + curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; + GIANT_UNLOCK(curthread); + break; + default: + GIANT_UNLOCK(curthread); + return (EINVAL); + } + + return (0); +} + +int +_pthread_setcanceltype(int type, int *oldtype) +{ + struct pthread *curthread = _get_curthread(); + int otype; + + GIANT_LOCK(curthread); + otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + if (oldtype != NULL) + *oldtype = otype; + curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; + GIANT_UNLOCK(curthread); + pthread_testcancel(); + break; + case PTHREAD_CANCEL_DEFERRED: + if (oldtype != NULL) + *oldtype = otype; + curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; + GIANT_UNLOCK(curthread); + break; + default: + GIANT_UNLOCK(curthread); + return (EINVAL); + } + + return (0); +} + +/* + * XXXTHR Make an internal locked version. + */ +void +_pthread_testcancel(void) +{ + struct pthread *curthread = _get_curthread(); + + GIANT_LOCK(curthread); + if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && + ((curthread->cancelflags & PTHREAD_CANCELLING) != 0) && + ((curthread->flags & PTHREAD_EXITING) == 0)) { + /* + * It is possible for this thread to be swapped out + * while performing cancellation; do not allow it + * to be cancelled again. + */ + curthread->cancelflags &= ~PTHREAD_CANCELLING; + GIANT_UNLOCK(curthread); + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } + GIANT_UNLOCK(curthread); +} + +void +_thread_enter_cancellation_point(void) +{ + struct pthread *curthread = _get_curthread(); + + pthread_testcancel(); + + GIANT_LOCK(curthread); + curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; + GIANT_UNLOCK(curthread); +} + +void +_thread_leave_cancellation_point(void) +{ + struct pthread *curthread = _get_curthread(); + + GIANT_LOCK(curthread); + curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; + GIANT_UNLOCK(curthread); + + pthread_testcancel(); +} diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c new file mode 100644 index 0000000..8ae6b42 --- /dev/null +++ b/lib/libthr/thread/thr_clean.c @@ -0,0 +1,72 @@ +/* + * 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 <signal.h> +#include <errno.h> +#include <stdlib.h> +#include <pthread.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->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); + } + free(old); + } +} + diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c new file mode 100644 index 0000000..0327575 --- /dev/null +++ b/lib/libthr/thread/thr_cond.c @@ -0,0 +1,544 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include "thr_private.h" + +/* + * Prototypes + */ +static pthread_t cond_queue_deq(pthread_cond_t); +static void cond_queue_remove(pthread_cond_t, pthread_t); +static void cond_queue_enq(pthread_cond_t, pthread_t); + +__weak_reference(_pthread_cond_init, pthread_cond_init); +__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); +__weak_reference(_pthread_cond_wait, pthread_cond_wait); +__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); +__weak_reference(_pthread_cond_signal, pthread_cond_signal); +__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); + +#define COND_LOCK(c) \ +do { \ + if (umtx_lock(&(c)->c_lock, curthread->thr_id)) \ + abort(); \ +} while (0) + +#define COND_UNLOCK(c) \ +do { \ + if (umtx_unlock(&(c)->c_lock, curthread->thr_id)) \ + abort(); \ +} while (0) + + +/* Reinitialize a condition variable to defaults. */ +int +_cond_reinit(pthread_cond_t *cond) +{ + if (cond == NULL) + return (EINVAL); + + if (*cond == NULL) + return (pthread_cond_init(cond, NULL)); + + /* + * Initialize the condition variable structure: + */ + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags = COND_FLAGS_INITED; + (*cond)->c_type = COND_TYPE_FAST; + (*cond)->c_mutex = NULL; + (*cond)->c_seqno = 0; + bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock)); + + return (0); +} + +int +_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + enum pthread_cond_type type; + pthread_cond_t pcond; + + if (cond == NULL) + return (EINVAL); + + /* + * Check if a pointer to a condition variable attribute + * structure was passed by the caller: + */ + if (cond_attr != NULL && *cond_attr != NULL) + type = (*cond_attr)->c_type; + else + /* Default to a fast condition variable: */ + type = COND_TYPE_FAST; + + /* Process according to condition variable type: */ + switch (type) { + case COND_TYPE_FAST: + break; + default: + return (EINVAL); + break; + } + + if ((pcond = (pthread_cond_t) + malloc(sizeof(struct pthread_cond))) == NULL) + return (ENOMEM); + /* + * Initialise the condition variable + * structure: + */ + TAILQ_INIT(&pcond->c_queue); + pcond->c_flags |= COND_FLAGS_INITED; + pcond->c_type = type; + pcond->c_mutex = NULL; + pcond->c_seqno = 0; + bzero(&pcond->c_lock, sizeof(pcond->c_lock)); + + *cond = pcond; + + return (0); +} + +int +_pthread_cond_destroy(pthread_cond_t *cond) +{ + struct pthread *curthread = _get_curthread(); + + if (cond == NULL || *cond == NULL) + return (EINVAL); + + COND_LOCK(*cond); + + /* + * Free the memory allocated for the condition + * variable structure: + */ + free(*cond); + + /* + * NULL the caller's pointer now that the condition + * variable has been destroyed: + */ + *cond = NULL; + + return (0); +} + +int +_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + int rval; + struct timespec abstime = { 0, 0 }; + + /* + * XXXTHR This is a hack. Make a pthread_cond_common function that + * accepts NULL so we don't change posix semantics for timedwait. + */ + rval = pthread_cond_timedwait(cond, mutex, &abstime); + + /* This should never happen. */ + if (rval == ETIMEDOUT) + abort(); + + return (rval); +} + +int +_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, + const struct timespec * abstime) +{ + struct pthread *curthread = _get_curthread(); + struct timespec *time; + int rval = 0; + int done = 0; + int seqno; + int mtxrval; + + + _thread_enter_cancellation_point(); + + if (abstime == NULL || abstime->tv_nsec >= 1000000000) + return (EINVAL); + + if (abstime->tv_sec == 0 && abstime->tv_nsec == 0) + time = NULL; + else + time = abstime; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) + return (rval); + + + COND_LOCK(*cond); + + /* + * If the condvar was statically allocated, properly + * initialize the tail queue. + */ + if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags |= COND_FLAGS_INITED; + } + + /* Process according to condition variable type. */ + + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + COND_UNLOCK(*cond); + rval = EINVAL; + break; + } + /* Remember the mutex */ + (*cond)->c_mutex = *mutex; + + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + if (rval == -1){ + printf("foo"); + fflush(stdout); + abort(); + } + + COND_UNLOCK(*cond); + break; + } + COND_UNLOCK(*cond); + + /* + * We need giant for the queue operations. It also + * protects seqno and the pthread flag fields. This is + * dropped and reacquired in _thread_suspend(). + */ + + GIANT_LOCK(curthread); + /* + * c_seqno is protected by giant. + */ + seqno = (*cond)->c_seqno; + + do { + /* + * Queue the running thread on the condition + * variable. + */ + cond_queue_enq(*cond, curthread); + + if (curthread->cancelflags & PTHREAD_CANCELLING) { + /* + * POSIX Says that we must relock the mutex + * even if we're being canceled. + */ + GIANT_UNLOCK(curthread); + _mutex_cv_lock(mutex); + pthread_testcancel(); + PANIC("Shouldn't have come back."); + } + + PTHREAD_SET_STATE(curthread, PS_COND_WAIT); + rval = _thread_suspend(curthread, time); + if (rval == -1) { + printf("foo"); + fflush(stdout); + abort(); + } + + done = (seqno != (*cond)->c_seqno); + + cond_queue_remove(*cond, curthread); + + } while ((done == 0) && (rval == 0)); + /* + * If we timed out someone still may have signaled us + * before we got a chance to run again. We check for + * this by looking to see if our state is RUNNING. + */ + if (rval == EAGAIN) { + if (curthread->state != PS_RUNNING) { + PTHREAD_SET_STATE(curthread, PS_RUNNING); + rval = ETIMEDOUT; + } else + rval = 0; + } + GIANT_UNLOCK(curthread); + + mtxrval = _mutex_cv_lock(mutex); + + /* + * If the mutex failed return that error, otherwise we're + * returning ETIMEDOUT. + */ + if (mtxrval == -1) { + printf("foo"); + fflush(stdout); + abort(); + } + if (mtxrval != 0) + rval = mtxrval; + + break; + + /* Trap invalid condition variable types: */ + default: + COND_UNLOCK(*cond); + rval = EINVAL; + break; + } + + /* + * See if we have to cancel before we retry. We could be + * canceled with the mutex held here! + */ + pthread_testcancel(); + + _thread_leave_cancellation_point(); + + return (rval); +} + +int +_pthread_cond_signal(pthread_cond_t * cond) +{ + struct pthread *curthread = _get_curthread(); + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + return (EINVAL); + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) + return (rval); + + + COND_LOCK(*cond); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + GIANT_LOCK(curthread); + (*cond)->c_seqno++; + + if ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Wake up the signaled thread: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + } + + GIANT_UNLOCK(curthread); + break; + + /* Trap invalid condition variable types: */ + default: + rval = EINVAL; + break; + } + + + COND_UNLOCK(*cond); + + return (rval); +} + +int +_pthread_cond_broadcast(pthread_cond_t * cond) +{ + struct pthread *curthread = _get_curthread(); + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + return (EINVAL); + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) + return (rval); + + COND_LOCK(*cond); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + GIANT_LOCK(curthread); + (*cond)->c_seqno++; + + /* + * Enter a loop to bring all threads off the + * condition queue: + */ + while ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Wake up the signaled thread: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + } + GIANT_UNLOCK(curthread); + + /* There are no more waiting threads: */ + (*cond)->c_mutex = NULL; + + break; + + /* Trap invalid condition variable types: */ + default: + rval = EINVAL; + break; + } + + COND_UNLOCK(*cond); + + + return (rval); +} + +void +_cond_wait_backout(pthread_t pthread) +{ + struct pthread *curthread = _get_curthread(); + pthread_cond_t cond; + + cond = pthread->data.cond; + if (cond == NULL) + return; + + COND_LOCK(cond); + + /* Process according to condition variable type: */ + switch (cond->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + GIANT_LOCK(curthread); + + cond_queue_remove(cond, pthread); + + GIANT_UNLOCK(curthread); + break; + + default: + break; + } + + COND_UNLOCK(cond); +} + +/* + * Dequeue a waiting thread from the head of a condition queue in + * descending priority order. + */ +static pthread_t +cond_queue_deq(pthread_cond_t cond) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { + TAILQ_REMOVE(&cond->c_queue, pthread, sqe); + cond_queue_remove(cond, pthread); + if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 && + pthread->state == PS_COND_WAIT) + /* + * Only exit the loop when we find a thread + * that hasn't timed out or been canceled; + * those threads are already running and don't + * need their run state changed. + */ + break; + } + + return(pthread); +} + +/* + * Remove a waiting thread from a condition queue in descending priority + * order. + */ +static void +cond_queue_remove(pthread_cond_t cond, pthread_t pthread) +{ + /* + * Because pthread_cond_timedwait() can timeout as well + * as be signaled by another thread, it is necessary to + * guard against removing the thread from the queue if + * it isn't in the queue. + */ + if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { + TAILQ_REMOVE(&cond->c_queue, pthread, sqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; + } + /* Check for no more waiters. */ + if (TAILQ_FIRST(&cond->c_queue) == NULL) + cond->c_mutex = NULL; +} + +/* + * Enqueue a waiting thread to a condition queue in descending priority + * order. + */ +static void +cond_queue_enq(pthread_cond_t cond, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); + + PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); + + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); + else { + tid = TAILQ_FIRST(&cond->c_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, sqe); + TAILQ_INSERT_BEFORE(tid, pthread, sqe); + } + pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; + pthread->data.cond = cond; +} diff --git a/lib/libthr/thread/thr_condattr_destroy.c b/lib/libthr/thread/thr_condattr_destroy.c new file mode 100644 index 0000000..e0ade00 --- /dev/null +++ b/lib/libthr/thread/thr_condattr_destroy.c @@ -0,0 +1,53 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy); + +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); +} diff --git a/lib/libthr/thread/thr_condattr_init.c b/lib/libthr/thread/thr_condattr_init.c new file mode 100644 index 0000000..1af12e1 --- /dev/null +++ b/lib/libthr/thread/thr_condattr_init.c @@ -0,0 +1,58 @@ +/* + * 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 <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_condattr_init, pthread_condattr_init); + +int +_pthread_condattr_init(pthread_condattr_t *attr) +{ + int ret; + pthread_condattr_t pattr; + + 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); +} diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c new file mode 100644 index 0000000..9a663b4 --- /dev/null +++ b/lib/libthr/thread/thr_create.c @@ -0,0 +1,228 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/time.h> +#include <machine/reg.h> +#include <pthread.h> +#include "thr_private.h" +#include "libc_private.h" + +static u_int64_t next_uniqueid = 1; + +#define OFF(f) offsetof(struct pthread, f) +int _thread_next_offset = OFF(tle.tqe_next); +int _thread_uniqueid_offset = OFF(uniqueid); +int _thread_state_offset = OFF(state); +int _thread_name_offset = OFF(name); +int _thread_ctx_offset = OFF(ctx); +#undef OFF + +int _thread_PS_RUNNING_value = PS_RUNNING; +int _thread_PS_DEAD_value = PS_DEAD; + +__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 = _get_curthread(); + struct itimerval itimer; + int f_gc = 0; + int ret = 0; + pthread_t gc_thread; + pthread_t new_thread; + pthread_attr_t pattr; + int flags; + void *stack; + + /* + * Locking functions in libc are required when there are + * threads other than the initial thread. + */ + __isthreaded = 1; + + /* Allocate memory for the thread structure: */ + if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) + return (EAGAIN); + + /* Check if default thread attributes are required: */ + if (attr == NULL || *attr == NULL) + pattr = &pthread_attr_default; + else + pattr = *attr; + + /* Check if a stack was specified in the thread attributes: */ + if ((stack = pattr->stackaddr_attr) == NULL) { + stack = _thread_stack_alloc(pattr->stacksize_attr, + pattr->guardsize_attr); + if (stack == NULL) { + free(new_thread); + return (EAGAIN); + } + } + + /* Initialise the thread structure: */ + memset(new_thread, 0, sizeof(struct pthread)); + new_thread->stack = stack; + new_thread->start_routine = start_routine; + new_thread->arg = arg; + + new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + new_thread->magic = PTHREAD_MAGIC; + + /* Initialise the machine context: */ + getcontext(&new_thread->ctx); + new_thread->ctx.uc_stack.ss_sp = new_thread->stack; + new_thread->ctx.uc_stack.ss_size = pattr->stacksize_attr; + makecontext(&new_thread->ctx, _thread_start, 1); + + /* Copy the thread attributes: */ + memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); + + /* + * Check if this thread is to inherit the scheduling + * attributes from its parent: + */ + if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { + /* Copy the scheduling attributes: */ + new_thread->base_priority = curthread->base_priority & + ~PTHREAD_SIGNAL_PRIORITY; + new_thread->attr.prio = curthread->base_priority & + ~PTHREAD_SIGNAL_PRIORITY; + new_thread->attr.sched_policy = curthread->attr.sched_policy; + } 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; + new_thread->inherited_priority = 0; + + /* Initialize joiner to NULL (no joiner): */ + new_thread->joiner = NULL; + + /* Initialize the mutex queue: */ + TAILQ_INIT(&new_thread->mutexq); + + /* Initialise hooks in the thread structure: */ + new_thread->specific = NULL; + new_thread->cleanup = NULL; + new_thread->flags = 0; + + /* + * Protect the scheduling queues. + */ + GIANT_LOCK(curthread); + + /* + * Initialise the unique id which GDB uses to + * track threads. + */ + new_thread->uniqueid = next_uniqueid++; + + /* + * Check if the garbage collector thread + * needs to be started. + */ + f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); + + /* Add the thread to the linked list of all threads: */ + TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); + + /* + * Create the thread. + * + */ + if (pattr->suspend == PTHREAD_FLAGS_SUSPENDED) + flags = THR_SUSPENDED; + else + flags = 0; + + ret = thr_create(&new_thread->ctx, &new_thread->thr_id, flags); + + if (ret != 0) { + _thread_printf("thr_create() == %d\n", ret); + PANIC("thr_create"); + } + + GIANT_UNLOCK(curthread); + + /* Return a pointer to the thread structure: */ + (*thread) = new_thread; + + /* + * Start a garbage collector thread + * if necessary. + */ +#if 0 + if (f_gc && pthread_create(&gc_thread,NULL, _thread_gc,NULL) != 0) + PANIC("Can't create gc thread"); +#endif + + return (0); +} + +void +_thread_start(void) +{ + struct pthread *curthread = _get_curthread_slow(); + + curthread->arch_id = _set_curthread(curthread); + + if (_get_curthread() != curthread) { + _thread_printf("%x - %x\n", _get_curthread(), curthread); + abort(); + } + + /* 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..ca1b473 --- /dev/null +++ b/lib/libthr/thread/thr_detach.c @@ -0,0 +1,82 @@ +/* + * 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 <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_detach, pthread_detach); + +int +_pthread_detach(pthread_t pthread) +{ + pthread_t curthread; + + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + return (EINVAL); + + if (pthread->attr.flags & PTHREAD_DETACHED) + return (EINVAL); + + curthread = _get_curthread(); + + pthread->attr.flags |= PTHREAD_DETACHED; + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + GIANT_LOCK(curthread); + + /* Check if there is a joiner: */ + if (pthread->joiner != NULL) { + struct pthread *joiner = pthread->joiner; + + /* Make the thread runnable: */ + PTHREAD_NEW_STATE(joiner, PS_RUNNING); + + /* Set the return value for the woken thread: */ + joiner->join_status.error = ESRCH; + joiner->join_status.ret = NULL; + joiner->join_status.thread = NULL; + + /* + * Disconnect the joiner from the thread being detached: + */ + pthread->joiner = NULL; + } + + GIANT_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..f8882f5 --- /dev/null +++ b/lib/libthr/thread/thr_equal.c @@ -0,0 +1,44 @@ +/* + * 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" + +__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_exit.c b/lib/libthr/thread/thr_exit.c new file mode 100644 index 0000000..2d791d2 --- /dev/null +++ b/lib/libthr/thread/thr_exit.c @@ -0,0 +1,186 @@ +/* + * 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 <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_exit, pthread_exit); + +void +_thread_exit(char *fname, int lineno, char *string) +{ + char s[256]; + + /* Prepare an error message string: */ + snprintf(s, sizeof(s), + "Fatal error '%s' at line %d in file %s (errno = %d)\n", + string, lineno, fname, errno); + + /* Write the string to the standard error file descriptor: */ + __sys_write(2, s, strlen(s)); + + /* Force this process to exit: */ + /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */ +#if defined(_PTHREADS_INVARIANTS) + abort(); +#else + __sys_exit(1); +#endif +} + +/* + * 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 +_thread_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(); + pthread_t pthread; + + /* Check if this thread is already in the process of exiting: */ + if ((curthread->flags & PTHREAD_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: */ + curthread->flags |= PTHREAD_EXITING; + + /* Save the return value: */ + curthread->ret = status; + + while (curthread->cleanup != NULL) { + pthread_cleanup_pop(1); + } + if (curthread->attr.cleanup_attr != NULL) { + curthread->attr.cleanup_attr(curthread->attr.arg_attr); + } + /* Check if there is thread specific data: */ + if (curthread->specific != NULL) { + /* Run the thread-specific data destructors: */ + _thread_cleanupspecific(); + } + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* Add this thread to the list of dead threads. */ + TAILQ_INSERT_HEAD(&_dead_list, curthread, dle); + + /* + * Signal the garbage collector thread that there is something + * to clean up. + */ + if (pthread_cond_signal(&_gc_cond) != 0) + PANIC("Cannot signal gc cond"); + + /* + * Avoid a race condition where a scheduling signal can occur + * causing the garbage collector thread to run. If this happens, + * the current thread can be cleaned out from under us. + */ + GIANT_LOCK(curthread); + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* Check if there is a thread joining this one: */ + if (curthread->joiner != NULL) { + pthread = curthread->joiner; + curthread->joiner = NULL; + + /* Make the joining thread runnable: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Set the return value for the joining thread: */ + pthread->join_status.ret = curthread->ret; + pthread->join_status.error = 0; + pthread->join_status.thread = NULL; + + /* Make this thread collectable by the garbage collector. */ + PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) == + 0), "Cannot join a detached thread"); + curthread->attr.flags |= PTHREAD_DETACHED; + } + + /* Remove this thread from the thread list: */ + TAILQ_REMOVE(&_thread_list, curthread, tle); + + PTHREAD_SET_STATE(curthread, PS_DEAD); + GIANT_UNLOCK(curthread); + + /* + * Retire the architecture specific id so that it can be used for + * new threads. + */ + _retire_thread(curthread->arch_id); + _thr_exit(); + + /* This point should not be reached. */ + PANIC("Dead thread has resumed"); +} diff --git a/lib/libthr/thread/thr_find_thread.c b/lib/libthr/thread/thr_find_thread.c new file mode 100644 index 0000000..a784818 --- /dev/null +++ b/lib/libthr/thread/thr_find_thread.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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 <pthread.h> +#include "thr_private.h" + +/* Find a thread in the linked list of active threads: */ +int +_find_thread(pthread_t pthread) +{ + pthread_t curthread; + pthread_t pthread1; + + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + return(EINVAL); + + curthread = _get_curthread(); + GIANT_LOCK(curthread); + + /* Search for the specified thread: */ + TAILQ_FOREACH(pthread1, &_thread_list, tle) { + if (pthread == pthread1) + break; + } + + GIANT_UNLOCK(curthread); + + /* Return zero if the thread exists: */ + return ((pthread1 != NULL) ? 0:ESRCH); +} diff --git a/lib/libthr/thread/thr_gc.c b/lib/libthr/thread/thr_gc.c new file mode 100644 index 0000000..987f88f --- /dev/null +++ b/lib/libthr/thread/thr_gc.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE 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$ + * + * Garbage collector thread. Frees memory allocated for dead threads. + * + */ +#include <sys/param.h> +#include <errno.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <pthread.h> +#include "thr_private.h" + +pthread_addr_t +_thread_gc(pthread_addr_t arg) +{ + struct pthread *curthread = _get_curthread(); + int f_debug; + int f_done = 0; + int ret; + sigset_t mask; + pthread_t pthread; + pthread_t pthread_cln; + struct timespec abstime; + void *p_stack; + + /* Block all signals */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + /* Mark this thread as a library thread (not a user thread). */ + curthread->flags |= PTHREAD_FLAGS_PRIVATE; + + /* Set a debug flag based on an environment variable. */ + f_debug = (getenv("LIBC_R_DEBUG") != NULL); + + /* Set the name of this thread. */ + pthread_set_name_np(curthread,"GC"); + + while (!f_done) { + /* Check if debugging this application. */ + if (f_debug) + /* Dump thread info to file. */ + _thread_dump_info(); + + /* + * Lock the garbage collector mutex which ensures that + * this thread sees another thread exit: + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* No stack or thread structure to free yet. */ + p_stack = NULL; + pthread_cln = NULL; + + GIANT_LOCK(curthread); + + /* Check if this is the last running thread. */ + if (TAILQ_FIRST(&_thread_list) == curthread && + TAILQ_NEXT(curthread, tle) == NULL) + /* + * This is the last thread, so it can exit + * now. + */ + f_done = 1; + + /* + * Enter a loop to search for the first dead thread that + * has memory to free. + */ + for (pthread = TAILQ_FIRST(&_dead_list); + p_stack == NULL && pthread_cln == NULL && pthread != NULL; + pthread = TAILQ_NEXT(pthread, dle)) { + /* Don't destroy the initial thread. */ + if (pthread == _thread_initial) + continue; + /* + * Check if this thread has detached: + */ + if ((pthread->attr.flags & + PTHREAD_DETACHED) != 0) { + /* Remove this thread from the dead list: */ + TAILQ_REMOVE(&_dead_list, pthread, dle); + + /* + * Check if the stack was not specified by + * the caller to pthread_create() and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + _thread_stack_free(pthread->stack, + pthread->attr.stacksize_attr, + pthread->attr.guardsize_attr); + } + + /* + * Point to the thread structure that must + * be freed outside the locks: + */ + pthread_cln = pthread; + + } else { + /* + * This thread has not detached, so do + * not destroy it. + * + * Check if the stack was not specified by + * the caller to pthread_create() and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + _thread_stack_free(pthread->stack, + pthread->attr.stacksize_attr, + pthread->attr.guardsize_attr); + + /* + * NULL the stack pointer now that the + * memory has been freed: + */ + pthread->stack = NULL; + } + } + } + + GIANT_UNLOCK(curthread); + /* + * Check if this is not the last thread and there is no + * memory to free this time around. + */ + if (!f_done && p_stack == NULL && pthread_cln == NULL) { + /* Get the current time. */ + if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) + PANIC("gc cannot get time"); + + /* + * Do a backup poll in 10 seconds if no threads + * die before then. + */ + abstime.tv_sec += 10; + + /* + * Wait for a signal from a dying thread or a + * timeout (for a backup poll). + */ + if ((ret = pthread_cond_timedwait(&_gc_cond, + &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) { + _thread_printf("ret = %d", ret); + PANIC("gc cannot wait for a signal"); + } + } + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* + * If there is memory to free, do it now. The call to + * free() might block, so this must be done outside the + * locks. + */ + if (p_stack != NULL) + free(p_stack); + if (pthread_cln != NULL) { + if (pthread_cln->name != NULL) { + /* Free the thread name string. */ + free(pthread_cln->name); + } + /* + * Free the memory allocated for the thread + * structure. + */ + free(pthread_cln); + } + } + return (NULL); +} diff --git a/lib/libthr/thread/thr_getprio.c b/lib/libthr/thread/thr_getprio.c new file mode 100644 index 0000000..fa95ef9 --- /dev/null +++ b/lib/libthr/thread/thr_getprio.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 <errno.h> +#include <pthread.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..7f1503c --- /dev/null +++ b/lib/libthr/thread/thr_getschedparam.c @@ -0,0 +1,59 @@ +/* + * 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 <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_getschedparam, pthread_getschedparam); + +int +_pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param) +{ + int ret; + + if ((param == NULL) || (policy == NULL)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Find the thread in the list of active threads: */ + else if ((ret = _find_thread(pthread)) == 0) { + /* Return the threads base priority and scheduling policy: */ + param->sched_priority = + PTHREAD_BASE_PRIORITY(pthread->base_priority); + *policy = pthread->attr.sched_policy; + } + + return(ret); +} diff --git a/lib/libthr/thread/thr_info.c b/lib/libthr/thread/thr_info.c new file mode 100644 index 0000000..2e2f9de --- /dev/null +++ b/lib/libthr/thread/thr_info.c @@ -0,0 +1,193 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include "thr_private.h" + +#ifndef NELEMENTS +#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +static void dump_thread(int fd, pthread_t pthread, int long_version); + +__weak_reference(_pthread_set_name_np, pthread_set_name_np); + +struct s_thread_info { + enum pthread_state state; + char *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { + {PS_RUNNING , "Running"}, + {PS_MUTEX_WAIT , "Waiting on a mutex"}, + {PS_COND_WAIT , "Waiting on a condition variable"}, + {PS_SLEEP_WAIT , "Sleeping"}, + {PS_WAIT_WAIT , "Waiting process"}, + {PS_JOIN , "Waiting to join"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} +}; + +void +_thread_dump_info(void) +{ + char s[512]; + int fd; + int i; + pthread_t pthread; + char tmpfile[128]; + + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ + return; + } else { + /* Output a header for active threads: */ + strcpy(s, "\n\n=============\nACTIVE THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the global list: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + dump_thread(fd, pthread, /*long_verson*/ 1); + } + + /* Check if there are no dead threads: */ + if (TAILQ_FIRST(&_dead_list) == NULL) { + /* Output a record: */ + strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n"); + __sys_write(fd, s, strlen(s)); + } else { + /* Output a header for dead threads: */ + strcpy(s, "\n\nDEAD THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* + * Enter a loop to report each thread in the global + * dead thread list: + */ + TAILQ_FOREACH(pthread, &_dead_list, dle) { + dump_thread(fd, pthread, /*long_version*/ 0); + } + } + + /* Close the dump file: */ + __sys_close(fd); + } +} + +static void +dump_thread(int fd, pthread_t pthread, int long_version) +{ + struct pthread *curthread = _get_curthread(); + char s[512]; + int i; + + /* Find the state: */ + for (i = 0; i < NELEMENTS(thread_info) - 1; i++) + if (thread_info[i].state == pthread->state) + break; + + /* Output a record for the thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? "" : pthread->name, + pthread->active_priority, thread_info[i].name, pthread->fname, + pthread->lineno); + __sys_write(fd, s, strlen(s)); + + if (long_version != 0) { + /* Check if this is the running thread: */ + if (pthread == curthread) { + /* Output a record for the running thread: */ + strcpy(s, "This is the running thread\n"); + __sys_write(fd, s, strlen(s)); + } + /* Check if this is the initial thread: */ + if (pthread == _thread_initial) { + /* Output a record for the initial thread: */ + strcpy(s, "This is the initial thread\n"); + __sys_write(fd, s, strlen(s)); + } + /* Process according to thread state: */ + switch (pthread->state) { + /* + * Trap other states that are not explicitly + * coded to dump information: + */ + default: + /* Nothing to do here. */ + break; + } + } +} + +/* Set the thread name for debug: */ +void +_pthread_set_name_np(pthread_t thread, const char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == PTHREAD_MAGIC) { + if (thread->name != NULL) { + /* Free space for previous name. */ + free(thread->name); + } + thread->name = strdup(name); + } +} diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c new file mode 100644 index 0000000..266ff16 --- /dev/null +++ b/lib/libthr/thread/thr_init.c @@ -0,0 +1,363 @@ +/* + * 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$ + */ + +/* Allocate space for global thread variables here: */ +#define GLOBAL_PTHREAD_PRIVATE + +#include "namespace.h" +#include <sys/param.h> +#include <sys/types.h> +#include <machine/reg.h> + +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/uio.h> +#include <sys/socket.h> +#include <sys/event.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/ttycom.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "thr_private.h" + +/* + * All weak references used within libc should be in this table. + * This will is so that static libraries will work. + * + * XXXTHR - Check this list. + */ +static void *references[] = { + &_accept, + &_bind, + &_close, + &_connect, + &_dup, + &_dup2, + &_execve, + &_fcntl, + &_flock, + &_flockfile, + &_fstat, + &_fstatfs, + &_fsync, + &_funlockfile, + &_getdirentries, + &_getlogin, + &_getpeername, + &_getsockname, + &_getsockopt, + &_ioctl, + &_kevent, + &_listen, + &_nanosleep, + &_open, + &_pthread_getspecific, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_mutex_destroy, + &_pthread_mutex_init, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock, + &_pthread_mutexattr_init, + &_pthread_mutexattr_destroy, + &_pthread_mutexattr_settype, + &_pthread_once, + &_pthread_setspecific, + &_read, + &_readv, + &_recvfrom, + &_recvmsg, + &_select, + &_sendmsg, + &_sendto, + &_setsockopt, + &_sigaction, + &_sigprocmask, + &_sigsuspend, + &_socket, + &_socketpair, + &_wait4, + &_write, + &_writev +}; + +/* + * These are needed when linking statically. All references within + * libgcc (and in the future libc) to these routines are weak, but + * if they are not (strongly) referenced by the application or other + * libraries, then the actual functions will not be loaded. + */ +static void *libgcc_references[] = { + &_pthread_once, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_getspecific, + &_pthread_setspecific, + &_pthread_mutex_init, + &_pthread_mutex_destroy, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock +}; + +int _pthread_guard_default; +int _pthread_page_size; + +/* + * Threaded process initialization + */ +void +_thread_init(void) +{ + struct pthread *pthread; + int fd; + int flags; + int i; + size_t len; + int mib[2]; + sigset_t set; + + struct clockinfo clockinfo; + struct sigaction act; + + /* Check if this function has already been called: */ + if (_thread_initial) + /* Only initialise the threaded application once. */ + return; + + _pthread_page_size = getpagesize(); + _pthread_guard_default = getpagesize(); + + pthread_attr_default.guardsize_attr = _pthread_guard_default; + + + /* + * Make gcc quiescent about {,libgcc_}references not being + * referenced: + */ + if ((references[0] == NULL) || (libgcc_references[0] == NULL)) + PANIC("Failed loading mandatory references in _thread_init"); + + /* + * Check for the special case of this process running as + * or in place of init as pid = 1: + */ + if (getpid() == 1) { + /* + * Setup a new session for this process which is + * assumed to be running as root. + */ + if (setsid() == -1) + PANIC("Can't set session ID"); + if (revoke(_PATH_CONSOLE) != 0) + PANIC("Can't revoke console"); + if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) + PANIC("Can't open console"); + if (setlogin("root") == -1) + PANIC("Can't set login to root"); + if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) + PANIC("Can't set controlling terminal"); + if (__sys_dup2(fd, 0) == -1 || + __sys_dup2(fd, 1) == -1 || + __sys_dup2(fd, 2) == -1) + PANIC("Can't dup2"); + } + + /* Allocate memory for the thread structure of the initial thread: */ + if ((pthread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { + /* + * Insufficient memory to initialise this application, so + * abort: + */ + PANIC("Cannot allocate memory for initial thread"); + } + _thread_initial = pthread; + pthread->arch_id = _set_curthread(pthread); + + /* Zero the initial thread structure: */ + memset(pthread, 0, sizeof(struct pthread)); + /* Get our thread id. */ + thr_self(&pthread->thr_id); + + /* Give this thread default attributes: */ + memcpy((void *) &pthread->attr, &pthread_attr_default, + sizeof(struct pthread_attr)); + + /* Find the stack top */ + mib[0] = CTL_KERN; + mib[1] = KERN_USRSTACK; + len = sizeof (_usrstack); + if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) + _usrstack = (void *)USRSTACK; + /* + * Create a red zone below the main stack. All other stacks are + * constrained to a maximum size by the paramters 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 - PTHREAD_STACK_INITIAL - + _pthread_guard_default, _pthread_guard_default, 0, + MAP_ANON, -1, 0) == MAP_FAILED) + PANIC("Cannot allocate red zone for initial thread"); + + /* Set the main thread stack pointer. */ + pthread->stack = _usrstack - PTHREAD_STACK_INITIAL; + + /* Set the stack attributes. */ + pthread->attr.stackaddr_attr = pthread->stack; + pthread->attr.stacksize_attr = PTHREAD_STACK_INITIAL; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + pthread->magic = PTHREAD_MAGIC; + + /* Set the initial cancel state */ + pthread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED; + + /* Setup the context for initial thread. */ + getcontext(&pthread->ctx); + pthread->ctx.uc_stack.ss_sp = pthread->stack; + pthread->ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL; + + /* Default the priority of the initial thread: */ + pthread->base_priority = PTHREAD_DEFAULT_PRIORITY; + pthread->active_priority = PTHREAD_DEFAULT_PRIORITY; + pthread->inherited_priority = 0; + + /* Initialise the state of the initial thread: */ + pthread->state = PS_RUNNING; + + /* Set the name of the thread: */ + pthread->name = strdup("_thread_initial"); + + /* Initialize joiner to NULL (no joiner): */ + pthread->joiner = NULL; + + /* Initialize the owned mutex queue and count: */ + TAILQ_INIT(&(pthread->mutexq)); + pthread->priority_mutex_count = 0; + + /* Initialise the rest of the fields: */ + pthread->specific = NULL; + pthread->cleanup = NULL; + pthread->flags = 0; + pthread->error = 0; + TAILQ_INIT(&_thread_list); + TAILQ_INSERT_HEAD(&_thread_list, pthread, tle); + + /* Enter a loop to get the existing signal status: */ + for (i = 1; i < NSIG; i++) { + /* Check for signals which cannot be trapped. */ + if (i == SIGKILL || i == SIGSTOP) + continue; + + /* Get the signal handler details. */ + if (__sys_sigaction(i, NULL, + &_thread_sigact[i - 1]) != 0) + PANIC("Cannot read signal handler info"); + } + act.sa_sigaction = _thread_sig_wrapper; + act.sa_flags = SA_SIGINFO; + SIGFILLSET(act.sa_mask); + + if (__sys_sigaction(SIGTHR, &act, NULL)) + PANIC("Cannot set SIGTHR handler.\n"); + + SIGEMPTYSET(set); + SIGADDSET(set, SIGTHR); + __sys_sigprocmask(SIG_BLOCK, &set, 0); + + /* Get the kernel clockrate: */ + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + len = sizeof (struct clockinfo); + if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0) + _clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ? + clockinfo.tick : CLOCK_RES_USEC_MIN; + + /* Initialise the garbage collector mutex and condition variable. */ + if (_pthread_mutex_init(&_gc_mutex,NULL) != 0 || + pthread_cond_init(&_gc_cond,NULL) != 0) + PANIC("Failed to initialise garbage collector mutex or condvar"); +} + +struct pthread * +_get_curthread_slow(void) +{ + struct pthread *td; + thr_id_t id; + + if (_thread_initial == NULL) + _thread_init(); + + thr_self(&id); + TAILQ_FOREACH(td, &_thread_list, tle) + if (td->thr_id == id) + return (td); + return (NULL); +} + +/* + * Special start up code for NetBSD/Alpha + */ +#if defined(__NetBSD__) && defined(__alpha__) +int +main(int argc, char *argv[], char *env); + +int +_thread_main(int argc, char *argv[], char *env) +{ + _thread_init(); + return (main(argc, argv, env)); +} +#endif diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c new file mode 100644 index 0000000..e22408c --- /dev/null +++ b/lib/libthr/thread/thr_join.c @@ -0,0 +1,161 @@ +/* + * 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 <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_join, pthread_join); + +int +_pthread_join(pthread_t pthread, void **thread_return) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + pthread_t thread; + + _thread_enter_cancellation_point(); + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { + /* Invalid thread: */ + _thread_leave_cancellation_point(); + return(EINVAL); + } + + /* Check if the caller has specified itself: */ + if (pthread == curthread) { + /* Avoid a deadlock condition: */ + _thread_leave_cancellation_point(); + return(EDEADLK); + } + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + GIANT_LOCK(curthread); + + /* + * Search for the specified thread in the list of active threads. This + * is done manually here rather than calling _find_thread() because + * the searches in _thread_list and _dead_list (as well as setting up + * join/detach state) have to be done atomically. + */ + TAILQ_FOREACH(thread, &_thread_list, tle) + if (thread == pthread) + break; + + if (thread == NULL) + /* + * Search for the specified thread in the list of dead threads: + */ + TAILQ_FOREACH(thread, &_dead_list, dle) + if (thread == pthread) + break; + + + /* Check if the thread was not found or has been detached: */ + if (thread == NULL || + ((pthread->attr.flags & PTHREAD_DETACHED) != 0)) { + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + ret = ESRCH; + goto out; + + } + if (pthread->joiner != NULL) { + /* Multiple joiners are not supported. */ + /* XXXTHR - support multiple joiners. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + ret = ENOTSUP; + goto out; + + /* Check if the thread is not dead: */ + } + /* + * Unlock the garbage collector mutex, now that the garbage collector + * can't be run: + */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + if (pthread->state != PS_DEAD) { + /* Set the running thread to be the joiner: */ + pthread->joiner = curthread; + + /* Keep track of which thread we're joining to: */ + curthread->join_status.thread = pthread; + + while (curthread->join_status.thread == pthread) { + PTHREAD_SET_STATE(curthread, PS_JOIN); + /* Wait for our signal to wake up. */ + _thread_suspend(curthread, NULL); + } + + /* + * The thread return value and error are set by the thread we're + * joining to when it exits or detaches: + */ + ret = curthread->join_status.error; + if ((ret == 0) && (thread_return != NULL)) + *thread_return = curthread->join_status.ret; + } else { + /* + * The thread exited (is dead) without being detached, and no + * thread has joined it. + */ + + /* Check if the return value is required: */ + if (thread_return != NULL) { + /* Return the thread's return value: */ + *thread_return = pthread->ret; + } + + /* Make the thread collectable by the garbage collector. */ + pthread->attr.flags |= PTHREAD_DETACHED; + + } + +out: + GIANT_UNLOCK(curthread); + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c new file mode 100644 index 0000000..1ad8526 --- /dev/null +++ b/lib/libthr/thread/thr_kern.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2003 Jeffrey Roberson <jeff@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/cdefs.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <sys/time.h> +#include <sys/timespec.h> +#include <pthread.h> +#include <signal.h> +#include <errno.h> + +#include "thr_private.h" + +/* XXX Why can't I get this from time.h? :-( */ +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } while (0) + +static sigset_t restore; + +pthread_t _giant_owner = NULL; +int _giant_count = 0; + +void +GIANT_LOCK(pthread_t pthread) +{ + sigset_t set; + sigset_t sav; + int error; + + if (_giant_owner == pthread) { + abort(); + _giant_count++; + } + + /* + * Block all signals. + */ + SIGFILLSET(set); + + /* + * We can not use the global 'restore' set until after we have + * acquired the giant lock. + */ +#if 0 + error = __sys_sigprocmask(SIG_SETMASK, &set, &sav); + if (error) { + _thread_printf(0, "GIANT_LOCK: sig err %d\n", errno); + abort(); + } +#endif + + error = umtx_lock(&_giant_mutex, pthread->thr_id); + if (error) { + _thread_printf(0, "GIANT_LOCK: %d\n", errno); + abort(); + } + + _giant_owner = pthread; + _giant_count = 1; + + restore = sav; +} + +void +GIANT_UNLOCK(pthread_t pthread) +{ + sigset_t set; + int error; + + if (_giant_owner != pthread) + abort(); + + if (--_giant_count > 0) + return; + + _giant_owner = NULL; + + /* + * restore is protected by giant. We could restore our signal state + * incorrectly if someone else set restore between unlocking giant + * and restoring the signal mask. To avoid this we cache a copy prior + * to the unlock. + */ + set = restore; + + error = umtx_unlock(&_giant_mutex, pthread->thr_id); + if (error) { + _thread_printf(0, "GIANT_UNLOCK: %d\n", errno); + abort(); + } + +#if 0 + /* + * Restore signals. + */ + error = __sys_sigprocmask(SIG_SETMASK, &set, NULL); + if (error) { + _thread_printf(0, "GIANT_UNLOCK: sig err %d\n", errno); + abort(); + } +#endif +} + +int +_thread_suspend(pthread_t thread, struct timespec *abstime) +{ + struct timespec remaining; + struct timespec *ts; + siginfo_t info; + sigset_t set; + int giant_count; /* Saved recursion */ + int error; + + /* + * Catch SIGTHR. + */ + SIGFILLSET(set); + SIGDELSET(set, SIGTHR); + + if (abstime) { + struct timespec now; + struct timeval tv; + + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, &now); + + remaining = *abstime; + timespecsub(&remaining, &now); + ts = &remaining; + } else + ts = NULL; + + /* + * Save and unroll the recursion count. + */ + giant_count = _giant_count; + _giant_count = 1; + GIANT_UNLOCK(thread); + + error = sigtimedwait(&set, &info, ts); + if (error == -1) + error = errno; + + /* XXX Kernel bug. */ + if (error == EINTR) + error = 0; + + /* + * Restore the recursion count. + */ + GIANT_LOCK(thread); + _giant_count = giant_count; + + return (error); +} diff --git a/lib/libthr/thread/thr_main_np.c b/lib/libthr/thread/thr_main_np.c new file mode 100644 index 0000000..1d5849d --- /dev/null +++ b/lib/libthr/thread/thr_main_np.c @@ -0,0 +1,47 @@ +/* + * 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 <pthread.h> +#include <pthread_np.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 (!_thread_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0); +} diff --git a/lib/libthr/thread/thr_mattr_init.c b/lib/libthr/thread/thr_mattr_init.c new file mode 100644 index 0000000..3d4195c --- /dev/null +++ b/lib/libthr/thread/thr_mattr_init.c @@ -0,0 +1,56 @@ +/* + * 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$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init); + +int +_pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + pthread_mutexattr_t pattr; + + if ((pattr = (pthread_mutexattr_t) + malloc(sizeof(struct pthread_mutex_attr))) == NULL) + return (ENOMEM); + + memcpy(pattr, &pthread_mutexattr_default, + sizeof(struct pthread_mutex_attr)); + *attr = pattr; + + return (0); +} diff --git a/lib/libthr/thread/thr_mattr_kind_np.c b/lib/libthr/thread/thr_mattr_kind_np.c new file mode 100644 index 0000000..f3d30ff --- /dev/null +++ b/lib/libthr/thread/thr_mattr_kind_np.c @@ -0,0 +1,97 @@ +/* + * 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$ + */ +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__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); + +int +_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = kind; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr) +{ + int ret; + if (attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + ret = attr->m_type; + } + return(ret); +} + +int +_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + int ret; + if (attr == NULL || *attr == NULL || type >= MUTEX_TYPE_MAX) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = type; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type) +{ + int ret; + + if (attr == NULL || *attr == NULL || (*attr)->m_type >= + MUTEX_TYPE_MAX) { + ret = EINVAL; + } else { + *type = (*attr)->m_type; + ret = 0; + } + return ret; +} diff --git a/lib/libthr/thread/thr_multi_np.c b/lib/libthr/thread/thr_multi_np.c new file mode 100644 index 0000000..bd42365 --- /dev/null +++ b/lib/libthr/thread/thr_multi_np.c @@ -0,0 +1,50 @@ +/* + * 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 <pthread.h> +#include <pthread_np.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..9b57b69 --- /dev/null +++ b/lib/libthr/thread/thr_mutex.c @@ -0,0 +1,432 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <pthread.h> +#include "thr_private.h" + +/* + * Prototypes + */ +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static struct pthread_mutex_attr static_mutex_attr = + PTHREAD_MUTEXATTR_STATIC_INITIALIZER; +static pthread_mutexattr_t static_mattr = &static_mutex_attr; + +/* Single underscore versions provided for libc internal usage: */ +__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); +__weak_reference(__pthread_mutex_lock, pthread_mutex_lock); + +/* No difference between libc and application usage of these: */ +__weak_reference(_pthread_mutex_init, pthread_mutex_init); +__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy); +__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock); + + +/* Reinitialize a mutex to defaults. */ +int +_mutex_reinit(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL) + return (EINVAL); + if (*mutex == NULL) + return (pthread_mutex_init(mutex, NULL)); + + (*mutex)->m_attr.m_type = PTHREAD_MUTEX_DEFAULT; + (*mutex)->m_attr.m_protocol = PTHREAD_PRIO_NONE; + (*mutex)->m_attr.m_ceiling = 0; + (*mutex)->m_attr.m_flags &= MUTEX_FLAGS_PRIVATE; + (*mutex)->m_attr.m_flags |= MUTEX_FLAGS_INITED; + bzero(&(*mutex)->m_mtx, sizeof(struct umtx)); + (*mutex)->m_owner = NULL; + (*mutex)->m_count = 0; + (*mutex)->m_refcount = 0; + + return (0); +} + +int +_pthread_mutex_init(pthread_mutex_t * mutex, + const pthread_mutexattr_t * mutex_attr) +{ + enum pthread_mutextype type; + pthread_mutex_t pmutex; + + if (mutex == NULL) + return (EINVAL); + + /* + * Allocate mutex. + */ + pmutex = (pthread_mutex_t)calloc(1, sizeof(struct pthread_mutex)); + if (pmutex == NULL) + return (ENOMEM); + + bzero(pmutex, sizeof(*pmutex)); + + /* Set mutex attributes. */ + if (mutex_attr == NULL || *mutex_attr == NULL) { + /* Default to a (error checking) POSIX mutex. */ + pmutex->m_attr.m_type = PTHREAD_MUTEX_ERRORCHECK; + pmutex->m_attr.m_protocol = PTHREAD_PRIO_NONE; + pmutex->m_attr.m_ceiling = 0; + pmutex->m_attr.m_flags = 0; + } else + bcopy(*mutex_attr, &pmutex->m_attr, sizeof(mutex_attr)); + + /* + * Sanity check mutex type. + */ + if ((pmutex->m_attr.m_type < PTHREAD_MUTEX_ERRORCHECK) || + (pmutex->m_attr.m_type >= MUTEX_TYPE_MAX) || + (pmutex->m_attr.m_protocol < PTHREAD_PRIO_NONE) || + (pmutex->m_attr.m_protocol > PTHREAD_MUTEX_RECURSIVE)) + goto err; + + + /* + * Initialize mutex. + */ + pmutex->m_attr.m_flags |= MUTEX_FLAGS_INITED; + *mutex = pmutex; + + return (0); +err: + free(pmutex); + return (EINVAL); +} + +int +_pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL || *mutex == NULL) + return (EINVAL); + + /* Ensure that the mutex is unlocked. */ + if (((*mutex)->m_owner != NULL) || + ((*mutex)->m_refcount != 0)) + return (EBUSY); + + + /* Free it. */ + free(*mutex); + *mutex = NULL; + return (0); +} + +static int +init_static(pthread_mutex_t *mutex) +{ + pthread_t curthread; + int ret; + + curthread = _get_curthread(); + GIANT_LOCK(curthread); + if (*mutex == NULL) + ret = pthread_mutex_init(mutex, NULL); + else + ret = 0; + GIANT_UNLOCK(curthread); + return (ret); +} + +static int +init_static_private(pthread_mutex_t *mutex) +{ + pthread_t curthread; + int ret; + + curthread = _get_curthread(); + GIANT_LOCK(curthread); + if (*mutex == NULL) + ret = pthread_mutex_init(mutex, &static_mattr); + else + ret = 0; + GIANT_UNLOCK(curthread); + return(ret); +} + +static int +mutex_trylock_common(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int error; + + PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL), + "Uninitialized mutex in pthread_mutex_trylock_common"); + + /* + * Attempt to obtain the lock. + */ + if ((error = umtx_trylock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) { + (*mutex)->m_owner = curthread; + TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe); + + return (0); + } + /* The lock was invalid. */ + if (error != EBUSY) + abort(); + + if ((*mutex)->m_owner == curthread) { + if ((*mutex)->m_attr.m_type == PTHREAD_MUTEX_RECURSIVE) { + (*mutex)->m_count++; + return (0); + } else + return (EDEADLK); + } + + return (error); +} + +int +__pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + int ret; + + if (mutex == NULL) + return (EINVAL); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if ((*mutex == NULL) && (ret = init_static(mutex)) != 0) + return (ret); + + + return (mutex_trylock_common(mutex)); +} + +int +_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + int ret; + + if (mutex == NULL) + return (EINVAL); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking the mutex private (delete safe): + */ + if ((*mutex == NULL) && (ret = init_static_private(mutex)) != 0) + return (ret); + + return (mutex_trylock_common(mutex)); +} + +static int +mutex_lock_common(pthread_mutex_t * mutex) +{ + struct pthread *curthread = _get_curthread(); + int giant_count; + int error; + + PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL), + "Uninitialized mutex in pthread_mutex_trylock_common"); + + /* + * Obtain the lock. + */ + if ((error = umtx_trylock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) { + (*mutex)->m_owner = curthread; + TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe); + + return (0); + } + /* The lock was invalid. */ + if (error != EBUSY) + abort(); + + if ((*mutex)->m_owner == curthread) { + if ((*mutex)->m_attr.m_type == PTHREAD_MUTEX_RECURSIVE) { + (*mutex)->m_count++; + + return (0); + } else + return (EDEADLK); + } + + /* + * Lock Giant so we can save the recursion count and set our + * state. Then we'll call into the kernel to block on this mutex. + */ + + GIANT_LOCK(curthread); + PTHREAD_SET_STATE(curthread, PS_MUTEX_WAIT); + if (_giant_count != 1) + abort(); + giant_count = _giant_count; + + /* + * This will unwind all references. + */ + _giant_count = 1; + GIANT_UNLOCK(curthread); + + if ((error = umtx_lock(&(*mutex)->m_mtx, curthread->thr_id)) == 0) { + (*mutex)->m_owner = curthread; + TAILQ_INSERT_TAIL(&curthread->mutexq, *mutex, m_qe); + } else + _thread_printf(0, "umtx_lock(%d)\n", error); + + /* + * Set our state and restore our recursion count. + */ + GIANT_LOCK(curthread); + PTHREAD_SET_STATE(curthread, PS_RUNNING); + + giant_count = _giant_count; + GIANT_UNLOCK(curthread); + + return (error); +} + +int +__pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int ret; + + if (_thread_initial == NULL) + _thread_init(); + + if (mutex == NULL) + return (EINVAL); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + if ((*mutex == NULL) && ((ret = init_static(mutex)) != 0)) + return (ret); + + return (mutex_lock_common(mutex)); +} + +int +_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int ret = 0; + + if (_thread_initial == NULL) + _thread_init(); + + if (mutex == NULL) + return (EINVAL); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + if ((*mutex == NULL) && ((ret = init_static_private(mutex)) != 0)) + return (ret); + + return (mutex_lock_common(mutex)); +} + + +int +_mutex_cv_unlock(pthread_mutex_t * mutex) +{ + int ret; + + if ((ret = pthread_mutex_unlock(mutex)) == 0) + (*mutex)->m_refcount++; + + return (ret); +} + +int +_mutex_cv_lock(pthread_mutex_t * mutex) +{ + int ret; + + + if ((ret = pthread_mutex_lock(mutex)) == 0) + (*mutex)->m_refcount--; + + return (ret); +} + +int +_pthread_mutex_unlock(pthread_mutex_t * mutex) +{ + struct pthread *curthread = _get_curthread(); + thr_id_t sav; + int ret = 0; + + if (mutex == NULL || *mutex == NULL) + return (EINVAL); + + if ((*mutex)->m_owner != curthread) + return (EPERM); + + if ((*mutex)->m_count != 0) { + (*mutex)->m_count--; + return (0); + } + + TAILQ_REMOVE(&curthread->mutexq, *mutex, m_qe); + (*mutex)->m_owner = NULL; + + sav = (*mutex)->m_mtx.u_owner; + ret = umtx_unlock(&(*mutex)->m_mtx, curthread->thr_id); + if (ret) { + _thread_printf(0, "umtx_unlock(%d)", ret); + _thread_printf(0, "%x : %x : %x\n", curthread, (*mutex)->m_mtx.u_owner, sav); + } + + return (ret); +} + +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_attr.m_flags & MUTEX_FLAGS_PRIVATE) != 0) + pthread_mutex_unlock(&m); + } +} diff --git a/lib/libthr/thread/thr_mutex_prioceiling.c b/lib/libthr/thread/thr_mutex_prioceiling.c new file mode 100644 index 0000000..4d50038 --- /dev/null +++ b/lib/libthr/thread/thr_mutex_prioceiling.c @@ -0,0 +1,122 @@ +/* + * 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) +{ + return (EINVAL); +#if 0 + 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); +#endif +} + +int +_pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) +{ + return (EINVAL); +#if 0 + int ret; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_attr.m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + ret = (*mutex)->m_attr.m_prio; + + return (ret); +#endif +} + +int +_pthread_mutex_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) +{ + return (EINVAL); +#if 0 + int ret = 0; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else { + /* Lock the mutex: */ + if ((ret = pthread_mutex_lock(mutex)) == 0) { + /* Return the old ceiling and set the new ceiling: */ + *old_ceiling = (*mutex)->m_prio; + (*mutex)->m_prio = prioceiling; + + /* Unlock the mutex: */ + ret = pthread_mutex_unlock(mutex); + } + } + return(ret); +#endif +} diff --git a/lib/libthr/thread/thr_mutex_protocol.c b/lib/libthr/thread/thr_mutex_protocol.c new file mode 100644 index 0000000..f7be5a6 --- /dev/null +++ b/lib/libthr/thread/thr_mutex_protocol.c @@ -0,0 +1,70 @@ +/* + * 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 = PTHREAD_MAX_PRIORITY; + } + return(ret); +} + diff --git a/lib/libthr/thread/thr_mutexattr_destroy.c b/lib/libthr/thread/thr_mutexattr_destroy.c new file mode 100644 index 0000000..b9852b5 --- /dev/null +++ b/lib/libthr/thread/thr_mutexattr_destroy.c @@ -0,0 +1,53 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy); + +int +_pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c new file mode 100644 index 0000000..cef478d --- /dev/null +++ b/lib/libthr/thread/thr_once.c @@ -0,0 +1,53 @@ +/* + * 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" + +__weak_reference(_pthread_once, pthread_once); + +int +_pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) +{ + if (once_control->state == PTHREAD_NEEDS_INIT) { + if (_thread_initial == NULL) + _thread_init(); + pthread_mutex_lock(&(once_control->mutex)); + if (once_control->state == PTHREAD_NEEDS_INIT) { + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + } + pthread_mutex_unlock(&(once_control->mutex)); + } + return (0); +} diff --git a/lib/libthr/thread/thr_printf.c b/lib/libthr/thread/thr_printf.c new file mode 100644 index 0000000..0da9ae5 --- /dev/null +++ b/lib/libthr/thread/thr_printf.c @@ -0,0 +1,124 @@ +/*- + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <stdarg.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[10]; + char *s; + unsigned r, u; + int c, d; + + va_start(ap, fmt); + while ((c = *fmt++)) { + if (c == '%') { + c = *fmt++; + switch (c) { + case 'c': + pchar(fd, va_arg(ap, int)); + continue; + case 's': + pstr(fd, va_arg(ap, char *)); + continue; + case 'd': + case 'u': + case 'p': + case 'x': + r = ((c == 'u') || (c == 'd')) ? 10 : 16; + if (c == 'd') { + d = va_arg(ap, unsigned); + if (d < 0) { + pchar(fd, '-'); + u = (unsigned)(d * -1); + } else + u = (unsigned)d; + } 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); + } + va_end(ap); +} + +/* + * Write a single character to stdout, in a thread-safe manner. + */ +static void +pchar(int fd, char c) +{ + + write(fd, &c, 1); +} + +/* + * Write a string to stdout, in a thread-safe manner. + */ +static void +pstr(int fd, const char *s) +{ + + 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..8a31ffa --- /dev/null +++ b/lib/libthr/thread/thr_private.h @@ -0,0 +1,804 @@ +/* + * 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. + * + * Private thread definitions for the uthread kernel. + * + * $FreeBSD$ + */ + +#ifndef _THR_PRIVATE_H +#define _THR_PRIVATE_H + +/* + * Evaluate the storage class specifier. + */ +#ifdef GLOBAL_PTHREAD_PRIVATE +#define SCLASS +#else +#define SCLASS extern +#endif + +/* + * Include files. + */ +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/queue.h> +#include <pthread_np.h> +#include <sched.h> +#include <signal.h> +#include <spinlock.h> +#include <stdio.h> +#include <ucontext.h> + +#include <machine/atomic.h> +#include <sys/thr.h> +#include <sys/umtx.h> + +/* + * 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) + +/* + * State change macro without scheduling queue change: + */ +#define PTHREAD_SET_STATE(thrd, newstate) do { \ + (thrd)->state = newstate; \ + (thrd)->fname = __FILE__; \ + (thrd)->lineno = __LINE__; \ +} while (0) + +/* + * State change macro with scheduling queue change - This must be + * called with GIANT held. + */ +#if defined(_PTHREADS_INVARIANTS) +#include <assert.h> +#define PTHREAD_ASSERT(cond, msg) do { \ + if (!(cond)) \ + PANIC(msg); \ +} while (0) +#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) \ + PTHREAD_ASSERT((((thrd)->flags & PTHREAD_FLAGS_IN_SYNCQ) == 0), \ + "Illegal call from signal handler"); +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_SET_STATE(thrd, newstate); \ + } else if (newstate == PS_RUNNING) { \ + if (thr_kill(thrd->thr_id, SIGTHR)) \ + abort(); \ + PTHREAD_SET_STATE(thrd, newstate); \ + } \ + } \ +} while (0) +#else +#define PTHREAD_ASSERT(cond, msg) +#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if (thr_kill(thrd->thr_id, SIGTHR)) \ + abort(); \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#if 0 +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + } else if (newstate == PS_RUNNING) { \ + if (thr_kill(thrd->thr_id, SIGTHR)) \ + abort(); \ + } \ + } \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#endif +#endif + + +/* + * TailQ initialization values. + */ +#define TAILQ_INITIALIZER { NULL, NULL } + +#define UMTX_INITIALIZER { NULL, NULL } + +struct pthread_mutex_attr { + enum pthread_mutextype m_type; + int m_protocol; + int m_ceiling; + long m_flags; +}; + +/* + * Static mutex initialization values. + */ + +#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \ + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE } + +#define PTHREAD_MUTEX_STATIC_INITIALIZER \ + { PTHREAD_MUTEXATTR_STATIC_INITIALIZER, UMTX_INITIALIZER, NULL, \ + 0, 0, TAILQ_INITIALIZER } + +struct pthread_mutex { + struct pthread_mutex_attr m_attr; /* Mutex attributes. */ + struct umtx m_mtx; /* Mutex. */ + struct pthread *m_owner; /* Current owner. */ + int m_count; /* Recursion count. */ + int m_refcount; /* Reference count. */ + TAILQ_ENTRY(pthread_mutex) m_qe; /* All locks held. */ +}; + +/* + * Flags for mutexes. + */ +#define MUTEX_FLAGS_PRIVATE 0x01 +#define MUTEX_FLAGS_INITED 0x02 +#define MUTEX_FLAGS_BUSY 0x04 + +/* + * Condition variable definitions. + */ +enum pthread_cond_type { + COND_TYPE_FAST, + COND_TYPE_MAX +}; + +struct pthread_cond { + enum pthread_cond_type c_type; + TAILQ_HEAD(cond_head, pthread) c_queue; + pthread_mutex_t c_mutex; + void *c_data; + long c_flags; + int c_seqno; + + /* + * Lock for accesses to this structure. + */ + struct umtx c_lock; +}; + +struct pthread_cond_attr { + enum pthread_cond_type c_type; + long c_flags; +}; + +/* + * Flags for condition variables. + */ +#define COND_FLAGS_INITED 0x01 + +/* + * Static cond initialization values. + */ +#define PTHREAD_COND_STATIC_INITIALIZER \ + { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \ + 0, 0, UMTX_INITIALIZER } + +/* + * Semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +}; + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { + struct pthread_cleanup *next; + void (*routine) (); + void *routine_arg; +}; + +struct pthread_attr { + int sched_policy; + int sched_inherit; + int sched_interval; + int prio; + int suspend; + int flags; + void *arg_attr; + void (*cleanup_attr) (); + void *stackaddr_attr; + size_t stacksize_attr; + size_t guardsize_attr; +}; + +/* + * Thread creation state attributes. + */ +#define PTHREAD_CREATE_RUNNING 0 +#define PTHREAD_CREATE_SUSPENDED 1 + +/* + * Miscellaneous definitions. + */ +#define PTHREAD_STACK_DEFAULT 65536 +/* + * Size of default red zone at the end of each stack. In actuality, this "red + * zone" is merely an unmapped region, except in the case of the initial stack. + * Since mmap() makes it possible to specify the maximum growth of a MAP_STACK + * region, an unmapped gap between thread stacks achieves the same effect as + * explicitly mapped red zones. + * This is declared and initialized in uthread_init.c. + */ +extern int _pthread_guard_default; + +extern int _pthread_page_size; + +/* + * 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 PTHREAD_STACK_INITIAL 0x100000 + +/* + * Define the different priority ranges. All applications have thread + * priorities constrained within 0-31. The threads library raises the + * priority when delivering signals in order to ensure that signal + * delivery happens (from the POSIX spec) "as soon as possible". + * In the future, the threads library will also be able to map specific + * threads into real-time (cooperating) processes or kernel threads. + * The RT and SIGNAL priorities will be used internally and added to + * thread base priorities so that the scheduling queue can handle both + * normal and RT priority threads with and without signal handling. + * + * The approach taken is that, within each class, signal delivery + * always has priority over thread execution. + */ +#define PTHREAD_DEFAULT_PRIORITY 15 +#define PTHREAD_MIN_PRIORITY 0 +#define PTHREAD_MAX_PRIORITY 31 /* 0x1F */ +#define PTHREAD_SIGNAL_PRIORITY 32 /* 0x20 */ +#define PTHREAD_RT_PRIORITY 64 /* 0x40 */ +#define PTHREAD_FIRST_PRIORITY PTHREAD_MIN_PRIORITY +#define PTHREAD_LAST_PRIORITY \ + (PTHREAD_MAX_PRIORITY + PTHREAD_SIGNAL_PRIORITY + PTHREAD_RT_PRIORITY) +#define PTHREAD_BASE_PRIORITY(prio) ((prio) & PTHREAD_MAX_PRIORITY) + +/* + * Clock resolution in microseconds. + */ +#define CLOCK_RES_USEC 10000 +#define CLOCK_RES_USEC_MIN 1000 + +/* + * Time slice period in microseconds. + */ +#define TIMESLICE_USEC 20000 + +/* + * XXX Define a thread-safe macro to get the current time of day + * which is updated at regular intervals by the scheduling signal + * handler. + */ +#define GET_CURRENT_TOD(tv) gettimeofday(&(tv), NULL) + + +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_rwlock { + pthread_mutex_t lock; /* monitor lock */ + int state; /* 0 = idle >0 = # of readers -1 = writer */ + pthread_cond_t read_signal; + pthread_cond_t write_signal; + int blocked_writers; +}; + +/* + * Thread states. + */ +enum pthread_state { + PS_RUNNING, + PS_MUTEX_WAIT, + PS_COND_WAIT, + PS_SLEEP_WAIT, /* XXX We need to wrap syscalls to set this state */ + PS_WAIT_WAIT, + PS_JOIN, + PS_DEAD, + PS_DEADLOCK, + PS_STATE_MAX +}; + + +/* + * File descriptor locking definitions. + */ +#define FD_READ 0x1 +#define FD_WRITE 0x2 +#define FD_RDWR (FD_READ | FD_WRITE) + +union pthread_wait_data { + pthread_mutex_t mutex; + pthread_cond_t cond; + spinlock_t *spinlock; + struct pthread *thread; +}; + +struct join_status { + struct pthread *thread; + void *ret; + int error; +}; + +struct pthread_state_data { + union pthread_wait_data psd_wait_data; + enum pthread_state psd_state; + int psd_flags; +}; + +struct pthread_specific_elem { + const void *data; + int seqno; +}; + +/* + * Thread structure. + */ +struct pthread { + /* + * Magic value to help recognize a valid thread structure + * from an invalid one: + */ +#define PTHREAD_MAGIC ((u_int32_t) 0xd09ba115) + u_int32_t magic; + char *name; + u_int64_t uniqueid; /* for gdb */ + thr_id_t thr_id; + + /* + * Lock for accesses to this thread structure. + */ + spinlock_t lock; + + /* Queue entry for list of all threads: */ + TAILQ_ENTRY(pthread) tle; + + /* Queue entry for list of dead threads: */ + TAILQ_ENTRY(pthread) dle; + + /* + * Thread start routine, argument, stack pointer and thread + * attributes. + */ + void *(*start_routine)(void *); + void *arg; + void *stack; + struct pthread_attr attr; + + /* + * Machine context, including signal state. + */ + ucontext_t ctx; + + /* + * Cancelability flags - the lower 2 bits are used by cancel + * definitions in pthread.h + */ +#define PTHREAD_AT_CANCEL_POINT 0x0004 +#define PTHREAD_CANCELLING 0x0008 + + /* + * Protected by Giant. + */ + int cancelflags; + + /* Thread state: */ + enum pthread_state 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; + struct join_status join_status; + + /* + * A thread can belong to: + * + * o A queue of threads waiting for a mutex + * o A queue of threads waiting for a condition variable + * + * A thread can also be joining a thread (the joiner field above). + * + * It must not be possible for a thread to belong to any of the + * above queues while it is handling a signal. Signal handlers + * may longjmp back to previous stack frames circumventing normal + * control flow. This could corrupt queue integrity if the thread + * retains membership in the queue. Therefore, if a thread is a + * member of one of these queues when a signal handler is invoked, + * it must remove itself from the queue before calling the signal + * handler and reinsert itself after normal return of the handler. + * + * Use sqe for synchronization (mutex and condition variable) queue + * links. + */ + TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */ + + /* Wait data. */ + union pthread_wait_data data; + + /* Miscellaneous flags; only set with signals deferred. */ + int flags; +#define PTHREAD_FLAGS_PRIVATE 0x0001 +#define PTHREAD_EXITING 0x0002 +#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ +#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ +#define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */ +#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */ +#define PTHREAD_FLAGS_IN_SYNCQ \ + (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) + + /* + * Base priority is the user setable and retrievable priority + * of the thread. It is only affected by explicit calls to + * set thread priority and upon thread creation via a thread + * attribute or default priority. + */ + char base_priority; + + /* + * Inherited priority is the priority a thread inherits by + * taking a priority inheritence or protection mutex. It + * is not affected by base priority changes. Inherited + * priority defaults to and remains 0 until a mutex is taken + * that is being waited on by any other thread whose priority + * is non-zero. + */ + char inherited_priority; + + /* + * Active priority is always the maximum of the threads base + * priority and inherited priority. When there is a change + * in either the base or inherited priority, the active + * priority must be recalculated. + */ + char active_priority; + + /* Number of priority ceiling or protection mutexes owned. */ + int priority_mutex_count; + + /* + * Queue of currently owned mutexes. + */ + TAILQ_HEAD(, pthread_mutex) mutexq; + + void *ret; + struct pthread_specific_elem *specific; + int specific_data_count; + + /* + * Architecture specific id field used for _{get, set}_curthread() + * interface. + */ + void *arch_id; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; + char *fname; /* Ptr to source file name */ + int lineno; /* Source line number. */ +}; + +/* + * Global variables for the uthread kernel. + */ + +SCLASS void *_usrstack +#ifdef GLOBAL_PTHREAD_PRIVATE += (void *) USRSTACK; +#else +; +#endif + +/* List of all threads: */ +SCLASS TAILQ_HEAD(, pthread) _thread_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_thread_list); +#else +; +#endif + +/* Dead threads: */ +SCLASS TAILQ_HEAD(, pthread) _dead_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_dead_list); +#else +; +#endif + +/* Initial thread: */ +SCLASS struct pthread *_thread_initial +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Default thread attributes: */ +SCLASS struct pthread_attr pthread_attr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { SCHED_RR, 0, TIMESLICE_USEC, PTHREAD_DEFAULT_PRIORITY, + PTHREAD_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, + PTHREAD_STACK_DEFAULT, -1 }; +#else +; +#endif + +/* Default mutex attributes: */ +SCLASS struct pthread_mutex_attr pthread_mutexattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }; +#else +; +#endif + +/* Default condition variable attributes: */ +SCLASS struct pthread_cond_attr pthread_condattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { COND_TYPE_FAST, 0 }; +#else +; +#endif + +SCLASS int _clock_res_usec /* Clock resolution in usec. */ +#ifdef GLOBAL_PTHREAD_PRIVATE += CLOCK_RES_USEC; +#else +; +#endif + +/* Giant lock. */ +SCLASS struct umtx _giant_mutex +#ifdef GLOBAL_PTHREAD_PRIVATE += UMTX_INITIALIZER +#endif +; + +SCLASS int _giant_count; + +/* Garbage collector mutex and condition variable. */ +SCLASS pthread_mutex_t _gc_mutex +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; +SCLASS pthread_cond_t _gc_cond +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + +/* + * Array of signal actions for this process. + */ +SCLASS struct sigaction _thread_sigact[NSIG]; + +/* Tracks the number of threads blocked while waiting for a spinlock. */ +SCLASS volatile int _spinblock_count +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* + * And, should we climb the beanstalk, + * We'll meet his brother, Giant. + */ +void GIANT_LOCK(pthread_t curthread); +void GIANT_UNLOCK(pthread_t curthread); + +/* Undefine the storage class specifier: */ +#undef SCLASS + +/* + * Function prototype definitions. + */ +__BEGIN_DECLS +char *__ttyname_basic(int); +char *__ttyname_r_basic(int, char *, size_t); +char *ttyname_r(int, char *, size_t); +void _cond_wait_backout(pthread_t); +int _find_thread(pthread_t); +struct pthread *_get_curthread_slow(void); +struct pthread *_get_curthread(void); +void *_set_curthread(struct pthread *); +void _retire_thread(void *arch_id); +void *_thread_stack_alloc(size_t, size_t); +void _thread_stack_free(void *, size_t, size_t); +int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); +int _mutex_cv_lock(pthread_mutex_t *); +int _mutex_cv_unlock(pthread_mutex_t *); +void _mutex_lock_backout(pthread_t); +void _mutex_notify_priochange(pthread_t); +int _mutex_reinit(pthread_mutex_t *); +void _mutex_unlock_private(pthread_t); +int _cond_reinit(pthread_cond_t *); +void *_pthread_getspecific(pthread_key_t); +int _pthread_key_create(pthread_key_t *, void (*) (void *)); +int _pthread_key_delete(pthread_key_t); +int _pthread_mutex_destroy(pthread_mutex_t *); +int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); +int _pthread_mutex_lock(pthread_mutex_t *); +int _pthread_mutex_trylock(pthread_mutex_t *); +int _pthread_mutex_unlock(pthread_mutex_t *); +int _pthread_mutexattr_init(pthread_mutexattr_t *); +int _pthread_mutexattr_destroy(pthread_mutexattr_t *); +int _pthread_mutexattr_settype(pthread_mutexattr_t *, int); +int _pthread_once(pthread_once_t *, void (*) (void)); +pthread_t _pthread_self(void); +int _pthread_setspecific(pthread_key_t, const void *); +void _thread_exit(char *, int, char *); +void _thread_exit_cleanup(void); +void *_thread_cleanup(pthread_t); +void _thread_cleanupspecific(void); +void _thread_dump_info(void); +void _thread_init(void); +void _thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context); +void _thread_printf(int fd, const char *, ...); +void _thread_start(void); +void _thread_seterrno(pthread_t, int); +pthread_addr_t _thread_gc(pthread_addr_t); +void _thread_enter_cancellation_point(void); +void _thread_leave_cancellation_point(void); +void _thread_cancellation_point(void); +int _thread_suspend(pthread_t thread, struct timespec *abstime); + +/* #include <sys/aio.h> */ +#ifdef _SYS_AIO_H_ +int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); +#endif + +/* #include <sys/event.h> */ +#ifdef _SYS_EVENT_H_ +int __sys_kevent(int, const struct kevent *, int, struct kevent *, + int, const struct timespec *); +#endif + +/* #include <sys/ioctl.h> */ +#ifdef _SYS_IOCTL_H_ +int __sys_ioctl(int, unsigned long, ...); +#endif + +/* #include <sys/mman.h> */ +#ifdef _SYS_MMAN_H_ +int __sys_msync(void *, size_t, int); +#endif + +/* #include <sys/mount.h> */ +#ifdef _SYS_MOUNT_H_ +int __sys_fstatfs(int, struct statfs *); +#endif + +/* #include <sys/socket.h> */ +#ifdef _SYS_SOCKET_H_ +int __sys_accept(int, struct sockaddr *, socklen_t *); +int __sys_bind(int, const struct sockaddr *, socklen_t); +int __sys_connect(int, const struct sockaddr *, socklen_t); +int __sys_getpeername(int, struct sockaddr *, socklen_t *); +int __sys_getsockname(int, struct sockaddr *, socklen_t *); +int __sys_getsockopt(int, int, int, void *, socklen_t *); +int __sys_listen(int, int); +ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); +ssize_t __sys_recvmsg(int, struct msghdr *, int); +int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int); +ssize_t __sys_sendmsg(int, const struct msghdr *, int); +ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); +int __sys_setsockopt(int, int, int, const void *, socklen_t); +int __sys_shutdown(int, int); +int __sys_socket(int, int, int); +int __sys_socketpair(int, int, int, int *); +#endif + +/* #include <sys/stat.h> */ +#ifdef _SYS_STAT_H_ +int __sys_fchflags(int, u_long); +int __sys_fchmod(int, mode_t); +int __sys_fstat(int, struct stat *); +#endif + +/* #include <sys/uio.h> */ +#ifdef _SYS_UIO_H_ +ssize_t __sys_readv(int, const struct iovec *, int); +ssize_t __sys_writev(int, const struct iovec *, int); +#endif + +/* #include <sys/wait.h> */ +#ifdef WNOHANG +pid_t __sys_wait4(pid_t, int *, int, struct rusage *); +#endif + +/* #include <dirent.h> */ +#ifdef _DIRENT_H_ +int __sys_getdirentries(int, char *, int, long *); +#endif + +/* #include <fcntl.h> */ +#ifdef _SYS_FCNTL_H_ +int __sys_fcntl(int, int, ...); +int __sys_flock(int, int); +int __sys_open(const char *, int, ...); +#endif + +/* #include <poll.h> */ +#ifdef _SYS_POLL_H_ +int __sys_poll(struct pollfd *, unsigned, int); +#endif + +/* #include <signal.h> */ +#ifdef _SIGNAL_H_ +int __sys_sigaction(int, const struct sigaction *, struct sigaction *); +int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); +int __sys_sigprocmask(int, const sigset_t *, sigset_t *); +int __sys_sigreturn(ucontext_t *); +#endif + +/* #include <unistd.h> */ +#ifdef _UNISTD_H_ +int __sys_close(int); +int __sys_dup(int); +int __sys_dup2(int, int); +int __sys_execve(const char *, char * const *, char * const *); +void __sys_exit(int); +int __sys_fchown(int, uid_t, gid_t); +pid_t __sys_fork(void); +long __sys_fpathconf(int, int); +int __sys_fsync(int); +int __sys_pipe(int *); +ssize_t __sys_read(int, void *, size_t); +ssize_t __sys_write(int, const void *, size_t); +#endif + +__END_DECLS + +#endif /* !_PTHREAD_PRIVATE_H */ diff --git a/lib/libthr/thread/thr_resume_np.c b/lib/libthr/thread/thr_resume_np.c new file mode 100644 index 0000000..783c45f --- /dev/null +++ b/lib/libthr/thread/thr_resume_np.c @@ -0,0 +1,87 @@ +/* + * 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 <errno.h> +#include <pthread.h> +#include "thr_private.h" + +static void resume_common(struct pthread *); + +__weak_reference(_pthread_resume_np, pthread_resume_np); +__weak_reference(_pthread_resume_all_np, pthread_resume_all_np); + +/* Resume a thread: */ +int +_pthread_resume_np(pthread_t thread) +{ + int ret; + + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(thread)) == 0) { + pthread_t curthread; + + curthread = _get_curthread(); + GIANT_LOCK(curthread); + + if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) + resume_common(thread); + + GIANT_UNLOCK(curthread); + } + return (ret); +} + +void +_pthread_resume_all_np(void) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *thread; + + GIANT_LOCK(curthread); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if ((thread != curthread) && + ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)) + resume_common(thread); + } + + GIANT_UNLOCK(curthread); +} + +static void +resume_common(struct pthread *thread) +{ + thread->flags &= ~PTHREAD_FLAGS_SUSPENDED; + if (thr_kill(thread->thr_id, SIGTHR)) + abort(); +} diff --git a/lib/libthr/thread/thr_rwlock.c b/lib/libthr/thread/thr_rwlock.c new file mode 100644 index 0000000..f41e8a2 --- /dev/null +++ b/lib/libthr/thread/thr_rwlock.c @@ -0,0 +1,341 @@ +/*- + * 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 <pthread.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_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); + +static int init_static (pthread_rwlock_t *rwlock); + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static int +init_static (pthread_rwlock_t *rwlock) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*rwlock == NULL) + ret = pthread_rwlock_init(rwlock, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +int +_pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int ret; + + if (rwlock == NULL) + ret = EINVAL; + else { + pthread_rwlock_t prwlock; + + prwlock = *rwlock; + + pthread_mutex_destroy(&prwlock->lock); + pthread_cond_destroy(&prwlock->read_signal); + pthread_cond_destroy(&prwlock->write_signal); + free(prwlock); + + *rwlock = NULL; + + ret = 0; + } + + return(ret); +} + +int +_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + pthread_rwlock_t prwlock; + int ret; + + /* allocate rwlock object */ + prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock)); + + if (prwlock == NULL) + return(ENOMEM); + + /* initialize the lock */ + if ((ret = pthread_mutex_init(&prwlock->lock, NULL)) != 0) + free(prwlock); + else { + /* initialize the read condition signal */ + ret = pthread_cond_init(&prwlock->read_signal, NULL); + + if (ret != 0) { + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* initialize the write condition signal */ + ret = pthread_cond_init(&prwlock->write_signal, NULL); + + if (ret != 0) { + pthread_cond_destroy(&prwlock->read_signal); + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* success */ + prwlock->state = 0; + prwlock->blocked_writers = 0; + + *rwlock = prwlock; + } + } + } + + return(ret); +} + +int +_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + ret = pthread_cond_wait(&prwlock->read_signal, &prwlock->lock); + + if (ret != 0) { + /* can't do a whole lot if this fails */ + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + } + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + if (prwlock->blocked_writers || prwlock->state < 0) + ret = EBUSY; + else if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; /* too many read locks acquired */ + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state != 0) + ret = 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) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state > 0) { + if (--prwlock->state == 0 && prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + else + ret = pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + while (prwlock->state != 0) { + ++prwlock->blocked_writers; + + ret = pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); + + if (ret != 0) { + --prwlock->blocked_writers; + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + + --prwlock->blocked_writers; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + diff --git a/lib/libthr/thread/thr_rwlockattr.c b/lib/libthr/thread/thr_rwlockattr.c new file mode 100644 index 0000000..8c0697b --- /dev/null +++ b/lib/libthr/thread/thr_rwlockattr.c @@ -0,0 +1,98 @@ +/*- + * 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 <stdlib.h> + +#include <pthread.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..d213e5e --- /dev/null +++ b/lib/libthr/thread/thr_self.c @@ -0,0 +1,44 @@ +/* + * 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" + +__weak_reference(_pthread_self, pthread_self); + +pthread_t +_pthread_self(void) +{ + /* 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..17059e3 --- /dev/null +++ b/lib/libthr/thread/thr_sem.c @@ -0,0 +1,257 @@ +/* + * 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 <stdlib.h> +#include <errno.h> +#include <semaphore.h> +#include <pthread.h> +#include "thr_private.h" + +#define _SEM_CHECK_VALIDITY(sem) \ + if ((*(sem))->magic != SEM_MAGIC) { \ + errno = EINVAL; \ + retval = -1; \ + goto RETURN; \ + } + +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_open, sem_open); +__weak_reference(_sem_close, sem_close); +__weak_reference(_sem_unlink, sem_unlink); +__weak_reference(_sem_wait, sem_wait); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_post, sem_post); +__weak_reference(_sem_getvalue, sem_getvalue); + + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + int retval; + + /* + * Range check the arguments. + */ + if (pshared != 0) { + /* + * The user wants a semaphore that can be shared among + * processes, which this implementation can't do. Sounds like a + * permissions problem to me (yeah right). + */ + errno = EPERM; + retval = -1; + goto RETURN; + } + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + retval = -1; + goto RETURN; + } + + *sem = (sem_t)malloc(sizeof(struct sem)); + if (*sem == NULL) { + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + /* + * Initialize the semaphore. + */ + if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { + pthread_mutex_destroy(&(*sem)->lock); + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + (*sem)->count = (u_int32_t)value; + (*sem)->nwaiters = 0; + (*sem)->magic = SEM_MAGIC; + + retval = 0; + RETURN: + return retval; +} + +int +_sem_destroy(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + /* Make sure there are no waiters. */ + pthread_mutex_lock(&(*sem)->lock); + if ((*sem)->nwaiters > 0) { + pthread_mutex_unlock(&(*sem)->lock); + errno = EBUSY; + retval = -1; + goto RETURN; + } + pthread_mutex_unlock(&(*sem)->lock); + + pthread_mutex_destroy(&(*sem)->lock); + pthread_cond_destroy(&(*sem)->gtzero); + (*sem)->magic = 0; + + free(*sem); + + retval = 0; + RETURN: + return retval; +} + +sem_t * +_sem_open(const char *name, int oflag, ...) +{ + errno = ENOSYS; + return SEM_FAILED; +} + +int +_sem_close(sem_t *sem) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_wait(sem_t *sem) +{ + int retval; + + _thread_enter_cancellation_point(); + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + while ((*sem)->count == 0) { + (*sem)->nwaiters++; + pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); + (*sem)->nwaiters--; + } + (*sem)->count--; + + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + _thread_leave_cancellation_point(); + return retval; +} + +int +_sem_trywait(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + if ((*sem)->count > 0) { + (*sem)->count--; + retval = 0; + } else { + errno = EAGAIN; + retval = -1; + } + + pthread_mutex_unlock(&(*sem)->lock); + + RETURN: + return retval; +} + +int +_sem_post(sem_t *sem) +{ + pthread_t curthread; + int retval; + + _SEM_CHECK_VALIDITY(sem); + + curthread = _get_curthread(); + /* + * sem_post() is required to be safe to call from within signal + * handlers. Thus, we must defer signals. + */ + pthread_mutex_lock(&(*sem)->lock); + + /* GIANT_LOCK(curthread); */ + + (*sem)->count++; + if ((*sem)->nwaiters > 0) + pthread_cond_signal(&(*sem)->gtzero); + + /* GIANT_UNLOCK(curthread); */ + + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + return retval; +} + +int +_sem_getvalue(sem_t *sem, int *sval) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + *sval = (int)(*sem)->count; + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + return retval; +} diff --git a/lib/libthr/thread/thr_seterrno.c b/lib/libthr/thread/thr_seterrno.c new file mode 100644 index 0000000..ec801d6 --- /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. + */ +#ifdef errno +#undef errno +#endif +extern int errno; + +void +_thread_seterrno(pthread_t thread, int error) +{ + /* Check for the initial thread: */ + if (thread == _thread_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..c5a9506 --- /dev/null +++ b/lib/libthr/thread/thr_setprio.c @@ -0,0 +1,52 @@ +/* + * 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" + +__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..f9551e0 --- /dev/null +++ b/lib/libthr/thread/thr_setschedparam.c @@ -0,0 +1,115 @@ +/* + * 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 <errno.h> +#include <sys/param.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_setschedparam, pthread_setschedparam); + +int +_pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ +#if 0 /* XXXTHR */ + int old_prio, in_readyq = 0, ret = 0; +#endif + + if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) + return (EINVAL); + + if ((param->sched_priority < PTHREAD_MIN_PRIORITY) || + (param->sched_priority > PTHREAD_MAX_PRIORITY)) + return (ENOTSUP); + + return (0); +#if 0 /* XXXTHR */ + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(pthread)) == 0) { + GIANT_LOCK(); + + if (param->sched_priority != + PTHREAD_BASE_PRIORITY(pthread->base_priority)) { + /* + * Remove the thread from its current priority + * queue before any adjustments are made to its + * active priority: + */ + old_prio = pthread->active_priority; + if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { + in_readyq = 1; + PTHREAD_PRIOQ_REMOVE(pthread); + } + + /* Set the thread base priority: */ + pthread->base_priority &= + (PTHREAD_SIGNAL_PRIORITY | PTHREAD_RT_PRIORITY); + pthread->base_priority = param->sched_priority; + + /* Recalculate the active priority: */ + pthread->active_priority = MAX(pthread->base_priority, + pthread->inherited_priority); + + if (in_readyq) { + if ((pthread->priority_mutex_count > 0) && + (old_prio > pthread->active_priority)) { + /* + * POSIX states that if the priority is + * being lowered, the thread must be + * inserted at the head of the queue for + * its priority if it owns any priority + * protection or inheritence mutexes. + */ + PTHREAD_PRIOQ_INSERT_HEAD(pthread); + } + else + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } + + /* + * Check for any mutex priority adjustments. This + * includes checking for a priority mutex on which + * this thread is waiting. + */ + _mutex_notify_priochange(pthread); + } + + /* Set the scheduling policy: */ + pthread->attr.sched_policy = policy; + + GIANT_UNLOCK(); + } + return(ret); +#endif +} diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c new file mode 100644 index 0000000..3aee706 --- /dev/null +++ b/lib/libthr/thread/thr_sig.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2003 Jeffrey Roberson <jeff@freebsd.org> + * Copyright (c) 2003 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 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/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <setjmp.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +/* #define DEBUG_SIGNAL */ +#ifdef DEBUG_SIGNAL +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +__weak_reference(_sigprocmask, sigprocmask); + +int +_sigprocmask(int how, const sigset_t *set, sigset_t *oset) +{ + sigset_t new; + + /* + * Make sure applications can't unblock our synchronization + * signal. We always want to take this with sigwait(). + */ + if (set != NULL) { + new = *set; + switch (how) { + case SIG_BLOCK: + case SIG_SETMASK: + SIGADDSET(new, SIGTHR); + break; + case SIG_UNBLOCK: + SIGDELSET(new, SIGTHR); + break; + default: + break; + } + set = &new; + } + + return (__sys_sigprocmask(how, set, oset)); +} + +__weak_reference(_pthread_sigmask, pthread_sigmask); + +int +_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + int error; + + /* + * This always sets the mask on the current thread. + */ + error = sigprocmask(how, set, oset); + + /* + * pthread_sigmask returns errno or success while sigprocmask returns + * -1 and sets errno. + */ + if (error == -1) + error = errno; + + return (error); +} + + +__weak_reference(_pthread_kill, pthread_kill); + +int +_pthread_kill(pthread_t pthread, int sig) +{ + + if (_thread_initial == NULL) + _thread_init(); + return (thr_kill(pthread->thr_id, sig)); +} + +/* + * User thread signal handler wrapper. + */ +void +_thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context) +{ + struct pthread_state_data psd; + struct pthread *curthread = _get_curthread(); + __siginfohandler_t *handler; + + GIANT_LOCK(curthread); + /* Save the thread's previous state. */ + curthread->data = psd.psd_wait_data; + curthread->state = psd.psd_state; + curthread->flags = psd.psd_flags; + + /* Check the threads previous state: */ + if (psd.psd_state != PS_RUNNING) { + /* + * Do a little cleanup handling for those threads in + * queues before calling the signal handler. Signals + * for these threads are temporarily blocked until + * after cleanup handling. + */ + switch (psd.psd_state) { + case PS_COND_WAIT: + _cond_wait_backout(curthread); + psd.psd_state = PS_RUNNING; + break; + + case PS_MUTEX_WAIT: + /* _mutex_lock_backout(curthread); XXXTHR */ + psd.psd_state = PS_RUNNING; + break; + + default: + break; + } + } + + if (_thread_sigact[sig -1].sa_handler != NULL) { + GIANT_UNLOCK(curthread); + handler = (__siginfohandler_t *) + _thread_sigact[sig - 1].sa_handler; + handler(sig, info, context); + GIANT_LOCK(curthread); + } + + /* Restore the signal frame. */ + psd.psd_wait_data = curthread->data; + psd.psd_state = curthread->state; + psd.psd_flags = curthread->flags & + (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE); + GIANT_UNLOCK(curthread); +} diff --git a/lib/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c new file mode 100644 index 0000000..07ef387 --- /dev/null +++ b/lib/libthr/thread/thr_spec.c @@ -0,0 +1,225 @@ +/* + * 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 <signal.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include "thr_private.h" + +struct pthread_key { + spinlock_t lock; + volatile int allocated; + volatile int count; + int seqno; + void (*destructor) (); +}; + +/* Static variables: */ +static struct pthread_key key_table[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 *)) +{ + for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[*key].lock); + + if (key_table[(*key)].allocated == 0) { + key_table[(*key)].allocated = 1; + key_table[(*key)].destructor = destructor; + key_table[(*key)].seqno++; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + return (0); + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + } + return (EAGAIN); +} + +int +_pthread_key_delete(pthread_key_t key) +{ + int ret = 0; + + if (key < PTHREAD_KEYS_MAX) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + + if (key_table[key].allocated) + key_table[key].allocated = 0; + else + ret = EINVAL; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + } else + ret = EINVAL; + return (ret); +} + +void +_thread_cleanupspecific(void) +{ + struct pthread *curthread = _get_curthread(); + void *data = NULL; + int key; + int itr; + void (*destructor)( void *); + + for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { + for (key = 0; key < PTHREAD_KEYS_MAX; key++) { + if (curthread->specific_data_count > 0) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + destructor = NULL; + + if (key_table[key].allocated && + (curthread->specific[key].data != NULL)) { + if (curthread->specific[key].seqno == + key_table[key].seqno) { + data = (void *) curthread->specific[key].data; + destructor = key_table[key].destructor; + } + curthread->specific[key].data = NULL; + curthread->specific_data_count--; + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + + /* + * If there is a destructore, call it + * with the key table entry unlocked: + */ + if (destructor) + destructor(data); + } else { + free(curthread->specific); + curthread->specific = NULL; + return; + } + } + } + if (curthread->specific != NULL) { + free(curthread->specific); + curthread->specific = NULL; + } +} + +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 (key < PTHREAD_KEYS_MAX) { + if (key_table[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 = + key_table[key].seqno; + ret = 0; + } else + ret = EINVAL; + } else + ret = EINVAL; + } else + ret = ENOMEM; + return (ret); +} + +void * +_pthread_getspecific(pthread_key_t key) +{ + struct pthread *pthread; + void *data; + + /* Point to the running thread: */ + pthread = _get_curthread(); + + /* Check if there is specific data: */ + if (pthread->specific != NULL && key < PTHREAD_KEYS_MAX) { + /* Check if this key has been used before: */ + if (key_table[key].allocated && + (pthread->specific[key].seqno == key_table[key].seqno)) { + /* Return the value: */ + data = (void *) pthread->specific[key].data; + } else { + /* + * This key has not been used before, so return NULL + * instead: + */ + data = NULL; + } + } else + /* No specific data has been created, so just return NULL: */ + data = NULL; + return (data); +} diff --git a/lib/libthr/thread/thr_spinlock.c b/lib/libthr/thread/thr_spinlock.c new file mode 100644 index 0000000..20b33f2 --- /dev/null +++ b/lib/libthr/thread/thr_spinlock.c @@ -0,0 +1,88 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <unistd.h> + +#include <libc_private.h> + +#include "thr_private.h" + +void +_spinunlock(spinlock_t *lck) +{ + struct pthread *curthread = _get_curthread(); + + if (umtx_unlock((struct umtx *)lck, curthread->thr_id)) + abort(); +} + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + */ +void +_spinlock(spinlock_t *lck) +{ + struct pthread *curthread = _get_curthread(); + + if (umtx_lock((struct umtx *)lck, curthread->thr_id)) + abort(); +} + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + * + * This function checks if the running thread has already locked the + * location, warns if this occurs and creates a thread dump before + * returning. + */ +void +_spinlock_debug(spinlock_t *lck, char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + + if (umtx_lock((struct umtx *)lck, curthread->thr_id)) + abort(); +} diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c new file mode 100644 index 0000000..c75d6ee --- /dev/null +++ b/lib/libthr/thread/thr_stack.c @@ -0,0 +1,240 @@ +/* + * 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/param.h> +#include <sys/queue.h> +#include <sys/user.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 simply left unmapped) above the top of the stack, + * such that the stack will not be able to grow all the way to the bottom of the + * next stack. This isn't fool-proof. It is possible for a stack to grow by a + * large amount, such that it grows into the next stack, and as long as the + * memory within the red zone is never accessed, nothing will prevent one thread + * stack from trouncing all over the next. + * + * low memory + * . . . . . . . . . . . . . . . . . . + * | | + * | stack 3 | start of 3rd thread stack + * +-----------------------------------+ + * | | + * | Red Zone (guard page) | red zone for 2nd thread + * | | + * +-----------------------------------+ + * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack + * | | + * | | + * | | + * | | + * | stack 2 | + * +-----------------------------------+ <-- start of 2nd thread stack + * | | + * | Red Zone | red zone for 1st thread + * | | + * +-----------------------------------+ + * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack + * | | + * | | + * | | + * | | + * | stack 1 | + * +-----------------------------------+ <-- start of 1st thread stack + * | | (initial value of last_stack) + * | Red Zone | + * | | red zone for main thread + * +-----------------------------------+ + * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack + * | | ^ + * | | | + * | | | + * | | | stack growth + * | | + * +-----------------------------------+ <-- start of main thread stack + * (USRSTACK) + * high memory + * + */ +static void * last_stack; + +void * +_thread_stack_alloc(size_t stacksize, size_t guardsize) +{ + void *stack = NULL; + struct stack *spare_stack; + size_t stack_size; + + /* + * Round up stack size to nearest multiple of _pthread_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. + */ + if (stacksize % _pthread_page_size != 0) + stack_size = ((stacksize / _pthread_page_size) + 1) * + _pthread_page_size; + else + stack_size = stacksize; + + /* + * If the stack and guard sizes are default, try to allocate a stack + * from the default-size stack cache: + */ + if (stack_size == PTHREAD_STACK_DEFAULT && + guardsize == _pthread_guard_default) { + /* + * Use the garbage collector mutex for synchronization of the + * spare stack list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + if ((spare_stack = LIST_FIRST(&_dstackq)) != NULL) { + /* Use the spare stack. */ + LIST_REMOVE(spare_stack, qe); + stack = spare_stack->stackaddr; + } + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + } + /* + * 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 { + /* + * Use the garbage collector mutex for synchronization of the + * spare stack list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + LIST_FOREACH(spare_stack, &_mstackq, qe) { + if (spare_stack->stacksize == stack_size && + spare_stack->guardsize == guardsize) { + LIST_REMOVE(spare_stack, qe); + stack = spare_stack->stackaddr; + break; + } + } + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + } + + /* Check if a stack was not allocated from a stack cache: */ + if (stack == NULL) { + + if (last_stack == NULL) + last_stack = _usrstack - PTHREAD_STACK_INITIAL - + _pthread_guard_default; + + /* Allocate a new stack. */ + stack = last_stack - stack_size; + + /* + * 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 -= (stack_size + guardsize); + + /* Stack: */ + if (mmap(stack, stack_size, PROT_READ | PROT_WRITE, MAP_STACK, + -1, 0) == MAP_FAILED) + stack = NULL; + } + + return (stack); +} + +/* This function must be called with _gc_mutex held. */ +void +_thread_stack_free(void *stack, size_t stacksize, size_t guardsize) +{ + struct stack *spare_stack; + + spare_stack = (stack + stacksize - sizeof(struct stack)); + /* Round stacksize up to nearest multiple of _pthread_page_size. */ + if (stacksize % _pthread_page_size != 0) { + spare_stack->stacksize = + ((stacksize / _pthread_page_size) + 1) * + _pthread_page_size; + } else + spare_stack->stacksize = stacksize; + spare_stack->guardsize = guardsize; + spare_stack->stackaddr = stack; + + if (spare_stack->stacksize == PTHREAD_STACK_DEFAULT && + spare_stack->guardsize == _pthread_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); + } +} diff --git a/lib/libthr/thread/thr_suspend_np.c b/lib/libthr/thread/thr_suspend_np.c new file mode 100644 index 0000000..7fa668d --- /dev/null +++ b/lib/libthr/thread/thr_suspend_np.c @@ -0,0 +1,53 @@ +/* + * 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 <pthread.h> +#include "thr_private.h" + +__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) +{ + /* XXXTHR */ + return (-1); +} + +void +_pthread_suspend_all_np(void) +{ + /* XXXTHR */ +} diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c new file mode 100644 index 0000000..d8fa348 --- /dev/null +++ b/lib/libthr/thread/thr_syscalls.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2000 Jason Evans <jasone@freebsd.org>. + * Copyright (c) 2002 Daniel M. Eischen <deischen@freebsd.org> + * Copyright (c) 2003 Jeff Roberson <jeff@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 <sys/cdefs.h> +#include <sys/fcntl.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.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 <pthread.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "thr_private.h" + +__weak_reference(_aio_suspend, aio_suspend); + +int +_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct + timespec *timeout) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_aio_suspend(iocbs, niocb, timeout); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__close, close); + +int +__close(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_close(fd); + _thread_leave_cancellation_point(); + + return ret; +} +__weak_reference(___creat, creat); + +int +___creat(const char *path, mode_t mode) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __creat(path, mode); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__fcntl, fcntl); + +int +__fcntl(int fd, int cmd,...) +{ + int ret; + va_list ap; + + _thread_enter_cancellation_point(); + + va_start(ap, cmd); + switch (cmd) { + case F_DUPFD: + 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); + + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__fsync, fsync); + +int +__fsync(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_fsync(fd); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__msync, msync); + +int +__msync(void *addr, size_t len, int flags) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_msync(addr, len, flags); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(_nanosleep, nanosleep); + +int +_nanosleep(const struct timespec * time_to_sleep, struct timespec * + time_remaining) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_nanosleep(time_to_sleep, time_remaining); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__open, open); + +int +__open(const char *path, int flags,...) +{ + int ret; + int mode = 0; + va_list ap; + + _thread_enter_cancellation_point(); + + /* 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); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__poll, poll); + +int +__poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_poll(fds, nfds, timeout); + _thread_leave_cancellation_point(); + + return ret; +} + +extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timespec *timo, const sigset_t *mask); + +int +pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timespec *timo, const sigset_t *mask) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __pselect(count, rfds, wfds, efds, timo, mask); + _thread_leave_cancellation_point(); + + return (ret); +} + +__weak_reference(__read, read); + +ssize_t +__read(int fd, void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = __sys_read(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__readv, readv); + +ssize_t +__readv(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = __sys_readv(fd, iov, iovcnt); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__select, select); + +int +__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(_sleep, sleep); + +unsigned int +_sleep(unsigned int seconds) +{ + unsigned int ret; + + _thread_enter_cancellation_point(); + ret = __sleep(seconds); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(_system, system); + +int +_system(const char *string) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __system(string); + _thread_leave_cancellation_point(); + + return ret; +} + + +__weak_reference(_tcdrain, tcdrain); + +int +_tcdrain(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __tcdrain(fd); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(_wait, wait); + +pid_t +_wait(int *istat) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __wait(istat); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__wait4, wait4); + +pid_t +__wait4(pid_t pid, int *istat, int options, struct rusage *rusage) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = _wait4(pid, istat, options, rusage); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(_waitpid, waitpid); + +pid_t +_waitpid(pid_t wpid, int *status, int options) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __waitpid(wpid, status, options); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__write, write); + +ssize_t +__write(int fd, const void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = __sys_write(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} + +__weak_reference(__writev, writev); + +ssize_t +__writev(int fd, const struct iovec *iov, int iovcnt) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = __sys_writev(fd, iov, iovcnt); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libthr/thread/thr_yield.c b/lib/libthr/thread/thr_yield.c new file mode 100644 index 0000000..2c96820 --- /dev/null +++ b/lib/libthr/thread/thr_yield.c @@ -0,0 +1,45 @@ +/* + * 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" + +__weak_reference(_pthread_yield, pthread_yield); + +/* Draft 4 yield */ +void +_pthread_yield(void) +{ + + sched_yield(); +} |