- 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:
parent
e50173aeaa
commit
bb535300dd
26
lib/libthr/Makefile
Normal file
26
lib/libthr/Makefile
Normal 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>
|
17
lib/libthr/arch/i386/i386/_curthread.S
Normal file
17
lib/libthr/arch/i386/i386/_curthread.S
Normal 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
|
122
lib/libthr/arch/i386/i386/_setcurthread.c
Normal file
122
lib/libthr/arch/i386/i386/_setcurthread.c
Normal 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);
|
||||
}
|
50
lib/libthr/thread/Makefile.inc
Normal file
50
lib/libthr/thread/Makefile.inc
Normal 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
|
450
lib/libthr/thread/thr_attr.c
Normal file
450
lib/libthr/thread/thr_attr.c
Normal 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);
|
||||
}
|
61
lib/libthr/thread/thr_autoinit.c
Normal file
61
lib/libthr/thread/thr_autoinit.c
Normal 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;
|
205
lib/libthr/thread/thr_cancel.c
Normal file
205
lib/libthr/thread/thr_cancel.c
Normal 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();
|
||||
}
|
72
lib/libthr/thread/thr_clean.c
Normal file
72
lib/libthr/thread/thr_clean.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
544
lib/libthr/thread/thr_cond.c
Normal file
544
lib/libthr/thread/thr_cond.c
Normal 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;
|
||||
}
|
53
lib/libthr/thread/thr_condattr_destroy.c
Normal file
53
lib/libthr/thread/thr_condattr_destroy.c
Normal 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);
|
||||
}
|
58
lib/libthr/thread/thr_condattr_init.c
Normal file
58
lib/libthr/thread/thr_condattr_init.c
Normal 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);
|
||||
}
|
228
lib/libthr/thread/thr_create.c
Normal file
228
lib/libthr/thread/thr_create.c
Normal 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");
|
||||
}
|
82
lib/libthr/thread/thr_detach.c
Normal file
82
lib/libthr/thread/thr_detach.c
Normal 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);
|
||||
}
|
44
lib/libthr/thread/thr_equal.c
Normal file
44
lib/libthr/thread/thr_equal.c
Normal 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);
|
||||
}
|
186
lib/libthr/thread/thr_exit.c
Normal file
186
lib/libthr/thread/thr_exit.c
Normal 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");
|
||||
}
|
61
lib/libthr/thread/thr_find_thread.c
Normal file
61
lib/libthr/thread/thr_find_thread.c
Normal 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
211
lib/libthr/thread/thr_gc.c
Normal 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);
|
||||
}
|
56
lib/libthr/thread/thr_getprio.c
Normal file
56
lib/libthr/thread/thr_getprio.c
Normal 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, ¶m)) == 0)
|
||||
ret = param.sched_priority;
|
||||
else {
|
||||
/* Invalid thread: */
|
||||
errno = ret;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* Return the thread priority or an error status: */
|
||||
return (ret);
|
||||
}
|
59
lib/libthr/thread/thr_getschedparam.c
Normal file
59
lib/libthr/thread/thr_getschedparam.c
Normal 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);
|
||||
}
|
193
lib/libthr/thread/thr_info.c
Normal file
193
lib/libthr/thread/thr_info.c
Normal 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);
|
||||
}
|
||||
}
|
363
lib/libthr/thread/thr_init.c
Normal file
363
lib/libthr/thread/thr_init.c
Normal 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
|
161
lib/libthr/thread/thr_join.c
Normal file
161
lib/libthr/thread/thr_join.c
Normal 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);
|
||||
}
|
188
lib/libthr/thread/thr_kern.c
Normal file
188
lib/libthr/thread/thr_kern.c
Normal 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);
|
||||
}
|
47
lib/libthr/thread/thr_main_np.c
Normal file
47
lib/libthr/thread/thr_main_np.c
Normal 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);
|
||||
}
|
56
lib/libthr/thread/thr_mattr_init.c
Normal file
56
lib/libthr/thread/thr_mattr_init.c
Normal 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);
|
||||
}
|
97
lib/libthr/thread/thr_mattr_kind_np.c
Normal file
97
lib/libthr/thread/thr_mattr_kind_np.c
Normal 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;
|
||||
}
|
50
lib/libthr/thread/thr_multi_np.c
Normal file
50
lib/libthr/thread/thr_multi_np.c
Normal 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);
|
||||
}
|
432
lib/libthr/thread/thr_mutex.c
Normal file
432
lib/libthr/thread/thr_mutex.c
Normal 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);
|
||||
}
|
||||
}
|
122
lib/libthr/thread/thr_mutex_prioceiling.c
Normal file
122
lib/libthr/thread/thr_mutex_prioceiling.c
Normal 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
|
||||
}
|
70
lib/libthr/thread/thr_mutex_protocol.c
Normal file
70
lib/libthr/thread/thr_mutex_protocol.c
Normal 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);
|
||||
}
|
||||
|
53
lib/libthr/thread/thr_mutexattr_destroy.c
Normal file
53
lib/libthr/thread/thr_mutexattr_destroy.c
Normal 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);
|
||||
}
|
53
lib/libthr/thread/thr_once.c
Normal file
53
lib/libthr/thread/thr_once.c
Normal 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);
|
||||
}
|
124
lib/libthr/thread/thr_printf.c
Normal file
124
lib/libthr/thread/thr_printf.c
Normal 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));
|
||||
}
|
||||
|
804
lib/libthr/thread/thr_private.h
Normal file
804
lib/libthr/thread/thr_private.h
Normal 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 */
|
87
lib/libthr/thread/thr_resume_np.c
Normal file
87
lib/libthr/thread/thr_resume_np.c
Normal 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();
|
||||
}
|
341
lib/libthr/thread/thr_rwlock.c
Normal file
341
lib/libthr/thread/thr_rwlock.c
Normal 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);
|
||||
}
|
||||
|
98
lib/libthr/thread/thr_rwlockattr.c
Normal file
98
lib/libthr/thread/thr_rwlockattr.c
Normal 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);
|
||||
}
|
||||
|
44
lib/libthr/thread/thr_self.c
Normal file
44
lib/libthr/thread/thr_self.c
Normal 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
257
lib/libthr/thread/thr_sem.c
Normal 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;
|
||||
}
|
59
lib/libthr/thread/thr_seterrno.c
Normal file
59
lib/libthr/thread/thr_seterrno.c
Normal 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;
|
||||
}
|
52
lib/libthr/thread/thr_setprio.c
Normal file
52
lib/libthr/thread/thr_setprio.c
Normal 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, ¶m)) == 0) {
|
||||
param.sched_priority = prio;
|
||||
ret = pthread_setschedparam(pthread, policy, ¶m);
|
||||
}
|
||||
|
||||
/* Return the error status: */
|
||||
return (ret);
|
||||
}
|
115
lib/libthr/thread/thr_setschedparam.c
Normal file
115
lib/libthr/thread/thr_setschedparam.c
Normal 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
166
lib/libthr/thread/thr_sig.c
Normal 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);
|
||||
}
|
225
lib/libthr/thread/thr_spec.c
Normal file
225
lib/libthr/thread/thr_spec.c
Normal 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);
|
||||
}
|
88
lib/libthr/thread/thr_spinlock.c
Normal file
88
lib/libthr/thread/thr_spinlock.c
Normal 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();
|
||||
}
|
240
lib/libthr/thread/thr_stack.c
Normal file
240
lib/libthr/thread/thr_stack.c
Normal 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);
|
||||
}
|
||||
}
|
53
lib/libthr/thread/thr_suspend_np.c
Normal file
53
lib/libthr/thread/thr_suspend_np.c
Normal 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 */
|
||||
}
|
418
lib/libthr/thread/thr_syscalls.c
Normal file
418
lib/libthr/thread/thr_syscalls.c
Normal 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;
|
||||
}
|
45
lib/libthr/thread/thr_yield.c
Normal file
45
lib/libthr/thread/thr_yield.c
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user