diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2005-12-03 18:16:20 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2005-12-03 18:16:20 +0000 |
commit | f8598074c9df8821312f2c4a7cea9ba772625f82 (patch) | |
tree | 919fd1834c7d3b53c19dbfd42833240e246d4d45 | |
parent | e9242d9ec62b39f3a6284080e22c1dc917876df5 (diff) |
add userland thread library. incomplete, but functional
-rw-r--r-- | lib/librthread/Makefile | 8 | ||||
-rw-r--r-- | lib/librthread/arch/amd64/_atomic_lock.c | 26 | ||||
-rw-r--r-- | lib/librthread/arch/amd64/rfork_thread.S | 99 | ||||
-rw-r--r-- | lib/librthread/arch/i386/_atomic_lock.c | 25 | ||||
-rw-r--r-- | lib/librthread/arch/i386/rfork_thread.S | 126 | ||||
-rw-r--r-- | lib/librthread/rthread.c | 265 | ||||
-rw-r--r-- | lib/librthread/rthread.h | 111 | ||||
-rw-r--r-- | lib/librthread/rthread_attr.c | 109 | ||||
-rw-r--r-- | lib/librthread/rthread_sched.c | 136 | ||||
-rw-r--r-- | lib/librthread/rthread_sig.c | 90 | ||||
-rw-r--r-- | lib/librthread/rthread_sync.c | 477 | ||||
-rw-r--r-- | lib/librthread/rthread_tls.c | 117 |
12 files changed, 1589 insertions, 0 deletions
diff --git a/lib/librthread/Makefile b/lib/librthread/Makefile new file mode 100644 index 00000000000..245106ce583 --- /dev/null +++ b/lib/librthread/Makefile @@ -0,0 +1,8 @@ +LIB=rthread +CFLAGS+=-Wall -g -Werror + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH} +SRCS= rthread.c rthread_attr.c rthread_sched.c rthread_sync.c rthread_tls.c rthread_sig.c +OBJS+= _atomic_lock.o rfork_thread.o # .S on alpha + +.include <bsd.lib.mk> diff --git a/lib/librthread/arch/amd64/_atomic_lock.c b/lib/librthread/arch/amd64/_atomic_lock.c new file mode 100644 index 00000000000..14569edc562 --- /dev/null +++ b/lib/librthread/arch/amd64/_atomic_lock.c @@ -0,0 +1,26 @@ +/* $OpenBSD: _atomic_lock.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ + +/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ + +/* + * Atomic lock for amd64 -- taken from i386 code. + */ + +#include "spinlock.h" + +int +_atomic_lock(volatile _spinlock_lock_t *lock) +{ + _spinlock_lock_t old; + + /* + * Use the eXCHanGe instruction to swap the lock value with + * a local variable containing the locked state. + */ + old = _SPINLOCK_LOCKED; + __asm__("xchg %0,%1" + : "=r" (old), "=m" (*lock) + : "0" (old), "1" (*lock)); + + return (old != _SPINLOCK_UNLOCKED); +} diff --git a/lib/librthread/arch/amd64/rfork_thread.S b/lib/librthread/arch/amd64/rfork_thread.S new file mode 100644 index 00000000000..faec9b233c7 --- /dev/null +++ b/lib/librthread/arch/amd64/rfork_thread.S @@ -0,0 +1,99 @@ +/* $OpenBSD: rfork_thread.S,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/*- + * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org> + * Copyright (c) 2003 Alan L. Cox <alc@cs.rice.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 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. + */ + +#include <machine/asm.h> +#if 0 +__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/amd64/gen/rfork_thread.S,v 1.1 2003/10/13 20:32:33 alc Exp $"); +#endif + +/* + * With thanks to John Dyson for the original version of this. + */ + +#include "../../../libc/arch/amd64/SYS.h" + +/* + * %edi %rsi %rdx %rcx + * rfork_thread(flags, stack_addr, start_fnc, start_arg); + * + * flags: Flags to rfork system call. See rfork(2). + * stack_addr: Top of stack for thread. + * start_fnc: Address of thread function to call in child. + * start_arg: Argument to pass to the thread function in child. + */ + +ENTRY(rfork_thread) + pushq %rbx + pushq %r12 + movq %rdx, %rbx + movq %rcx, %r12 + + /* + * Prepare and execute the thread creation syscall + */ + movq $SYS_rfork, %rax + int $0x80 + jb 2f + + /* + * Check to see if we are in the parent or child + */ + cmpl $0, %edx + jnz 1f + popq %r12 + popq %rbx + ret + + /* + * If we are in the child (new thread), then + * set-up the call to the internal subroutine. If it + * returns, then call __exit. + */ +1: + movq %rsi, %rsp + movq %r12, %rdi + call *%rbx + movl %eax, %edi + + /* + * Exit system call + */ +#ifdef SYS_exit + movq $SYS_exit, %rax +#else + movq $SYS_sys_exit, %rax +#endif + int $0x80 + + /* + * Branch here if the thread creation fails: + */ +2: + popq %r12 + popq %rbx + jmp CERROR diff --git a/lib/librthread/arch/i386/_atomic_lock.c b/lib/librthread/arch/i386/_atomic_lock.c new file mode 100644 index 00000000000..7b9b46a73c7 --- /dev/null +++ b/lib/librthread/arch/i386/_atomic_lock.c @@ -0,0 +1,25 @@ +/* $OpenBSD: _atomic_lock.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* David Leonard, <d@csee.uq.edu.au>. Public domain. */ + +/* + * Atomic lock for i386 + */ + +#include <machine/spinlock.h> + +int +_atomic_lock(register volatile _spinlock_lock_t *lock) +{ + register _spinlock_lock_t old; + + /* + * Use the eXCHanGe instruction to swap the lock value with + * a local variable containing the locked state. + */ + old = _SPINLOCK_LOCKED; + __asm__("xchg %0,%1" + : "=r" (old), "=m" (*lock) + : "0" (old), "1" (*lock)); + + return (old != _SPINLOCK_UNLOCKED); +} diff --git a/lib/librthread/arch/i386/rfork_thread.S b/lib/librthread/arch/i386/rfork_thread.S new file mode 100644 index 00000000000..39e35ac67c2 --- /dev/null +++ b/lib/librthread/arch/i386/rfork_thread.S @@ -0,0 +1,126 @@ +/* $OpenBSD: rfork_thread.S,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/*- + * Copyright (c) 2000 Peter Wemm <peter@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. + */ + +#include <machine/asm.h> +#if 0 +__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/i386/gen/rfork_thread.S,v 1.5 2003/05/07 17:23:25 jhb Exp $"); +#endif + +/* + * With thanks to John Dyson for the original version of this. + */ + +#include "../../../libc/arch/i386/SYS.h" + +/* + * 8 12 16 20 + * rfork_thread(flags, stack_addr, start_fnc, start_arg); + * + * flags: Flags to rfork system call. See rfork(2). + * stack_addr: Top of stack for thread. + * start_fnc: Address of thread function to call in child. + * start_arg: Argument to pass to the thread function in child. + */ + +ENTRY(rfork_thread) + pushl %ebp + movl %esp, %ebp + pushl %esi + + /* + * Push thread info onto the new thread's stack + */ + movl 12(%ebp), %esi # get stack addr + + subl $4, %esi + movl 20(%ebp), %eax # get start argument + movl %eax, (%esi) + + subl $4, %esi + movl 16(%ebp), %eax # get start thread address + movl %eax, (%esi) + + /* + * Prepare and execute the thread creation syscall + */ + pushl 8(%ebp) + pushl $0 + movl $SYS_rfork, %eax + int $0x80 +#if 0 + jb 2f +#endif + + /* + * Check to see if we are in the parent or child + */ + cmpl $0, %edx + jnz 1f + addl $8, %esp + popl %esi + movl %ebp, %esp + popl %ebp + ret + .p2align 2 + + /* + * If we are in the child (new thread), then + * set-up the call to the internal subroutine. If it + * returns, then call __exit. + */ +1: + movl %esi,%esp + popl %eax + call *%eax + addl $4, %esp + + /* + * Exit system call + */ + pushl %eax + pushl $0 +#ifdef SYS_exit + movl $SYS_exit, %eax +#else + movl $SYS_sys_exit, %eax +#endif + int $0x80 + + /* + * Branch here if the thread creation fails: + */ +2: + addl $8, %esp + popl %esi + movl %ebp, %esp + popl %ebp +#if 0 + /* FreeBSD code. how to translate? */ + PIC_PROLOGUE + jmp PIC_PLT(HIDENAME(cerror)) +#endif + jmp CERROR diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c new file mode 100644 index 00000000000..7e3cc057c7b --- /dev/null +++ b/lib/librthread/rthread.c @@ -0,0 +1,265 @@ +/* $OpenBSD: rthread.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * The heart of rthreads. Basic functions like creating and joining + * threads. + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +static int threads_ready; +static pthread_t thread_list; +static _spinlock_lock_t thread_lock; + +int yield(); +int getthrid(); +void threxit(int); +int rfork_thread(int, void *, void (*)(void *), void *); + +/* + * internal support functions + */ +void +_spinlock(_spinlock_lock_t *lock) +{ + + while (_atomic_lock(lock)) + pthread_yield(); +} + +void +_spinunlock(_spinlock_lock_t *lock) +{ + + *lock = _SPINLOCK_UNLOCKED; +} + +static pthread_t +thread_findself(void) +{ + pthread_t me; + pid_t tid = getthrid(); + + for (me = thread_list; me; me = me->next) + if (me->tid == tid) + break; + + return (me); +} + + +static void +thread_start(void *v) +{ + pthread_t thread = v; + void *retval; + + /* ensure parent returns from rfork, sets up tid */ + _spinlock(&thread_lock); + _spinunlock(&thread_lock); + retval = thread->fn(thread->arg); + pthread_exit(retval); +} + +static void +thread_init(void) +{ + pthread_t thread; + extern int __isthreaded; + + __isthreaded = 1; + + thread = malloc(sizeof(*thread)); + memset(thread, 0, sizeof(*thread)); + thread->tid = getthrid(); + snprintf(thread->name, sizeof(thread->name), "Main process"); + thread_list = thread; + threads_ready = 1; +} + +static struct stack * +alloc_stack(size_t len) +{ + struct stack *stack; + + stack = malloc(sizeof(*stack)); + stack->base = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); + stack->sp = (void *)(((size_t)stack->base + len - 16) & ~15); + return (stack); +} + + +/* + * real pthread functions + */ +pthread_t +pthread_self(void) +{ + pthread_t thread; + + if (!threads_ready) + thread_init(); + + _spinlock(&thread_lock); + thread = thread_findself(); + _spinunlock(&thread_lock); + + return (thread); +} + +void +pthread_exit(void *retval) +{ + pthread_t thread = pthread_self(); + + thread->retval = retval; + thread->flags |= THREAD_DONE; + _sem_wakeup(&thread->donesem); +#if 0 + if (thread->flags & THREAD_DETACHED) + free(thread); +#endif + threxit(0); + for(;;); +} + +int +pthread_join(pthread_t thread, void **retval) +{ + + _sem_wait(&thread->donesem, 0, 0); + printf("joined %d %p\n", thread->tid, thread->retval); + if (retval) + *retval = thread->retval; + + return (0); +} + +int +pthread_detach(pthread_t thread) +{ + _spinlock(&thread_lock); +#if 0 + if (thread->flags & THREAD_DONE) + free(thread); + else +#endif + thread->flags |= THREAD_DETACHED; + _spinunlock(&thread_lock); + return (0); +} + +int +pthread_create(pthread_t *threadp, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + pthread_t thread; + pid_t tid; + + if (!threads_ready) + thread_init(); + + thread = malloc(sizeof(*thread)); + memset(thread, 0, sizeof(*thread)); + thread->fn = start_routine; + thread->arg = arg; + + _spinlock(&thread_lock); + thread->next = thread_list; + thread_list = thread; + + thread->stack = alloc_stack(64 * 1024); + + tid = rfork_thread(RFPROC | RFTHREAD | RFMEM | RFNOWAIT, + thread->stack->sp, thread_start, thread); + /* new thread will appear thread_start */ + thread->tid = tid; + printf("new thread %d\n", tid); + *threadp = thread; + _spinunlock(&thread_lock); + + return (0); +} + +int +pthread_equal(pthread_t t1, pthread_t t2) +{ + return (t1 == t2); +} + +/* + * _np functions + */ +void +pthread_set_name_np(pthread_t thread, char *name) +{ + strlcpy(thread->name, name, sizeof(thread->name)); +} + +/* + * compat debug stuff + */ +void +_thread_dump_info(void) +{ + pthread_t thread; + + _spinlock(&thread_lock); + for (thread = thread_list; thread; thread = thread->next) + printf("thread %d flags %d name %s\n", + thread->tid, thread->flags, thread->name); + _spinunlock(&thread_lock); +} + + +/* + * the malloc lock + */ +static _spinlock_lock_t malloc_lock; + +void +_thread_malloc_lock() +{ + _spinlock(&malloc_lock); +} + +void +_thread_malloc_unlock() +{ + _spinunlock(&malloc_lock); +} + +void +_thread_malloc_init() +{ +} diff --git a/lib/librthread/rthread.h b/lib/librthread/rthread.h new file mode 100644 index 00000000000..3deec5835d5 --- /dev/null +++ b/lib/librthread/rthread.h @@ -0,0 +1,111 @@ +/* $OpenBSD: rthread.h,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Private data structures that back up the typedefs in pthread.h. + * Since only the thread library cares about their size or arrangement, + * it should be possible to switch libraries without relinking. + */ + +struct stack { + void *sp; + void *base; + size_t len; +}; + +typedef struct semaphore { + volatile int waitcount; + volatile int value; + _spinlock_lock_t lock; +} *sem_t; + +struct pthread_mutex { + struct semaphore sem; + int type; + pthread_t owner; + int count; +}; + +struct pthread_mutex_attr { + int type; +}; + +struct pthread_cond { + struct semaphore sem; +}; + +struct pthread_cond_attr { + int shared; +}; + +struct pthread_rwlock { + _spinlock_lock_t lock; + int readers; + int writer; + struct semaphore sem; +}; + +struct pthread_rwlockattr { + int dummy; +}; + +struct pthread_attr { + size_t stack_size; + int detach_state; + int contention_scope; + int sched_policy; + struct sched_param sched_param; + int sched_inherit; +}; + +struct rthread_key { + int keyid; + struct rthread_key *next; + void (*destructor)(void *); +}; + +struct rthread_storage { + int keyid; + struct rthread_storage *next; + void *data; +}; + +struct pthread { + pid_t tid; + struct semaphore donesem; + int flags; + void *retval; + void *(*fn)(void *); + void *arg; + char name[32]; + struct stack *stack; + pthread_t next; + int sched_policy; + struct sched_param sched_param; + struct rthread_storage *local_storage; + int sigpend; +}; +#define THREAD_DONE 0x001 +#define THREAD_DETACHED 0x002 + +void _spinlock(_spinlock_lock_t *); +void _spinunlock(_spinlock_lock_t *); +int _sem_wait(sem_t, int, int); +int _sem_wakeup(sem_t); +int _sem_wakeall(sem_t); + +int _atomic_lock(register volatile _spinlock_lock_t *); diff --git a/lib/librthread/rthread_attr.c b/lib/librthread/rthread_attr.c new file mode 100644 index 00000000000..532a53d0f17 --- /dev/null +++ b/lib/librthread/rthread_attr.c @@ -0,0 +1,109 @@ +/* $OpenBSD: rthread_attr.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * generic attribute support + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +int +pthread_attr_init(pthread_attr_t *attrp) +{ + pthread_attr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + *attrp = attr; + + return (0); +} + +int +pthread_attr_destroy(pthread_attr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_attr_getdetachstate(const pthread_attr_t *attrp, int *detachstate) +{ + *detachstate = (*attrp)->detach_state; + + return (0); +} + +int +pthread_attr_setdetachstate(pthread_attr_t *attrp, int detachstate) +{ + (*attrp)->detach_state = detachstate; + + return (0); +} + +int +pthread_attr_getstacksize(const pthread_attr_t *attrp, size_t *stacksize) +{ + *stacksize = (*attrp)->stack_size; + + return (0); + +} + +int +pthread_attr_setstacksize(pthread_attr_t *attrp, size_t stacksize) +{ + (*attrp)->stack_size = stacksize; + + return (0); +} + +int +pthread_attr_getscope(const pthread_attr_t *attrp, int *contentionscope) +{ + *contentionscope = (*attrp)->contention_scope; + + return (0); +} + +int +pthread_attr_setscope(pthread_attr_t *attrp, int contentionscope) +{ + (*attrp)->contention_scope = contentionscope; + + return (0); +} diff --git a/lib/librthread/rthread_sched.c b/lib/librthread/rthread_sched.c new file mode 100644 index 00000000000..3ca3113c483 --- /dev/null +++ b/lib/librthread/rthread_sched.c @@ -0,0 +1,136 @@ +/* $OpenBSD: rthread_sched.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * scheduling routines + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +int yield(void); + +int +pthread_getschedparam(pthread_t thread, int *policy, + struct sched_param *param) +{ + *policy = thread->sched_policy; + if (param) + *param = thread->sched_param; + + return (0); +} + +int +pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) +{ + thread->sched_policy = policy; + if (param) + thread->sched_param = *param; + + return (0); +} + +int +pthread_attr_getschedparam(const pthread_attr_t *attrp, struct sched_param *param) +{ + *param = (*attrp)->sched_param; + + return (0); +} + +int +pthread_attr_setschedparam(pthread_attr_t *attrp, const struct sched_param *param) +{ + (*attrp)->sched_param = *param; + + return (0); +} + +int +pthread_attr_getschedpolicy(const pthread_attr_t *attrp, int *policy) +{ + *policy = (*attrp)->sched_policy; + + return (0); +} + +int +pthread_attr_setschedpolicy(pthread_attr_t *attrp, int policy) +{ + (*attrp)->sched_policy = policy; + + return (0); +} + +int +pthread_attr_getinheritsched(const pthread_attr_t *attrp, int *inherit) +{ + *inherit = (*attrp)->sched_inherit; + + return (0); +} + +int +pthread_attr_setinheritsched(pthread_attr_t *attrp, int inherit) +{ + (*attrp)->sched_inherit = inherit; + + return (0); +} + +int +pthread_getprio(pthread_t thread) +{ + return (thread->sched_param.sched_priority); +} + +int +pthread_setprio(pthread_t thread, int priority) +{ + thread->sched_param.sched_priority = priority; + + return (0); +} + +void +pthread_yield(void) +{ + yield(); +} +int +sched_yield(void) +{ + yield(); + + return (0); +} diff --git a/lib/librthread/rthread_sig.c b/lib/librthread/rthread_sig.c new file mode 100644 index 00000000000..5fcb9002e86 --- /dev/null +++ b/lib/librthread/rthread_sig.c @@ -0,0 +1,90 @@ +/* $OpenBSD: rthread_sig.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * signals + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +int thrwakeup(long); +int thrsleep(long, int, void *); +int thrsigdivert(const sigset_t *); + +int +pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + return (sigprocmask(how, set, oset)); +} + +/* + * implementation of sigwait: + * 1. we install a handler for each masked signal. + * 2. we inform the kernel we are interested in this signal set. + * 3. sleep. the handler will wake us up. + * + * this is atomic because the kernel will only divert one signal + * to a thread until it asks for more. + */ +static void +sigwait_handler(int sig) +{ + pthread_t self = pthread_self(); + self->sigpend = sig; + thrwakeup((long)&self->sigpend); +} + +typedef void (*sigfn)(int); + +int +sigwait(const sigset_t *set, int *sig) +{ + int i; + sigset_t mask = *set; + pthread_t self = pthread_self(); + sigfn oldhandlers[NSIG]; + + for (i = 0; i < NSIG; i++) { + if (mask & (1 << i)) + oldhandlers[i] = signal(i, sigwait_handler); + } + + thrsigdivert(set); + thrsleep((long)&self->sigpend, 0, NULL); + + for (i = 0; i < NSIG; i++) { + if (mask & (1 << i)) + signal(i, oldhandlers[i]); + } + *sig = self->sigpend; + return (0); +} diff --git a/lib/librthread/rthread_sync.c b/lib/librthread/rthread_sync.c new file mode 100644 index 00000000000..a2d7faf01cd --- /dev/null +++ b/lib/librthread/rthread_sync.c @@ -0,0 +1,477 @@ +/* $OpenBSD: rthread_sync.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Mutexes, conditions, rwlocks, and semaphores - synchronization functions. + */ + + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +int thrsleep(long, int, void *); +int thrwakeup(long); + +/* + * Internal implementation of semaphores + */ +int +_sem_wait(sem_t sem, int tryonly, int timo) +{ + int sleep; + + _spinlock(&sem->lock); +again: + if (sem->value == 0) { + if (tryonly) { + _spinunlock(&sem->lock); + return (0); + } + sem->waitcount++; + sleep = 1; + } else { + sem->value--; + sleep = 0; + } + + if (sleep) { + if (thrsleep((long)sem, timo, &sem->lock) == EWOULDBLOCK) + return (0); + _spinlock(&sem->lock); + sem->waitcount--; + goto again; + } + _spinunlock(&sem->lock); + return (1); +} + +int +_sem_wakeup(sem_t sem) +{ + int rv = 0; + + _spinlock(&sem->lock); + sem->value++; + if (sem->waitcount) { + thrwakeup((long)sem); + rv = 1; + } + _spinunlock(&sem->lock); + return (rv); +} + +int +_sem_wakeall(sem_t sem) +{ + int rv; + + _spinlock(&sem->lock); + rv = sem->waitcount; + sem->value += rv; + thrwakeup((long)sem); + _spinunlock(&sem->lock); + + return (rv); +} + +/* + * mutexen + */ +int +pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) +{ + pthread_mutex_t mutex; + + mutex = malloc(sizeof(*mutex)); + if (!mutex) + return (errno); + memset((void *)mutex, 0, sizeof(*mutex)); + mutex->sem.value = 1; /* unlocked */ + mutex->type = attr ? (*attr)->type : PTHREAD_MUTEX_ERRORCHECK; + *mutexp = mutex; + + return (0); +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutexp) +{ + + /* check for waiters */ + free((void *)*mutexp); + *mutexp = NULL; + return (0); +} + +int +rthread_mutex_lock(pthread_mutex_t *mutexp, int trywait) +{ + pthread_mutex_t mutex = *mutexp; + pthread_t thread = pthread_self(); + + if (!mutex) { + pthread_mutex_init(mutexp, NULL); + mutex = *mutexp; + } + if (mutex->owner == thread) { + if (mutex->type == PTHREAD_MUTEX_RECURSIVE) { + mutex->count++; + return (0); + } + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) + return (EDEADLK); + } + if (!_sem_wait((void *)&mutex->sem, trywait, 0)) + return (EBUSY); + mutex->owner = thread; + mutex->count = 1; + + return (0); +} + +int +pthread_mutex_lock(pthread_mutex_t *p) +{ + return (rthread_mutex_lock(p, 0)); +} + +int +pthread_mutex_trylock(pthread_mutex_t *p) +{ + return (rthread_mutex_lock(p, 1)); +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutexp) +{ + pthread_t thread = pthread_self(); + pthread_mutex_t mutex = *mutexp; + + if (mutex->owner != thread) + return (EPERM); + + if (--mutex->count == 0) { + mutex->owner = NULL; + _sem_wakeup((void *)&mutex->sem); + } + + return (0); +} + +/* + * mutexen attributes + */ +int +pthread_mutexattr_init(pthread_mutexattr_t *attrp) +{ + pthread_mutexattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + attr->type = PTHREAD_MUTEX_ERRORCHECK; + *attrp = attr; + + return (0); +} + +int +pthread_mutexattr_destroy(pthread_mutexattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_mutexattr_settype(pthread_mutexattr_t *attrp, int type) +{ + (*attrp)->type = type; + + return (0); +} + +/* + * condition variables + */ +int +pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attrp) +{ + pthread_cond_t cond; + + cond = malloc(sizeof(*cond)); + if (!cond) + return (errno); + memset(cond, 0, sizeof(*cond)); + + *condp = cond; + + return (0); +} + +int +pthread_cond_destroy(pthread_cond_t *condp) +{ + + free(*condp); + *condp = NULL; + + return (0); +} + +int +pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, + const struct timespec *abstime) +{ + int error; + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + + pthread_mutex_unlock(mutexp); + _sem_wait(&(*condp)->sem, 0, (abstime ? + abstime->tv_sec * 100 + abstime->tv_nsec / 10000000 : 0)); + error = pthread_mutex_lock(mutexp); + + return (error); +} + +int +pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) +{ + return (pthread_cond_timedwait(condp, mutexp, NULL)); +} + +int +pthread_cond_signal(pthread_cond_t *condp) +{ + int error; + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + + _sem_wakeup(&(*condp)->sem); + + return (0); +} + +int +pthread_cond_broadcast(pthread_cond_t *condp) +{ + if (!*condp) + pthread_cond_init(condp, NULL); + + _sem_wakeall(&(*condp)->sem); + + return (0); +} + +/* + * condition variable attributes + */ +int +pthread_condattr_init(pthread_condattr_t *attrp) +{ + pthread_condattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + *attrp = attr; + + return (0); +} + +int +pthread_condattr_destroy(pthread_condattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +/* + * rwlocks + */ +int +pthread_rwlock_init(pthread_rwlock_t *lockp, const pthread_rwlockattr_t *attrp) +{ + pthread_rwlock_t lock; + + lock = malloc(sizeof(*lock)); + if (!lock) + return (errno); + memset(lock, 0, sizeof(*lock)); + *lockp = lock; + + return (0); +} + +int +pthread_rwlock_destroy(pthread_rwlock_t *lockp) +{ + free(*lockp); + *lockp = NULL; + + return (0); +} + +int +pthread_rwlock_rdlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; +again: + _spinlock(&lock->lock); + if (lock->writer) { + _spinunlock(&lock->lock); + _sem_wait(&lock->sem, 0, 0); + goto again; + } + lock->readers++; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_tryrdlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->writer) { + _spinunlock(&lock->lock); + return (EBUSY); + } + lock->readers++; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_wrlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + +again: + _spinlock(&lock->lock); + lock->writer++; + if (lock->readers) { + _spinunlock(&lock->lock); + _sem_wait(&lock->sem, 0, 0); + goto again; + } + lock->readers = -pthread_self()->tid; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_trywrlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->readers || lock->writer) { + _spinunlock(&lock->lock); + return (EBUSY); + } + lock->writer = 1; + lock->readers = -pthread_self()->tid; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_unlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->readers == -pthread_self()->tid) { + lock->readers = 0; + lock->writer--; + } else if (lock->readers > 0) { + lock->readers--; + } else { + _spinunlock(&lock->lock); + return (EPERM); + } + _spinunlock(&lock->lock); + _sem_wakeall(&lock->sem); + + return (0); +} + +/* + * rwlock attributes + */ +int +pthread_rwlockattr_init(pthread_rwlockattr_t *attrp) +{ + pthread_rwlockattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + *attrp = attr; + + return (0); +} + +int +pthread_rwlockattr_destory(pthread_rwlockattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} diff --git a/lib/librthread/rthread_tls.c b/lib/librthread/rthread_tls.c new file mode 100644 index 00000000000..a1e844fe497 --- /dev/null +++ b/lib/librthread/rthread_tls.c @@ -0,0 +1,117 @@ +/* $OpenBSD: rthread_tls.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * thread specific storage + */ + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +struct rthread_key *rthread_key_list; + +int +pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) +{ + static int last_key; + struct rthread_key *rkey; + + last_key++; + + rkey = malloc(sizeof(*key)); + if (!rkey) + return (errno); + rkey->keyid = last_key; + rkey->destructor = destructor; + rkey->next = rthread_key_list; + rthread_key_list = rkey; + + *key = last_key; + + return (0); +} + +int +pthread_key_delete(pthread_key_t key) +{ + + return (0); +} + +static struct rthread_storage * +rthread_findstorage(pthread_key_t key) +{ + struct rthread_storage *rs; + pthread_t self; + + self = pthread_self(); + + for (rs = self->local_storage; rs; rs = rs->next) { + if (rs->keyid == key) + break; + } + if (!rs) { + rs = malloc(sizeof(*rs)); + if (!rs) + return (NULL); + rs->keyid = key; + rs->data = NULL; + rs->next = self->local_storage; + self->local_storage = rs; + } + + return (rs); +} + +void * +pthread_getspecific(pthread_key_t key) +{ + struct rthread_storage *rs; + + rs = rthread_findstorage(key); + if (!rs) + return (NULL); + + return (rs->data); +} + +int +pthread_setspecific(pthread_key_t key, const void *data) +{ + struct rthread_storage *rs; + + rs = rthread_findstorage(key); + if (!rs) + return (ENOMEM); + rs->data = (void *)data; + + return (0); +} |