- Add libthr but don't hook it up to the regular build yet. This is an

adaptation of libc_r for the thr system call interface.  This is beta
   quality code.
This commit is contained in:
Jeff Roberson 2003-04-01 03:46:29 +00:00
parent e50173aeaa
commit bb535300dd
49 changed files with 7686 additions and 0 deletions

26
lib/libthr/Makefile Normal file
View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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);
}

211
lib/libthr/thread/thr_gc.c Normal file
View File

@ -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);
}

View File

@ -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, &param)) == 0)
ret = param.sched_priority;
else {
/* Invalid thread: */
errno = ret;
ret = -1;
}
/* Return the thread priority or an error status: */
return (ret);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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 */

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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());
}

257
lib/libthr/thread/thr_sem.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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, &param)) == 0) {
param.sched_priority = prio;
ret = pthread_setschedparam(pthread, policy, &param);
}
/* Return the error status: */
return (ret);
}

View File

@ -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
}

166
lib/libthr/thread/thr_sig.c Normal file
View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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();
}